diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d1903aed7e554..0c25e0dbd16d8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,21 +22,29 @@ jobs: sudo apt-get purge libgcc-9-dev gcc-9 libstdc++-9-dev sudo swapoff -a sudo rm -f /swapfile + sudo rm -rf /opt/hostedtoolcache + sudo rm -rf /usr/share/dotnet sudo apt clean docker rmi $(docker image ls -aq) df -h - uses: actions/checkout@v1 with: path: swift + - name: Prepare sccache timestamp + id: cache_timestamp + shell: cmake -P {0} + run: | + string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC) + message("::set-output name=timestamp::${current_date}") - uses: actions/cache@v1 with: path: ../build-cache - key: ${{ runner.os }}-sccache-v9 + key: ${{ runner.os }}-sccache-v10-${{ steps.cache_timestamp.outputs.timestamp }} + restore-keys: | + ${{ runner.os }}-sccache-v10- - name: Build Linux installable archive run: | ./utils/webassembly/ci.sh - echo "Cleanup build directory to free disk space" - rm -rf ../build - name: Upload Linux installable archive uses: actions/upload-artifact@v1 with: @@ -58,10 +66,18 @@ jobs: - uses: actions/checkout@v1 with: path: swift + - name: Prepare sccache timestamp + id: cache_timestamp + shell: cmake -P {0} + run: | + string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC) + message("::set-output name=timestamp::${current_date}") - uses: actions/cache@v1 with: path: ../build-cache - key: ${{ runner.os }}-sccache-v9 + key: ${{ runner.os }}-sccache-v10-${{ steps.cache_timestamp.outputs.timestamp }} + restore-keys: | + ${{ runner.os }}-sccache-v10- - name: Build macOS installable archive run: | sudo xcode-select --switch /Applications/Xcode_12_beta.app/Contents/Developer/ @@ -72,7 +88,7 @@ jobs: name: macos-installable path: ../swift-wasm-DEVELOPMENT-SNAPSHOT-osx.tar.gz - name: Pack test results - run: tar cJf swift-test-results.tar.gz ../build/*/swift-macosx-x86_64/swift-test-results + run: tar cJf swift-test-results.tar.gz ../target-build/*/swift-macosx-x86_64/swift-test-results - name: Upload test results uses: actions/upload-artifact@v1 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b2af5d8f7abe..fb765f84639a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,29 +4,100 @@ CHANGELOG
Note: This is in reverse chronological order, so newer entries are added to the top. -| Version | Released | Toolchain | -| :--------------------- | :--------- | :---------- | -| [Swift 5.3](#swift-53) | | | -| [Swift 5.2](#swift-52) | 2020-03-24 | Xcode 11.4 | -| [Swift 5.1](#swift-51) | 2019-09-20 | Xcode 11.0 | -| [Swift 5.0](#swift-50) | 2019-03-25 | Xcode 10.2 | -| [Swift 4.2](#swift-42) | 2018-09-17 | Xcode 10.0 | -| [Swift 4.1](#swift-41) | 2018-03-29 | Xcode 9.3 | -| [Swift 4.0](#swift-40) | 2017-09-19 | Xcode 9.0 | -| [Swift 3.1](#swift-31) | 2017-03-27 | Xcode 8.3 | -| [Swift 3.0](#swift-30) | 2016-09-13 | Xcode 8.0 | -| [Swift 2.2](#swift-22) | 2016-03-21 | Xcode 7.3 | -| [Swift 2.1](#swift-21) | 2015-10-21 | Xcode 7.1 | -| [Swift 2.0](#swift-20) | 2015-09-17 | Xcode 7.0 | -| [Swift 1.2](#swift-12) | 2015-04-08 | Xcode 6.3 | -| [Swift 1.1](#swift-11) | 2014-12-02 | Xcode 6.1.1 | -| [Swift 1.0](#swift-10) | 2014-09-15 | Xcode 6.0 | +| Version | Released | Toolchain | +| :------------------------ | :--------- | :---------- | +| [Swift Next](#swift-next) | +| [Swift 5.3](#swift-53) | | | +| [Swift 5.2](#swift-52) | 2020-03-24 | Xcode 11.4 | +| [Swift 5.1](#swift-51) | 2019-09-20 | Xcode 11.0 | +| [Swift 5.0](#swift-50) | 2019-03-25 | Xcode 10.2 | +| [Swift 4.2](#swift-42) | 2018-09-17 | Xcode 10.0 | +| [Swift 4.1](#swift-41) | 2018-03-29 | Xcode 9.3 | +| [Swift 4.0](#swift-40) | 2017-09-19 | Xcode 9.0 | +| [Swift 3.1](#swift-31) | 2017-03-27 | Xcode 8.3 | +| [Swift 3.0](#swift-30) | 2016-09-13 | Xcode 8.0 | +| [Swift 2.2](#swift-22) | 2016-03-21 | Xcode 7.3 | +| [Swift 2.1](#swift-21) | 2015-10-21 | Xcode 7.1 | +| [Swift 2.0](#swift-20) | 2015-09-17 | Xcode 7.0 | +| [Swift 1.2](#swift-12) | 2015-04-08 | Xcode 6.3 | +| [Swift 1.1](#swift-11) | 2014-12-02 | Xcode 6.1.1 | +| [Swift 1.0](#swift-10) | 2014-09-15 | Xcode 6.0 |
+Swift Next +---------- + +* [SE-0287][]: + + Implicit member expressions now support chains of member accesses, making the following valid: + + ```swift + let milky: UIColor = .white.withAlphaComponent(0.5) + let milky2: UIColor = .init(named: "white")!.withAlphaComponent(0.5) + let milkyChance: UIColor? = .init(named: "white")?.withAlphaComponent(0.5) + ``` + + As is the case with the existing implicit member expression syntax, the resulting type of the chain must be the same as the (implicit) base, so it is not well-formed to write: + + ```swift + let cgMilky: CGColor = .white.withAlphaComponent(0.5).cgColor + ``` + + (Unless, of course, appropriate `white` and `withAlphaComponent` members were defined on `CGColor`.) + + Members of a "chain" can be properties, method calls, subscript accesses, force unwraps, or optional chaining question marks. Furthermore, the type of each member along the chain is permitted to differ (again, as long as the base of the chain matches the resulting type) meaning the following successfully typechecks: + + ```swift + struct Foo { + static var foo = Foo() + static var bar = Bar() + + var anotherFoo: Foo { Foo() } + func getFoo() -> Foo { Foo() } + var optionalFoo: Foo? { Foo() } + subscript() -> Foo { Foo() } + } + + struct Bar { + var anotherFoo = Foo() + } + + let _: Foo? = .bar.anotherFoo.getFoo().optionalFoo?.optionalFoo![] + ``` + Swift 5.3 --------- +* [SE-0279][] & [SE-0286][]: + + Trailing closure syntax has been extended to allow additional labeled closures to follow the initial unlabeled closure: + + ```swift + // Single trailing closure argument + UIView.animate(withDuration: 0.3) { + self.view.alpha = 0 + } + // Multiple trailing closure arguments + UIView.animate(withDuration: 0.3) { + self.view.alpha = 0 + } completion: { _ in + self.view.removeFromSuperview() + } + ``` + + Additionally, trailing closure arguments now match the appropriate parameter according to a forward-scan rule (as opposed to the previous backward-scan rule): + + ```swift + func takesClosures(first: () -> Void, second: (Int) -> Void = { _ in }) {} + + takesClosures { + print("First") + } + ``` + + In the above example, the trailing closure argument matches parameter `first`, whereas pre-Swift-5.3 it would have matched `second`. In order to ease the transition to this new rule, cases in which the forward-scan and backward-scan match a single trailing closure to different parameters, the backward-scan result is preferred and a warning is emitted. This is expected to be upgraded to an error in the next major version of Swift. + * [SR-7083][]: Property observers such as `willSet` and `didSet` are now supported on `lazy` properties: @@ -8070,7 +8141,10 @@ Swift 1.0 [SE-0268]: [SE-0269]: [SE-0276]: +[SE-0279]: [SE-0280]: +[SE-0286]: +[SE-0287]: [SR-75]: [SR-106]: diff --git a/CMakeLists.txt b/CMakeLists.txt index 31d450f959d8d..38f3b831b2f59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -369,6 +369,10 @@ option(SWIFT_REPORT_STATISTICS "Create json files which contain internal compilation statistics" FALSE) +option(SWIFT_DISABLE_OBJC_INTEROP + "Disable Objective-C interoperability even on platforms what would normally have it" + FALSE) + # FIXME(wasm) Reflection tests are temporalily disabled due to lack of linker features option(SWIFTWASM_DISABLE_REFLECTION_TEST "Disable building swift-reflection-test for WebAssembly build" @@ -391,10 +395,6 @@ option(SWIFT_RUNTIME_ENABLE_LEAK_CHECKER "Should the runtime be built with support for non-thread-safe leak detecting entrypoints" FALSE) -option(SWIFT_STDLIB_USE_NONATOMIC_RC - "Build the standard libraries and overlays with nonatomic reference count operations enabled" - FALSE) - option(SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS "Enable runtime function counters and expose the API." FALSE) @@ -634,6 +634,22 @@ if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC" OR "${CMAKE_CXX_SIMULATE_ID}" STREQU set(SWIFT_COMPILER_IS_MSVC_LIKE TRUE) endif() +if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) + # CMake's default for CMAKE_CXX_FLAGS_RELEASE is "-O3 -DNDEBUG". Let's avoid "-O3" for consistency + # between Release and RelWithDebInfo. Dropping -DNDEBUG from this setting is blocked by triggering + # a test failure of Swift-Unit :: Syntax/./SwiftSyntaxTests/TypeSyntaxTests.MetatypeTypeWithAPIs + # because unit tests don't currently explicitly set -DNDEBUG/-UNDEBUG. + set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") + + _compute_lto_flag("${SWIFT_TOOLS_ENABLE_LTO}" _lto_flag_out) + if(_lto_flag_out) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_RELEASE} -gline-tables-only") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -gline-tables-only") + endif() +else() + +endif() + # # Configure SDKs. # @@ -933,7 +949,6 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") endif() endif() -find_package(Python2 COMPONENTS Interpreter REQUIRED) find_package(Python3 COMPONENTS Interpreter REQUIRED) # diff --git a/README.md b/README.md index e99f28b549c8d..ab4a2a6033f29 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,14 @@ The required version of Xcode changes frequently, and is often a beta release. Check this document or the host information on for the current required version. +Swift's build tooling is meant to support spaces in the paths passed to them, +but using spaces sometimes tickles bugs in Swift's build scripts or the tools +they rely on. For example, [SR-13441](https://bugs.swift.org/browse/SR-13441) +is caused by a space in the Xcode path used on macOS. If you see Swift's build +tooling misbehave due to a space in a path, please +[report the bug on the Swift bug tracker](https://swift.org/contributing/#reporting-bugs) +and then change the path to work around it. + You will also need [CMake](https://cmake.org) and [Ninja](https://ninja-build.org), which can be installed via a package manager: diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index ef28ed87b2483..f63860100e928 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -91,6 +91,7 @@ set(SWIFT_BENCH_MODULES single-source/Fibonacci single-source/FindStringNaive single-source/FlattenList + single-source/FloatingPointConversion single-source/FloatingPointParsing single-source/FloatingPointPrinting single-source/Hanoi @@ -136,6 +137,7 @@ set(SWIFT_BENCH_MODULES single-source/PrefixWhile single-source/Prims single-source/PrimsNonStrongRef + single-source/ProtocolConformance single-source/ProtocolDispatch single-source/ProtocolDispatch2 single-source/Queue diff --git a/benchmark/scripts/Template.swift b/benchmark/scripts/Template.swift index 00337a1fb48b4..ea25b249d4679 100644 --- a/benchmark/scripts/Template.swift +++ b/benchmark/scripts/Template.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -19,4 +19,4 @@ public let {name} = [ @inline(never) public func run_{name}(N: Int) {{ // TODO -}} \ No newline at end of file +}} diff --git a/benchmark/single-source/FloatingPointConversion.swift b/benchmark/single-source/FloatingPointConversion.swift new file mode 100644 index 0000000000000..ebf2c6d4b19a3 --- /dev/null +++ b/benchmark/single-source/FloatingPointConversion.swift @@ -0,0 +1,190 @@ +//===--- FloatingPointConversion.swift ------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import TestsUtils + +public let FloatingPointConversion = [ + BenchmarkInfo( + name: "ConvertFloatingPoint.ConcreteDoubleToDouble", + runFunction: run_ConvertFloatingPoint_ConcreteDoubleToDouble, + tags: [.validation, .api], + setUpFunction: { blackHole(doubles) }), + BenchmarkInfo( + name: "ConvertFloatingPoint.GenericDoubleToDouble", + runFunction: run_ConvertFloatingPoint_GenericDoubleToDouble, + tags: [.validation, .api], + setUpFunction: { blackHole(doubles) }), + BenchmarkInfo( + name: "ConvertFloatingPoint.MockFloat64ToDouble", + runFunction: run_ConvertFloatingPoint_MockFloat64ToDouble, + tags: [.validation, .api], + setUpFunction: { blackHole(mockFloat64s) }), +] + +protocol MockBinaryFloatingPoint: BinaryFloatingPoint { + associatedtype _Value: BinaryFloatingPoint + var _value: _Value { get set } + init(_ _value: _Value) +} + +extension MockBinaryFloatingPoint { + static var exponentBitCount: Int { _Value.exponentBitCount } + static var greatestFiniteMagnitude: Self { + Self(_Value.greatestFiniteMagnitude) + } + static var infinity: Self { Self(_Value.infinity) } + static var leastNonzeroMagnitude: Self { Self(_Value.leastNonzeroMagnitude) } + static var leastNormalMagnitude: Self { Self(_Value.leastNormalMagnitude) } + static var nan: Self { Self(_Value.nan) } + static var pi: Self { Self(_Value.pi) } + static var signalingNaN: Self { Self(_Value.signalingNaN) } + static var significandBitCount: Int { _Value.significandBitCount } + + static func + (lhs: Self, rhs: Self) -> Self { Self(lhs._value + rhs._value) } + static func += (lhs: inout Self, rhs: Self) { lhs._value += rhs._value } + static func - (lhs: Self, rhs: Self) -> Self { Self(lhs._value - rhs._value) } + static func -= (lhs: inout Self, rhs: Self) { lhs._value -= rhs._value } + static func * (lhs: Self, rhs: Self) -> Self { Self(lhs._value * rhs._value) } + static func *= (lhs: inout Self, rhs: Self) { lhs._value *= rhs._value } + static func / (lhs: Self, rhs: Self) -> Self { Self(lhs._value / rhs._value) } + static func /= (lhs: inout Self, rhs: Self) { lhs._value /= rhs._value } + + init(_ value: Int) { self.init(_Value(value)) } + init(_ value: Float) { self.init(_Value(value)) } + init(_ value: Double) { self.init(_Value(value)) } + #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + init(_ value: Float80) { self.init(_Value(value)) } + #endif + init(integerLiteral value: _Value.IntegerLiteralType) { + self.init(_Value(integerLiteral: value)) + } + init(floatLiteral value: _Value.FloatLiteralType) { + self.init(_Value(floatLiteral: value)) + } + init(sign: FloatingPointSign, exponent: _Value.Exponent, significand: Self) { + self.init( + _Value(sign: sign, exponent: exponent, significand: significand._value)) + } + init( + sign: FloatingPointSign, + exponentBitPattern: _Value.RawExponent, + significandBitPattern: _Value.RawSignificand + ) { + self.init( + _Value( + sign: sign, + exponentBitPattern: exponentBitPattern, + significandBitPattern: significandBitPattern)) + } + + var binade: Self { Self(_value.binade) } + var exponent: _Value.Exponent { _value.exponent } + var exponentBitPattern: _Value.RawExponent { _value.exponentBitPattern } + var isCanonical: Bool { _value.isCanonical } + var isFinite: Bool { _value.isFinite } + var isInfinite: Bool { _value.isInfinite } + var isNaN: Bool { _value.isNaN } + var isNormal: Bool { _value.isNormal } + var isSignalingNaN: Bool { _value.isSignalingNaN } + var isSubnormal: Bool { _value.isSubnormal } + var isZero: Bool { _value.isZero } + var magnitude: Self { Self(_value.magnitude) } + var nextDown: Self { Self(_value.nextDown) } + var nextUp: Self { Self(_value.nextUp) } + var sign: FloatingPointSign { _value.sign } + var significand: Self { Self(_value.significand) } + var significandBitPattern: _Value.RawSignificand { + _value.significandBitPattern + } + var significandWidth: Int { _value.significandWidth } + var ulp: Self { Self(_value.ulp) } + + mutating func addProduct(_ lhs: Self, _ rhs: Self) { + _value.addProduct(lhs._value, rhs._value) + } + func advanced(by n: _Value.Stride) -> Self { Self(_value.advanced(by: n)) } + func distance(to other: Self) -> _Value.Stride { + _value.distance(to: other._value) + } + mutating func formRemainder(dividingBy other: Self) { + _value.formRemainder(dividingBy: other._value) + } + mutating func formSquareRoot() { _value.formSquareRoot() } + mutating func formTruncatingRemainder(dividingBy other: Self) { + _value.formTruncatingRemainder(dividingBy: other._value) + } + func isEqual(to other: Self) -> Bool { _value.isEqual(to: other._value) } + func isLess(than other: Self) -> Bool { _value.isLess(than: other._value) } + func isLessThanOrEqualTo(_ other: Self) -> Bool { + _value.isLessThanOrEqualTo(other._value) + } + mutating func round(_ rule: FloatingPointRoundingRule) { _value.round(rule) } +} + +struct MockFloat64: MockBinaryFloatingPoint { + var _value: Double + init(_ _value: Double) { self._value = _value } +} + +let doubles = [ + 1.8547832857295, 26.321549267719135, 98.9544480962058, 73.70286973782363, + 82.04918555938816, 76.38902969312758, 46.35647857011161, 64.0821426030317, + 97.82373347320156, 55.742361037720634, 23.677941665488856, 93.7347588108058, + 80.72657040828412, 32.137580733275826, 64.78192587530002, 21.459686568896863, + 24.88407660280718, 85.25905561999171, 12.858847331083556, 29.418845887252864, + 67.64627066438761, 68.09883494078815, 57.781587230862094, 63.38335631088038, + 83.31376661495327, 87.45936846358906, 0.6757674136841918, 86.45465036820696, + 84.72715137492781, 82.67894289189142, 26.1667640621554, 21.24895661442493, + 65.06399183516027, 90.06549073883058, 59.2736650501005, 94.5800380563246, + 84.22617424003917, 26.93158630395639, 9.069952095976841, 96.10067836567679, + 62.60505762081415, 29.57878462599286, 66.06040114311294, 51.709999429326636, + 64.79777579583545, 45.25948795832151, 94.31492354198335, 52.31096166433902, +] + +let mockFloat64s = doubles.map { MockFloat64($0) } + +@inline(__always) +func convert< + T: BinaryFloatingPoint, U: BinaryFloatingPoint +>(_ value: T, to: U.Type) -> U { + U(value) +} + +@inline(never) +public func run_ConvertFloatingPoint_ConcreteDoubleToDouble(_ N: Int) { + for _ in 0..<(N * 100) { + for element in doubles { + let f = Double(identity(element)) + blackHole(f) + } + } +} + +@inline(never) +public func run_ConvertFloatingPoint_GenericDoubleToDouble(_ N: Int) { + for _ in 0..<(N * 100) { + for element in doubles { + let f = convert(identity(element), to: Double.self) + blackHole(f) + } + } +} + +@inline(never) +public func run_ConvertFloatingPoint_MockFloat64ToDouble(_ N: Int) { + for _ in 0..<(N * 100) { + for element in mockFloat64s { + let f = Double(identity(element)) + blackHole(f) + } + } +} diff --git a/benchmark/single-source/ProtocolConformance.swift b/benchmark/single-source/ProtocolConformance.swift new file mode 100644 index 0000000000000..b042065c02ab3 --- /dev/null +++ b/benchmark/single-source/ProtocolConformance.swift @@ -0,0 +1,76 @@ +//===--- ProtocolDispatch.swift -------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import TestsUtils + +public let ProtocolConformance = BenchmarkInfo ( + name: "ProtocolConformance", + runFunction: run_ProtocolConformance, + tags: [.validation, .runtime]) + +protocol P {} + +struct One: P {} +struct Two {} + +struct Cat {} + +extension Cat: P where T: P, U: P {} + +protocol Growable {} +extension Growable { + func grow() -> (Growable, Growable) { + return (Cat(), Cat()) + } +} + +extension One: Growable {} +extension Two: Growable {} +extension Cat: Growable {} + +@inline(never) +public func run_ProtocolConformance(_ N: Int) { + var array: [Growable] = [One(), Two()] + var i = 0 + var checks = 0 + + // The expected number of times we expect `elt is P` to be true. + var expectedConforms = 0 + + // The expected number of times we expect `elt is P` to be true + // per iteration, at the current time. + var expectedConformsPerIter = 1 + + // The number of times we've actually seen `elt is P` be true. + var conforms = 0 + while checks < N * 500 { + let (a, b) = array[i].grow() + array.append(a) + array.append(b) + + // The number of times `elt is P` is true per outer iteration + // goes up by 1 when the array's count is a power of 2. + if array.count & (array.count - 1) == 0 { + expectedConformsPerIter += 1 + } + expectedConforms += expectedConformsPerIter + + for elt in array { + if elt is P { + conforms += 1 + } + checks += 1 + } + i += 1 + } + CheckResults(expectedConforms == conforms) +} diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift index b4791ad6208e7..160c4eb50c8a3 100644 --- a/benchmark/utils/main.swift +++ b/benchmark/utils/main.swift @@ -79,6 +79,7 @@ import ExistentialPerformance import Fibonacci import FindStringNaive import FlattenList +import FloatingPointConversion import FloatingPointParsing import FloatingPointPrinting import Hanoi @@ -131,6 +132,7 @@ import PrefixWhile import Prims import PrimsNonStrongRef import PrimsSplit +import ProtocolConformance import ProtocolDispatch import ProtocolDispatch2 import Queue @@ -265,6 +267,7 @@ registerBenchmark(Fibonacci) registerBenchmark(FindStringNaive) registerBenchmark(FlattenListLoop) registerBenchmark(FlattenListFlatMap) +registerBenchmark(FloatingPointConversion) registerBenchmark(FloatingPointParsing) registerBenchmark(FloatingPointPrinting) registerBenchmark(Hanoi) @@ -317,6 +320,7 @@ registerBenchmark(PrefixWhile) registerBenchmark(Prims) registerBenchmark(PrimsNonStrongRef) registerBenchmark(PrimsSplit) +registerBenchmark(ProtocolConformance) registerBenchmark(ProtocolDispatch) registerBenchmark(ProtocolDispatch2) registerBenchmark(QueueGeneric) diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 1db26266cb757..e4304b6b484eb 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -93,7 +93,7 @@ function(_add_host_variant_c_compile_link_flags name) set(_sysroot "${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${SWIFT_HOST_VARIANT_ARCH}_PATH}") - if(SWIFT_HOST_VARIANT_SDK IN_LIST SWIFT_APPLE_PLATFORMS) + if(SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_USE_ISYSROOT) target_compile_options(${name} PRIVATE -isysroot;${_sysroot}) elseif(NOT SWIFT_COMPILER_IS_MSVC_LIKE AND NOT "${_sysroot}" STREQUAL "/") target_compile_options(${name} PRIVATE --sysroot=${_sysroot}) @@ -130,13 +130,18 @@ function(_add_host_variant_c_compile_flags target) _add_host_variant_c_compile_link_flags(${target}) is_build_type_optimized("${CMAKE_BUILD_TYPE}" optimized) - if(optimized) - target_compile_options(${target} PRIVATE -O2) + is_build_type_with_debuginfo("${CMAKE_BUILD_TYPE}" debuginfo) + # Add -O0/-O2/-O3/-Os/-g/-momit-leaf-frame-pointer/... based on CMAKE_BUILD_TYPE. + target_compile_options(${target} PRIVATE "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}") + + if(optimized) # Omit leaf frame pointers on x86 production builds (optimized, no debug # info, and no asserts). - is_build_type_with_debuginfo("${CMAKE_BUILD_TYPE}" debug) - if(NOT debug AND NOT LLVM_ENABLE_ASSERTIONS) + if(NOT debuginfo AND NOT LLVM_ENABLE_ASSERTIONS) + # Unfortunately, this cannot be folded into the standard + # CMAKE_CXX_FLAGS_... because Apple multi-SDK builds use different + # architectures for different SDKs. if(SWIFT_HOST_VARIANT_ARCH MATCHES "i?86") if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) target_compile_options(${target} PRIVATE -momit-leaf-frame-pointer) @@ -145,27 +150,6 @@ function(_add_host_variant_c_compile_flags target) endif() endif() endif() - else() - if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) - target_compile_options(${target} PRIVATE -O0) - else() - target_compile_options(${target} PRIVATE /Od) - endif() - endif() - - # CMake automatically adds the flags for debug info if we use MSVC/clang-cl. - if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) - is_build_type_with_debuginfo("${CMAKE_BUILD_TYPE}" debuginfo) - if(debuginfo) - _compute_lto_flag("${SWIFT_TOOLS_ENABLE_LTO}" _lto_flag_out) - if(_lto_flag_out) - target_compile_options(${target} PRIVATE -gline-tables-only) - else() - target_compile_options(${target} PRIVATE -g) - endif() - else() - target_compile_options(${target} PRIVATE -g0) - endif() endif() if(SWIFT_HOST_VARIANT_SDK STREQUAL WINDOWS) diff --git a/cmake/modules/DarwinSDKs.cmake b/cmake/modules/DarwinSDKs.cmake index 20a5620fba6a7..dc570b7005834 100644 --- a/cmake/modules/DarwinSDKs.cmake +++ b/cmake/modules/DarwinSDKs.cmake @@ -26,6 +26,24 @@ if(swift_build_osx) configure_target_variant(OSX-R "OS X Release" OSX R "Release") endif() +is_sdk_requested(FREESTANDING swift_build_freestanding) +if(swift_build_freestanding) + set(SWIFT_FREESTANDING_SDK "" CACHE STRING + "Which SDK to use when building the FREESTANDING stdlib") + set(SWIFT_FREESTANDING_TRIPLE_NAME "" CACHE STRING + "Which triple name (e.g. 'none-macho') to use when building the FREESTANDING stdlib") + set(SWIFT_FREESTANDING_ARCHS "" CACHE STRING + "Which architectures to build when building the FREESTANDING stdlib") + configure_sdk_darwin( + FREESTANDING "FREESTANDING" "" + "${SWIFT_FREESTANDING_SDK}" freestanding "${SWIFT_FREESTANDING_TRIPLE_NAME}" freestanding "${SWIFT_FREESTANDING_ARCHS}") + set(SWIFT_SDK_FREESTANDING_LIB_SUBDIR "freestanding") + configure_target_variant(FREESTANDING-DA "FREESTANDING Debug+Asserts" FREESTANDING DA "Debug+Asserts") + configure_target_variant(FREESTANDING-RA "FREESTANDING Release+Asserts" FREESTANDING RA "Release+Asserts") + configure_target_variant(FREESTANDING-R "FREESTANDING Release" FREESTANDING R "Release") + configure_target_variant(FREESTANDING-S "FREESTANDING MinSizeRelease" FREESTANDING S "MinSizeRelease") +endif() + # Compatible cross-compile SDKS for Darwin OSes: IOS, IOS_SIMULATOR, TVOS, # TVOS_SIMULATOR, WATCHOS, WATCHOS_SIMULATOR (archs hardcoded below). diff --git a/cmake/modules/SwiftConfigureSDK.cmake b/cmake/modules/SwiftConfigureSDK.cmake index 52c08025e62a0..feb7f513c96ce 100644 --- a/cmake/modules/SwiftConfigureSDK.cmake +++ b/cmake/modules/SwiftConfigureSDK.cmake @@ -145,6 +145,8 @@ endfunction() # SWIFT_SDK_${prefix}_LIB_SUBDIR Library subdir for this SDK # SWIFT_SDK_${prefix}_VERSION_MIN_NAME Version min name for this SDK # SWIFT_SDK_${prefix}_TRIPLE_NAME Triple name for this SDK +# SWIFT_SDK_${prefix}_OBJECT_FORMAT The object file format (e.g. MACHO) +# SWIFT_SDK_${prefix}_USE_ISYSROOT Whether to use -isysroot # SWIFT_SDK_${prefix}_ARCHITECTURES Architectures (as a list) # SWIFT_SDK_${prefix}_IS_SIMULATOR Whether this is a simulator target. # SWIFT_SDK_${prefix}_ARCH_${ARCH}_TRIPLE Triple name @@ -187,6 +189,7 @@ macro(configure_sdk_darwin set(SWIFT_SDK_${prefix}_VERSION_MIN_NAME "${version_min_name}") set(SWIFT_SDK_${prefix}_TRIPLE_NAME "${triple_name}") set(SWIFT_SDK_${prefix}_OBJECT_FORMAT "MACHO") + set(SWIFT_SDK_${prefix}_USE_ISYSROOT TRUE) set(SWIFT_SDK_${prefix}_ARCHITECTURES ${architectures}) if(SWIFT_DARWIN_SUPPORTED_ARCHS) @@ -270,6 +273,7 @@ macro(configure_sdk_unix name architectures) else() set(SWIFT_SDK_${prefix}_OBJECT_FORMAT "ELF") endif() + set(SWIFT_SDK_${prefix}_USE_ISYSROOT FALSE) foreach(arch ${architectures}) if("${prefix}" STREQUAL "ANDROID") @@ -432,6 +436,7 @@ macro(configure_sdk_windows name environment architectures) set(SWIFT_SDK_${prefix}_LIB_SUBDIR "windows") set(SWIFT_SDK_${prefix}_ARCHITECTURES "${architectures}") set(SWIFT_SDK_${prefix}_OBJECT_FORMAT "COFF") + set(SWIFT_SDK_${prefix}_USE_ISYSROOT FALSE) foreach(arch ${architectures}) if(arch STREQUAL armv7) diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index a65799b8c53cd..9e60d04a4f5e3 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -176,6 +176,11 @@ Globals global ::= global 'MJ' // noncanonical specialized generic type metadata instantiation cache associated with global global ::= global 'MN' // noncanonical specialized generic type metadata for global + #if SWIFT_RUNTIME_VERSION >= 5.4 + global ::= context (decl-name '_')+ 'WZ' // global variable one-time initialization function + global ::= context (decl-name '_')+ 'Wz' // global variable one-time initialization token + #endif + A direct symbol resolves directly to the address of an object. An indirect symbol resolves to the address of a pointer to the object. They are distinct manglings to make a certain class of bugs @@ -1107,3 +1112,40 @@ nominal type descriptor symbol for ``CxxStruct`` while compiling the ``main`` mo .. code:: sSo9CxxStructVMn // -> nominal type descriptor for __C.CxxStruct + +Importing C++ class template instantiations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A class template instantiation is imported as a struct named +``__CxxTemplateInst`` plus Itanium mangled type of the instantiation (see the +``type`` production in the Itanium specification). Note that Itanium mangling is +used on all platforms, regardless of the ABI of the C++ toolchain, to ensure +that the mangled name is a valid Swift type name (this is not the case for MSVC +mangled names). A prefix with a double underscore (to ensure we have a reserved +C++ identifier) is added to limit the possibility for conflicts with names of +user-defined structs. The struct is notionally defined in the ``__C`` module, +similarly to regular C and C++ structs and classes. Consider the following C++ +module: + +.. code-block:: c++ + + template + struct MagicWrapper { + T t; + }; + + struct MagicNumber {}; + + typedef MagicWrapper WrappedMagicNumber; + +``WrappedMagicNumber`` is imported as a typealias for struct +``__CxxTemplateInst12MagicWrapperI11MagicNumberE``. Interface of the imported +module looks as follows: + +.. code-block:: swift + + struct __CxxTemplateInst12MagicWrapperI11MagicNumberE { + var t: MagicNumber + } + struct MagicNumber {} + typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE diff --git a/docs/Branches.md b/docs/Branches.md index 083f89610419d..036849f9da2a1 100644 --- a/docs/Branches.md +++ b/docs/Branches.md @@ -18,11 +18,11 @@ To switch from one set of branches to another, you can use `utils/update-checkou ## The Release Branches -| Swift | LLVM Project -| ---------------- | ---------------------- -| swift-x.y-branch | swift/swift-x.y-branch +| Swift | LLVM Project +| ----------- | ----------------- +| release/x.y | swift/release/x.y -At some point before a release, a *release branch* will be created in every repository with a name like `swift-4.0-branch`. (The actual number is chosen by Apple.) After the branch has been created, commits must make it to this branch to make it into the release. In some cases, the [release manager][] for the branch will decide to merge in all additional changes from `master`; otherwise, cherry-picking changes and making a new pull request is the way to go. If there are any "patch" releases (e.g. Swift 4.0.1), they will also come from this branch. +At some point before a release, a *release branch* will be created in every repository with a name like `release/5.3`. (The actual number is chosen by Apple.) After the branch has been created, commits must make it to this branch to make it into the release. In some cases, the [release manager][] for the branch will decide to merge in all additional changes from `master`; otherwise, cherry-picking changes and making a new pull request is the way to go. If there are any "patch" releases (e.g. Swift 5.3.1), they will also come from this branch. Note that these branches come not from the "development" branches (above), but the "upstream" branches (below). This is because they need to contain the latest changes not just from Swift, but from the LLVM project as well. For some releases, the release branch for the LLVM project will be timed to coincide with the corresponding llvm.org release branch. @@ -35,7 +35,7 @@ Note that these branches come not from the "development" branches (above), but t `swift/master-next` is a branch for LLVM that includes all changes necessary to support Swift. Changes from llvm.org's master branch are automatically merged in. Why isn't this just `swift/master`? Well, because LLVM changes *very* rapidly, and that wouldn't be very stable. However, we do want to make sure the Swift stuff keeps working. -If you are making changes to LLVM to support Swift, you'll probably need to work on them in `swift/master` to test them against Swift itself, but they should be committed to `swift/master-next`, and cherry-picked to the current release branch (`swift/swift-x.y-branch`) if needed. Remember, the release branches are automerged into `swift/master` on a regular basis. +If you are making changes to LLVM to support Swift, you'll probably need to work on them in `swift/master` to test them against Swift itself, but they should be committed to `swift/master-next`, and cherry-picked to the current release branch (`swift/release/x.y`) if needed. Remember, the release branches are automerged into `swift/master` on a regular basis. (If you're making changes to LLVM Project that *aren't* about Swift, they should generally be made on llvm.org instead, then cherry-picked to the active release branch or `swift/master`.) @@ -83,6 +83,6 @@ Some branches are *automerged* into other branches, to keep them in sync. This i - `master` is automerged into `master-next` ### LLVM Project -- `swift/swift-x.y-branch` (the *latest* release branch) is automerged into `swift/master` +- `swift/release/x.y` (the *latest* release branch) is automerged into `swift/master` - llvm.org's `master` is automerged into `swift/master-next` -- llvm.org's release branch *may* be automerged into `swift/swift-x.y-branch`, if they are in sync +- llvm.org's release branch *may* be automerged into `swift/release/x.y`, if they are in sync diff --git a/docs/CppInteroperabilityManifesto.md b/docs/CppInteroperabilityManifesto.md index f3a8df51820d2..b23c914268c1b 100644 --- a/docs/CppInteroperabilityManifesto.md +++ b/docs/CppInteroperabilityManifesto.md @@ -67,6 +67,7 @@ Assumptions: + [Function templates: calls with generic type parameters](#function-templates-calls-with-generic-type-parameters) + [Function templates: importing as real generic functions](#function-templates-importing-as-real-generic-functions) + [Class templates](#class-templates) + + [Class templates: importing instantiation behind typedef](#class-templates-importing-instantiation-behind-typedef) + [Class templates: importing specific specilalizations](#class-templates-importing-specific-specilalizations) + [Class templates: using with generic type parameters](#class-templates-using-with-generic-type-parameters) + [Class templates: using in generic code through a synthesized protocol](#class-templates-using-in-generic-code-through-a-synthesized-protocol) @@ -2575,6 +2576,45 @@ We could ignore explicit specializations of function templates, because they don't affect the API. Explicit specializations of class templates can dramatically change the API of the type. +### Class templates: Importing full class template instantiations + +A class template instantiation could be imported as a struct named +`__CxxTemplateInst` plus Itanium mangled type of the instantiation (see the +`type` production in the Itanium specification). Note that Itanium mangling is +used on all platforms, regardless of the ABI of the C++ toolchain, to ensure +that the mangled name is a valid Swift type name (this is not the case for MSVC +mangled names). A prefix with a double underscore (to ensure we have a reserved +C++ identifier) is added to limit the possibility for conflicts with names of +user-defined structs. The struct is notionally defined in the `__C` module, +similarly to regular C and C++ structs and classes. Consider the following C++ +module: + +```c++ +// C++ header. + +template +struct MagicWrapper { + T t; +}; +struct MagicNumber {}; + +typedef MagicWrapper WrappedMagicNumber; +``` + +`WrappedMagicNumber` will be imported as a typealias for a struct +`__CxxTemplateInst12MagicWrapperI11MagicNumberE`. Interface of the imported +module will look as follows: + +```swift +// C++ header imported to Swift. + +struct __CxxTemplateInst12MagicWrapperI11MagicNumberE { + var t: MagicNumber +} +struct MagicNumber {} +typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE +``` + ### Class templates: importing specific specilalizations Just like with calls to C++ function templates, it is easy to compile a use of a @@ -2752,7 +2792,7 @@ func useConcrete() { ### Class templates: importing as real generic structs -If we know the complete set of allowed type arguments to a C++ function +If we know the complete set of allowed type arguments to a C++ struct template, we could import it as an actual Swift generic struct. Every method of that struct will perform dynamic dispatch based on type parameters. See the section about function templates for more details. diff --git a/docs/DynamicCasting.md b/docs/DynamicCasting.md new file mode 100644 index 0000000000000..0efc4fcb862b8 --- /dev/null +++ b/docs/DynamicCasting.md @@ -0,0 +1,729 @@ +# Dynamic Casting Behavior + +* Author: [Tim Kientzle](https://github.com/tbkka) +* Implementation: [apple/swift#29658](https://github.com/apple/swift/pull/29658) + +## Introduction + +The Swift language has three casting operators: `is`, `as?`, and `as!`. +Each one takes an instance on the left-hand side and a type expression on the right-hand side. + +* The _cast test operator_ `is` tests whether a particular instance can be converted to a particular destination type. It returns a boolean result. + +* The _conditional cast operator_ `as?` attempts the conversion and returns an `Optional` result: `nil` if the conversion failed, and a non-nil optional containing the result otherwise. + +* The _forced cast operator_ `as!` unconditionally performs the casting conversion and returns the result. If an `as!` expression does not succeed, the implementation may terminate the program. + +Note: The static coercion operator `as` serves a different role and its behavior will not be specifically discussed in this document. + +The following invariants relate the three casting operators: +* Cast test: `x is T == ((x as? T) != nil)` +* Conditional cast: `(x as? T) == (x is T) ? .some(x as! T) : nil` +* Forced cast: `x as! T` is equivalent to `(x as? T)!` + +In particular, note that `is` and `as!` can be implemented in terms of `as?` and vice-versa. + +As with other operators with `!` in their names, `as!` is intended to only be invoked in cases where the programmer knows a priori that the cast will succeed. +If the conversion would not succeed, then the behavior may not be fully deterministic. +See the discussion of Array casting below for a specific case where this non-determinism can be important. + +The following sections detail the rules that govern the casting operations for particular Swift types. +Except where noted, casting between types described in different sections below will always fail -- for example, casting a struct instance to a function type or vice-versa. + +Where possible, each section includes machine-verifiable _invariants_ that can be used as the basis for developing a robust test suite for this functionality. + +## Identity Cast + +Casting an instance of a type to its own type will always succeed and return the original value unchanged. + +``` +let a: Int = 7 +a is Int // true +a as? Int // Succeeds +a as! Int == a // true +``` + +## Class and Foreign Types + +Class types generally follow standard object-oriented casting conventions. +Objective-C and CoreFoundation (CF) types follow the behaviors expected from Objective-C. + +### Classes + +Casting among class types follows standard object-oriented programming conventions: + +* Class upcasts: If `C` is a subclass of `SuperC` and `c` is an instance of `C`, then `c is SuperC == true` and `(c as? SuperC) != nil`. (Note: These "upcasts" do not change the in-memory representation.) However, when `c` is accessed via a variable or expression of type `SuperC`, only methods and instance variables defined on `SuperC` are available. + +* Class downcasts: If `C` is a subclass of `SuperC` and `sc` is an instance of `SuperC`, then `sc is C` will be true iff `sc` is actually an instance of `C`. (Note: Again, a downcast does not affect the in-memory representation.) + +* Objective-C class casting: The rules above also apply when one of the classes in question is defined with the `@objc` attribute or inherits from an Objective-C class. + +* Class casts to AnyObject: Any class reference can be cast to `AnyObject` and then cast back to the original type. See "AnyObject" below. + +* If a struct or enum type conforms to `_ObjectiveCBridgeable`, then classes of the associated bridging type can be cast to the struct or enum type and vice versa. See "The `_ObjectiveCBridgeable` Protocol" below. + +Invariants: +* For any two class types `C1` and `C2`: `c is C1 && c is C2` iff `((c as? C1) as? C2) != nil` +* For any class type `C`: `c is C` iff `(c as! AnyObject) is C` +* For any class type `C`: if `c is C`, then `(c as! AnyObject) as! C === c` + +### CoreFoundation types + +* If `CF` is a CoreFoundation type, `cf` is an instance of `CF`, and `NS` is the corresponding Objective-C type, then `cf is NS == true` +* Further, since every Objective-C type inherits from `NSObject`, `cf is NSObject == true` +* In the above situation, if `T` is some other type and `cf is NS == true`, then `cf as! NS is T` iff `cf is T`. + +The intention of the above is to treat instances of CoreFoundation types as being simultaneously instances of the corresponding Objective-C type, in keeping with the general dual nature of these types. +In particular, if a protocol conformance is declared on the Objective-C type, then instances of the CoreFoundation type can be cast to the protocol type directly. + +XXX TODO: Converse? If ObjC instance has CF equivalent and CF type is extended, ... ?? + +### Objective-C types + +The following discussion applies in three different cases: +* _Explicit_ conversions from use of the `is`, `as?`, and `as!` operators. +* _Implicit_ conversions from Swift to Objective-C: These conversions are generated automatically when Swift code calls an Objective-C function or method with an argument that is not already of an Objective-C type, or when a Swift function returns a value to an Objective-C caller. +* _Implicit_ conversions from Objective-C to Swift: These are generated automatically when arguments are passed from an Objective-C caller to a Swift function, or when an Objective-C function returns a value to a Swift caller. +Unless stated otherwise, all of the following cases apply equally to all three of the above cases. + +Explicit casts among Swift and Objective-C class types follow the same general rules described earlier for class types in general. +Likewise, explicitly casting a class instance to an Objective-C protocol type follows the general rules for casts to protocol types. + +XXX TODO EXPLAIN Implicit conversions from Objective-C types to Swift types XXXX. + +CoreFoundation types can be explicitly cast to and from their corresponding Objective-C types as described above. + +Objective-C types and protocols +* `T` is an Objective-C class type iff `T.self is NSObject.Type` +* `P` is an Objective-C protocol iff XXX TODO XXX + +### The `_ObjectiveCBridgeable` Protocol + +The `_ObjectiveCBridgeable` protocol allows certain types to opt into custom casting behavior. +Note that although this mechanism was explicitly designed to simplify Swift interoperability with Objective-C, it is not necessarily tied to Objective-C. + +The `_ObjectiveCBridgeable` protocol defines an associated reference type `_ObjectiveCType`, along with a collection of methods that support casting to and from the associated `_ObjectiveCType`. +This protocol allows library code to provide tailored mechanisms for casting Swift types to reference types. +When casting to `AnyObject`, the casting logic prefers this tailored mechanism to the general `_SwiftValue` container mentioned above. + +Note: The associated `_ObjectiveCType` is constrained to be a subtype of `AnyObject`; it is not limited to being an actual Objective-C type. +In particular, this mechanism is equally available to the Swift implementation of Foundation on non-Apple platforms and the Objective-C Foundation on Apple platforms. + +Example #1: Foundation extends the `Array` type in the standard library with an `_ObjectiveCBridgeable` conformance to `NSArray`. This allows Swift arrays to be cast to and from Foundation `NSArray` instances. +``` +let a = [1, 2, 3] // Array +let b = a as? AnyObject // casts to NSArray +``` + +Example #2: Foundation also extends each Swift numeric type with an `_ObjectiveCBridgeable` conformance to `NSNumber`. +``` +let a = 1 // Int +// After the next line, b is an Optional +// holding a reference to an NSNumber +let b = a as? AnyObject +// NSNumber is bridgeable to Double +let c = b as? Double +``` + +## Other Concrete Types + +In addition to the class types described earlier, Swift has several other kinds of concrete types. + +Casting between the different kinds described below (such as casting an enum to a tuple) will always fail. + +### Structs and Enums + +You cannot cast between different concrete struct or enum types. +More formally: + +* If `S` and `T` are struct or enum types and `s is S == true`, then `s is T` iff `S.self == T.self`. + +Struct or enum types can be cast to class types if the struct or enum implements the `_ObjectiveCBridgeable` protocol as described earlier. + +### Optionals + +Casting to and from optional types will transparently unwrap optionals as much as necessary, including nested optional types. + +* If `T` and `U` are any two types, and `t` is an instance of `T`, then `.some(t) is Optional == t is U` +* Optional injection: if `T` and `U` are any two types, `t` is a non-nil instance of `T`, then `t is Optional == t is U` +* Optional projection: if `T` and `U` are any two types, and `t` is an instance of `T`, then `.some(t) is U == t is U` +* Nil Casting: if `T` and `U` are any two types, then `Optional.none is Optional == true` + +Note: For "Optional Injection" above, the requirement that `t` is a non-nil instance of `T` implies that either `T` is not an `Optional` or that `T` is `Optional` and `t` has the form `.some(u)` + +Examples +``` +// T and U are any two distinct types (possibly optional) +// NO is any non-optional type +let t: T +let u: U +let no: NO +// Casting freely adds/removes optional wrappers +t is Optional == true +t is Optional> == true +Optional.some(t) is T == true +Optional>.some(.some(t)) is T == true +// Non-optionals cast to optionals iff they cast to the inner type +no is Optional == no is U +Optional.some(no) is Optional == no is U +// Non-nil optionals cast to a different type iff the inner value does +Optional.some(t) is U == t is U +Optional>.some(.some(t)) is U == t is U +// Nil optionals always cast to other optional types +Optional.none is Optional == true +// Nil optionals never cast to non-optionals +Optional.none is NO == false +``` + +Depth Preservation: +The rules above imply that nested optionals are transparently unwrapped to arbitrary depth. +For example, if an instance of `T` can be cast to type `U`, then `T????` can be cast to `U????`. +This can be ambiguous if the former contains a `nil` value; +casting the nil to `U????` might end up with any of the following distinct values `.none`, `.some(.none)`, `.some(.some(.none))`, or `.some(.some(.some(.none)))`. + +To resolve this ambiguity, the implementation should first inspect the type of the inner `.none` value and count the optional depth. +Note that "optional depth" here refers to the number of optional wrappers needed to get from the innermost non-optional type to the type of the `.none`. + +1. If the target allows it, the value should inject into the target with the same optional depth as the source. +2. Otherwise, the value should inject with the greatest optional depth possible. + +Examples +``` +// Depth preservation +// The `.none` here has type `T?` with optional depth 1 +let t1: T???? = .some(.some(.some(.none))) +// This `.none` has type `T????` with optional depth 4 +let t4: T???? = .none +// Result has optional depth 1, matching source +t1 as! U???? // Produces .some(.some(.some(.none))) +t1 as! U??? // Produces .some(.some(.none)) +t1 as! U?? // Produces .some(.none) +t1 as! U? // Produces .none +// Result has optional depth 2, because 4 is not possible +t4 as! U?? // Produces .none +// Remember that `as?` adds a layer of optional +// These casts succeed, hence the outer `.some` +t1 as? U???? // Produces .some(.some(.some(.some(.none)))) +t1 as? U??? // Produces .some(.some(.some(.none))) +t1 as? U?? // Produces .some(.some(.none)) +t1 as? U? // Produces .some(.none) +t4 as? U?? // Produces .some(.none) +``` + +### Array/Set/Dictionary Casts + +For Array, Set, or Dictionary types, you can use the casting operators to translate to another instance of the same outer container (Array, Set, or Dictionary respectively) with a different component type. +Note that the following discussion applies only to these specific types. +It does not apply to any other types, nor is there any mechanism to add this behavior to other types. + +Example: Given an `arr` of type `Array`, you can cast `arr as? Array`. +The result will be a new array where each `Int` in the original array has been individually cast to an `Any`. + +However, if any component item cannot be cast, then the outer cast will also fail. +For example, consider the following: +``` +let a: Array = [Int(7), "string"] +a as? Array // Fails because "string" cannot be cast to `Int` +``` + +Specifically, the casting operator acts for `Array` as if it were implemented as follows. +In particular, note that an empty array can be successfully cast to any destination array type. +``` +func arrayCast(source: Array) -> Optional> { + var result = Array() + for t in source { + if let u = t as? U { + result.append(u) + } else { + return nil + } + } + return result +} +``` + +Invariants +* Arrays cast iff their contents do: If `t` is an instance of `T` and `U` is any type, then `t is U == [t] is [U]` +* Empty arrays always cast: If `T` and `U` are any types, `Array() is Array` + +Similar logic applies to `Set` and `Dictionary` casts. +Note that the resulting `Set` or `Dictionary` may have fewer items than the original if the component casting operation converts non-equal items in the source into equal items in the destination. + +Specifically, the casting operator acts on `Set` and `Dictionary` as if by the following code: +``` +func setCast(source: Set) -> Optional> { + var result = Set() + for t in source { + if let u = t as? U { + result.append(u) + } else { + return nil + } + } + return result +} + +func dictionaryCast(source: Dictionary) -> Optional> { + var result = Dictionary() + for (k,v) in source { + if let k2 = k as? K2, v2 = v as? V2 { + result[k2] = v2 + } else { + return nil + } + } + return result +} +``` + +#### Collection Casting performance and `as!` + +For `as?` casts, the casting behavior above requires that every element be converted separately. +This can be a particular bottleneck when trying to share large containers between Swift and Objective-C code. + +However, for `as!` casts, it is the programmer's responsibility to guarantee that the operation will succeed before requesting the conversion. +The implementation is allowed (but not required) to exploit this by deferring the inner component casts until the relevant item is needed. +Such lazy conversion can provide a significant performance improvement in cases where the data is known (by the programmer) to be safe and where the inner component casts are non-trivial. +However, if the conversion cannot be completed, it is indeterminate whether the cast request will fail immediately or whether the program will fail at some later point. + +### Tuples + +Casting from a tuple type T1 to a tuple type T2 will succeed iff the following hold: +* T1 and T2 have the same number of elements +* If an element has a label in both T1 and T2, the labels are identical +* Each element of T1 can be individually cast to the corresponding type of T2 + +### Functions + +Casting from a function type F1 to a function type F2 will succeed iff the following hold: +* The two types have the same number of arguments +* Corresponding arguments have identical types +* The return types are identical +* If F1 is a throwing function type, then F2 must be a throwing function type. If F1 is not throwing, then F2 may be a throwing or non-throwing function type. + +Note that it is _not_ sufficient for argument and return types to be castable; they must actually be identical. + +## Existential Types + +Conceptually, an "existential type" is an opaque wrapper that carries a type and an instance of that type. +The various existential types differ in what kinds of types they can hold (for example, `AnyObject` can only hold reference types) and in the capabilities exposed by the container (`AnyHashable` exposes equality testing and hashing). + +The key invariant for existential types `E` is the following: +* Strong existential invariant: If `t` is any instance, `U` is any type, and `t is E` then `(t as! E) as? U` produces the same result as `t as? U` + +Intuitively, this simply says that if you can put an instance `t` into an existential `E`, then you can take it back out again via casting. +For Equatable types, this implies that the results of the two operations here are equal to each other when they succeed. +It also implies that if either of these `as?` casts fails, so will the other. + +`AnyObject` and `AnyHashable` do not fully satisfy the strong invariant described above. Instead, they satisfy the following weaker version: +* Weak existential invariant: If `t` is any instance, `U` is any type, and both `t is U` and `t is E`, then `(t as! E) as? U` produces the same result as `t as? U` + +### Objective-C Interactions + +The difference between the strong and weak existential invariants comes about because casting to `AnyObject` or `AnyHashable` can trigger Objective-C bridging conversions. +The result of these conversions may support casts that the original type did not. +As a result, `(t as! E)` may be castable to `U` even if `t` alone is not directly castable. + +One example of this is Foundation's `NSNumber` type which conditionally bridges to several Swift numeric types. +As a result, when Foundation is in scope, `Int(7) is Double == false` but `(Int(7) as! AnyObject) is Double == true`. +In general, the ability to add new bridging behaviors from a single type to several distinct types implies that Swift casting cannot be transitive. + +### Any + +Any Swift instance can be cast to the type `Any`. +An instance of `Any` has no useful methods or properties; to utilize the contents, you must cast it to another type. +Every type identifier is an instance of the metatype `Any.Type`. + +Invariants +* If `t` is any instance, then `t is Any == true` +* If `t` is any instance, `t as! Any` always succeeds +* For every type `T` (including protocol types), `T.self is Any.Type` +* Strong existential invariant: If `t` is any instance and `U` is any type, then `(t as! Any) as? U` produces the same result as `t as? U`. + +### AnyObject + +Any class, enum, struct, tuple, function, metatype, or existential metatype instance can be cast to `AnyObject`. + +XXX TODO The runtime logic has code to cast protocol types to `AnyObject` only if they are compatible with `__SwiftValue`. What is the practical effect of this logic? Does it mean that casting a protocol type to `AnyObject` will sometimes unwrap (if the protocol is incompatible) and sometimes not? What protocols are affected by this? + +The contents of an `AnyObject` container can be accessed by casting to another type: +* Weak existential invariant: If `t` is any instance, `U` is any type, `t is AnyObject`, and `t is U`, then `(t as! AnyObject) as? U` will produce the same result as `t as? U` + +Implementation Note: `AnyObject` is represented in memory as a pointer to a refcounted object. The dynamic type of the object can be recovered from the "isa" field of the object. The optional form `AnyObject?` is the same except that it allows null. Reference types (class, metatype, or existential metatype instances) can be directly assigned to an `AnyObject` without any conversion. For non-reference types -- including struct, enum, and tuple types -- the casting logic will first look for an `_ObjectiveCBridgeable` conformance that it can use to convert the source into a tailored reference type. If that fails, the value will be copied into an opaque `_SwiftValue` container. + +(See "The _ObjectiveCBridgeable Protocol" below for more details.) + +### Error (SE-0112) + +The `Error` type behaves like an ordinary existential type for casting purposes. + +(See "Note: 'Self-conforming' protocols" below for additional details relevant to the `Error` protocol.) + +### AnyHashable (SE-0131) + +For casting purposes, `AnyHashable` behaves like an existential type. +It satisfies the weak existential invariant above. + +However, note that `AnyHashable` does not act like an existential for other purposes. +For example, it's metatype is named `AnyHashable.Type` and it does not have an existential metatype. + +### Protocol Witness types + +Any protocol definition (except those that include an `associatedtype` property or which makes use of the `Self` typealias) has an associated existential type named after the protocol. + +Specifically, assume you have a protocol definition +``` +protocol P {} +``` + +As a result of this definition, there is an existential type (also called `P`). +This existential type is also known as a "protocol witness type" since it exposes exactly the capabilities that are defined by the protocol. +Other capabilities of the type `T` are not accessible from a `P` instance. +Any Swift instance of a concrete type `T` can be cast to the type `P` iff `T` conforms to the protocol `P`. + +The contents of a protocol witness can be accessed by casting to some other appropriate type: +* Strong existential Invariant: For any protocol `P`, instance `t`, and type `U`, if `t is P`, then `t as? U` produces the same result as `(t as! P) as? U` + +In addition to the protocol witness type `P`, every Swift protocol `P` implicitly defines two other types: +`P.Protocol` is the "protocol metatype", the type of `P.self`. +`P.Type` is the "protocol existential metatype". +These are described in more detail below. + +Regarding Protocol casts and Optionals + +When casting an Optional to a protocol type, the optional is preserved if possible. +Given an instance `o` of type `Optional` and a protocol `P`, the cast request `o as? P` will produce different results depending on whether `Optional` directly conforms to `P`: + +* If `Optional` conforms to `P`, then the result will be a protocol witness wrapping the `o` instance. In this case, a subsequent cast to `Optional` will restore the original instance. In particular, this case will preserve `nil` instances. + +* If `Optional` does not directly conform, then `o` will be unwrapped and the cast will be attempted with the contained object. If `o == nil`, this will fail. In the case of a nested optional `T???` this will result in fully unwrapping the inner non-optional. + +* If all of the above fail, then the cast will fail. + +For example, `Optional` conforms to `CustomDebugStringConvertible` but not to `CustomStringConvertible`. +Casting an optional instance to the first of these protocols will result in an item whose `.debugDescription` will describe the optional instance. +Casting an optional instance to the second will provide an instance whose `.description` property describes the inner non-Optional instance. + +## Metatypes + +Swift supports two kinds of metatypes: +In addition to the regular metatypes supported by many other languages, it also has _existential_ metatypes that can be used to access static protocol requirements. + +### Metatypes + +For every type `T`, there is a unique instance `T.self` that represents the type at runtime. +As with all instances, `T.self` has a type. +We call this type the "metatype of `T`". +Technically, static variables or methods of a type belong to the `T.self` instance and are defined by the metatype of `T`: + +Example: +``` +struct S { + let ivar = 2 + static let svar = 1 +} +S.ivar // Error: only available on an instance +S().ivar // 2 +type(of: S()) == S.self +S.self.svar // 1 +S.svar // Shorthand for S.self.svar +``` + +For most Swift types, the metatype of `T` is named `T.Type`. +However, in the following cases the metatype has a different name: +* For a nominal protocol type `P`, the metatype is named `P.Protocol` +* For non-protocol existential types `E`, the metatype is also named `E.Protocol`. For example, `Any.Protocol`, `AnyObject.Protocol`, and `Error.Protocol`. +* For a type bound to a generic variable `G`, the metatype is named `G.Type` _even if `G` is bound to a protocol or existential type_. Specifically, if `G` is bound to the nominal protocol type `P`, then `G.Type` is another name for the metatype `P.Protocol`, and hence `G.Type.self == P.Protocol.self`. +* As explained above, although `AnyHashable` behaves like an existential type in some respects, its metatype is called `AnyHashable.Type`. + +Example: +``` +// Metatype of a struct type +struct S: P {} +S.self is S.Type // always true +S.Type.self is S.Type.Type // always true +let s = S() +type(of: s) == S.self // always true +type(of: S.self) == S.Type.self + +// Metatype of a protocol (or other existential) type +protocol P {} +P.self is P.Protocol // always true +// P.Protocol is a metatype, not a protocol, so: +P.Protocol.self is P.Protocol.Type // always true +let p = s as! P +type(of: p) == P.self // always true + +// Metatype for a type bound to a generic type variable +f(s) // Bind G to S +f(p) // Bind G to P +func f(_ g: G) { + G.self is G.Type // always true +} +``` + +Invariants +* For a nominal non-protocol type `T`, `T.self is T.Type` +* For a nominal protocol type `P`, `P.self is P.Protocol` +* `P.Protocol` is a singleton: `T.self is P.Protocol` iff `T` is exactly `P` +* A non-protocol type `T` conforms to a protocol `P` iff `T.self is P.Type` (If `T` is a protocol type, see "Self conforming existential types" below for details.) +* `T` is a subtype of a non-protocol type `U` iff `T.self is U.Type` +* Subtypes define metatype subtypes: if `T` and `U` are non-protocol types, `T.self is U.Type == T.Type.self is U.Type.Type` +* Subtypes define metatype subtypes: if `T` is a non-protocol type and `P` is a protocol type, `T.self is P.Protocol == T.Type.self is P.Protocol.Type` + +### Existential Metatypes + +Protocols can specify constraints and provide default implementations for instances of types. +They can also specify constraints and provide default implementations for static members of types. +As described above, casting a regular instance of a type to a protocol type produces a protocol witness instance that exposes only those features required or provided by the protocol. +Similarly, a type identifier instance (`T.self`) can be cast to a protocol's "existential metatype" to expose just the parts of the type corresponding to the protocol's static requirements. + +The existential metatype of a protocol `P` is called `P.Type`. +(Recall that for a non-protocol type `T`, the expression `T.Type` refers to the regular metatype. +Non-protocol types do not have existential metatypes. +For a generic variable `G`, the expression also refers to the regular metatype, even if the generic variable is bound to a protocol. +There is no mechanism in Swift to refer to the existential metatype via a generic variable.) + +Example +``` +protocol P { + var ivar: Int { get } + static svar: Int { get } +} +struct S: P { + let ivar = 1 + static let svar = 2 +} +S().ivar // 1 +S.self.svar // 2 +(S() as! P).ivar // 1 +(S.self as! P.Type).svar // 2 +``` + +Invariants +* If `T` conforms to `P` and `t` is an instance of `T`, then `t is P` and `T.self is P.Type` +* If `P` is a sub-protocol of `P1` and `T` is any type, then `T.self is P.Type` implies that `T.self is P1.Type` +* Since every type `T` conforms to `Any`, `T.self is Any.Type` is always true +* Since every class type `C` conforms to `AnyObject`, `C.self is AnyObject.Type` is always true (this includes Objective-C class types) + +### Note: "Self conforming" existential types + +As mentioned above, a protocol definition for `P` implicitly defines types `P.Type` (the existential metatype) and `P.Protocol` (the metatype). +It also defines an associated type called `P` which is the type of a container that can hold any object whose concrete type conforms to the protocol `P`. + +A protocol is "self conforming" if the container type `P` conforms to the protocol `P`. +This is equivalent to saying that `P.self` is an instance of `P.Type`. +(Remember that `P.self` is always an instance of `P.Protocol`.) + +This is a concern for Swift because of the following construct, which attempts to invoke a generic `f` in a situation where the concrete instance clearly conforms to `P` but is represented as a `P` existential: +``` +func f(t: T) { .. use t .. } +let a : P = something +f(a) +``` +This construct is valid only if `T` conforms to `P` when `T = P`; that is, if `P` self-conforms. + +A similar situation arises with generic types: +``` +struct MyGenericType { + init(_ value: T) { ... } +} +let a : P +let b : MyGenericType(a) +``` +As above, since `a` has type `P`, this code is instantiating `MyGenericType` with `T = P`, which is only valid if `P` conforms to `P`. +Note that any protocol that specifies static methods, static properties, associated types, or initializers cannot possibly be self-conforming. + +Although the discussion above specifically talks about protocols, it applies equally well to other existential types. +As of Swift 5.3, the only self-conforming existential types are `Any`, `Error`, and Objective-C protocols that have no static requirements. + +Invariants +* `Any` self-conforms: `Any.self is Any.Type == true` +* `Error` self-conforms: `Error.self is Error.Type == true` +* If `P` self-conforms and is a sub-protocol of `P1`, then `P.self is P1.Type == true` + +For example, the last invariant here implies that for any Objective-C protocol `OP` that has no static requirements, `OP.self is AnyObject.Type`. This follows from the fact that `OP` self-conforms and that every Objective-C protocol has `AnyObject` as an implicit parent protocol. + +## Implementation Notes + +Casting operators that appear in source code are translated into SIL in a variety of ways depending on the details of the types involved. +One common path renders `as!` into some variant of the `unconditional_checked_cast` instruction and renders `as?` and `is` into a conditional branch instruction such as `checked_cast_br`. + +SIL optimization passes attempt to simplify these. +In some cases, the result of the cast can be fully determined at compile time. +In a few cases, the compiler can generate tailored code to perform the cast (for example, assigning a reference to an `AnyObject` variable). +In other cases, the compiler can determine whether the cast will succeed without necessarily being able to compute the result. +For example, casting a class reference to a superclass will always succeed, which may allow a `checked_cast_br` instruction to be simplified into a non-branching `unconditional_checked_cast`. +Similarly, an `as?` cast that can be statically proven to always fail can be simplified into a constant `nil` value. +Note that these SIL functions are also used for other purposes, including implicit bridging conversions when calling into Objective-C. +This makes them common enough to be subject to some limited optimizations even in `-Onone` mode. + +When SIL is translated into LLVM IR, the remaining cast operations are rendered into calls to appropriate runtime functions. +The most general such function is `swift_dynamicCast` which accepts a pointer to the input value, a location in which to store the result, and metadata describing the types involved. +When possible, the compiler prefers to instead emit calls to specialized variants of this function with names like `swift_dynamicCastClass` and `swift_dynamicCastMetatypeToObject` (a full list is in the [Runtime Documentation](/docs/Runtime.md)). +These specialized versions require fewer arguments and perform fewer internal checks, which makes them cheaper to use. + +The `swift_dynamicCast` function examines the input and output types to determine appropriate conversions. +This process recurses on the input type to examine the contents of an existential container or `Optional`. +If the output is an existential container or `Optional` type, it will also recurse on the output type to determine a suitable base conversion and then must configure the container appropriately for the contents. +It may also perform additional metadata lookups to determine whether either type conforms to `Hashable`, `Error`, or `ObjectiveCBridgeable` protocols. +For collections, this process may end up recursively attempting to convert each element. + +## Compared to Swift 5.3 + +These are some of the ways in which Swift 5.3 differs from the behavior described above: + +* Casts for which the target type is "more Optional" than the static source type previously produced errors. This disallowed all of the following: injecting an `Int` into an `Int?`, extracting an `Int?` from an opaque `Any` container, and casting an `Array` to an `Array`. This document allows all of these. + +``` +let a = 7 +// Swift 5.3: error: cannot downcast to a more optional type +// Specification: returns true +a is Int? +// Swift 5.3: error: cannot downcast to a more optional type +// Specification: returns false +a is Optional + +let b: Int? = 7 +let c: Any = b +// Swift 5.3: error: cannot downcast to a more optional type +// Specification: returns true +c is Int? +``` + +* An instance of a CoreFoundation type could sometimes be cast to a protocol defined on the companion Obj-C type and sometimes not. To make the behavior consistent, we had to choose one; having such casts always succeed seems more consistent with the general dual nature of Obj-C/CF types. + +``` +import Foundation +protocol P {} +extension NSString: P {} +let a = CFStringCreateWithCString(nil, "hello, world", + CFStringBuiltInEncodings.UTF8.rawValue) +// Swift 5.3: prints "true" +print(a is P) +let b: Any = a +// Swift 5.3: prints "false" +// Specification: prints "true" +print(b is P) +``` + +* The Swift 5.3 compiler asserts attempting to cast a struct to AnyObject + +``` +struct S {} +let s = S() +// Swift 5.3: Compiler crash (in asserts build) +// Specification: Succeeds via _SwiftValue boxing +s as? AnyObject +``` + +* `NSNumber()` does not cast to itself via `as?` in unoptimized builds + +``` +import Foundation +let a = NSNumber() +// true in 5.3 for optimized builds; false for unoptimized builds +print((a as? NSNumber) != nil) +``` + +* `Optional` does not project + +``` +import Foundation +let a: Optional = NSNumber() +// Swift 5.3: false +// Specification: true +print(a is NSNumber) +// Swift 5.3: nil +// Specification: .some(NSNumber()) +print(a as? NSNumber) +``` + +* Casting `NSNumber()` to `Any` crashes at runtime + +``` +import Foundation +let a = NSNumber() +// Swift 5.3: Runtime crash (both optimized and unoptimized builds) +// Specification: Succeeds +print(a is Any) +``` + +* SR-2289: CF types cannot be cast to protocol existentials + +``` +import Foundation +protocol P {} +extension CFBitVector : P { + static func makeImmutable(from values: Array) -> CFBitVector { + return CFBitVectorCreate(nil, values, values.count * 8) + } +} +// Swift 5.3: Crashes in unoptimized build, prints true in optimized build +// Specification: prints true +print(CFBitVector.makeImmutable(from: [10,20]) is P) +``` + +* SR-4552: Cannot cast `Optional as Any` to protocol type. Note that this is a particular problem for reflection with weak fields, since `Mirror` reflects those as `Any` containing an `Optional` value. + +``` +protocol P {} +class C: P {} +let c: C? = C() +let a = c as? Any +// Swift 5.3: prints "false" +// Specification: prints "true" +print(a is P) +``` + +* SR-8964: `Any` containing `Optional` cannot cast to `Error` + +``` +struct MyError: Error { } +let a: Any? = MyError() +let b: Any = a +// Swift 5.3: Prints false +// Specification: prints true +print(b is Error) +``` + +* SR-6126: Inconsistent results for nested optionals + +``` +// Note: SR-6126 includes many cases similar to the following +let x: Int? = nil +print(x as Int??) // ==> "Optional(nil)" +// Swift 5.3: prints "nil" +// Specification: should print "Optional(nil)" (same as above) +print((x as? Int??)!) +``` + +* `Error.self` does not fully self-conform + +``` +// Swift 5.3: Prints "false" +// Specification: prints "true" +print(Error.self is Error.Type) +``` + +* Objective-C protocol metatypes do not fully self-conform + +``` +import Foundation +let a = NSObjectProtocol.self +print(a is NSObjectProtocol.Type) +``` + +* SR-1999: Cannot cast `Any` contents to a protocol type + +``` +protocol P {} +class Foo: P {} +let optionalFoo: Foo? = Foo() +let any: Any = optionalFoo +// Swift 5.3: Prints "false" +// Specification: prints "true" +print(any as? P) +``` + +* XXX TODO List others diff --git a/docs/Lexicon.md b/docs/Lexicon.md index 32e2d4acd8dfa..bc8ed1e9465d8 100644 --- a/docs/Lexicon.md +++ b/docs/Lexicon.md @@ -111,6 +111,11 @@ the AST level. See also [witness table](#witness-table). context. This type may contain [archetypes](#archetype) and cannot be used directly from outside the context. Compare with [interface type](#interface-type). +## critical edge + +An edge in a control flow graph where the destination has multiple predecessors +and the source has multiple successors. + ## customization point Informal term for a protocol requirement that has a default implementation, diff --git a/docs/LibraryEvolution.rst b/docs/LibraryEvolution.rst index e2813f4567fce..dac3495fe893a 100644 --- a/docs/LibraryEvolution.rst +++ b/docs/LibraryEvolution.rst @@ -578,7 +578,9 @@ There are very few safe changes to make to protocols and their members: - The ``@discardableResult`` and ``@warn_unqualified_access`` attributes may be added to or removed from a function requirement. - A new ``associatedtype`` requirement may be added (with the appropriate - availability), as long as it has a default implementation. + availability), as long as it has a default implementation. If the protocol + did not have one or more ``associatedtype`` requirements before the change, + then this is a `binary-compatible source-breaking change`. - A new non-type requirement may be added (with the appropriate availability), as long as it has an unconstrained default implementation. If the requirement uses ``Self`` and the protocol has no other requirements using ``Self`` and diff --git a/docs/Modules.rst b/docs/Modules.rst index fbea23d6c8b4b..fbaa3864313c5 100644 --- a/docs/Modules.rst +++ b/docs/Modules.rst @@ -441,10 +441,6 @@ Glossary __ https://en.wikipedia.org/wiki/Name_mangling#C.2B.2B - module - An entity containing the API for a library, to be `imported ` into - a source file. - qualified name A multi-piece name like ``Foundation.NSWindow``, which names an entity within a particular context. This document is concerned with the case where @@ -463,9 +459,3 @@ Glossary SIL "Swift Intermediate Language", a stable IR for the distribution of inlineable code. - - - target - A dynamic library, framework, plug-in, or application to be built. - A natural LTO boundary, and roughly the same as what Xcode requires - separate targets to build. diff --git a/docs/README.md b/docs/README.md index b3e2c3f976d4d..d5b028f34b736 100644 --- a/docs/README.md +++ b/docs/README.md @@ -159,6 +159,8 @@ documentation, please create a thread on the Swift forums under the Documents the Swift Intermediate Language (SIL). - [TransparentAttr.md](/docs/TransparentAttr.md): Documents the semantics of the `@_transparent` attribute. +- [DynamicCasting.md](/docs/DynamicCasting.md): + Behavior of the dynamic casting operators `is`, `as?`, and `as!`. - [Runtime.md](/docs/Runtime.md): Describes the ABI interface to the Swift runtime. diff --git a/docs/WebAssembly.md b/docs/WebAssembly.md new file mode 100644 index 0000000000000..b8b730f813342 --- /dev/null +++ b/docs/WebAssembly.md @@ -0,0 +1,29 @@ +# WebAssembly support in Swift + +WebAssembly is a platform that significantly differs from hardware platforms that Swift already supports. +While it's a virtual machine, there are considerations to be taken into account when targeting it: + +* WebAssembly is still at an early stage, so many features you'd be expect from other platforms are not +available yet, specifically: + 1. `wasm64` variant is not specified yet, only the 32-bit `wasm32` variant is supported in WebAssembly + hosts such as browsers. + 2. While a preview of multi-threading and atomics is available in some browsers and stand-alone + WebAssembly hosts, [the corresponding proposal](https://github.com/WebAssembly/threads/) haven't + formally reached the implementation phase yet. + 3. Dynamic linking is not formally specified and tooling for it is not available yet. +* Binary size is a high priority requirement. Since WebAssembly payloads are usually served in browsers, +one wouldn't want end users to download multi-megabyte binaries. + +Nevertheless, an early implementation of the WebAssembly target is available [in a separate +fork](https://github.com/SwiftWasm). Here we're describing some decisions that were made while developing +the implementation. + +## Relative Pointers + +Relative pointers are used in Swift runtime, but currently it's not feasible to use them for the WebAssembly +target due to the design of WebAssembly and lack of LLVM support. If LLVM supported subtraction relocation +type on WebAssembly like `R_X86_64_PC32` or `X86_64_RELOC_SUBTRACTOR`, this issue can be solved easily. + +Since `R_X86_64_PC32` and `X86_64_RELOC_SUBTRACTOR` are mainly used to generate PIC but WebAssembly doesn't +require PIC because it doesn't support dynamic linking. In addition, the memory space also begins at 0, so +it's unnecessary to relocate at load time. All absolute addresses can be embedded in wasm binary file directly. diff --git a/docs/WindowsBuild.md b/docs/WindowsBuild.md index 4260e19a78172..b66f30f0516cc 100644 --- a/docs/WindowsBuild.md +++ b/docs/WindowsBuild.md @@ -8,11 +8,10 @@ The commands below (with the exception of installing Visual Studio) must be ente ### Visual Studio -An easy way to get most of the tools to build Swift is using the [Visual Studio installer](https://www.visualstudio.com/downloads/). This command installs all needed Visual Studio components as well as Python and Git: +An easy way to get most of the tools to build Swift is using the [Visual Studio installer](https://www.visualstudio.com/downloads/). This command installs all needed Visual Studio components as well as Python, Git, CMake and Ninja: ``` vs_community ^ - --add Component.CPython2.x86 ^ --add Component.CPython3.x64 ^ --add Microsoft.VisualStudio.Component.Git ^ --add Microsoft.VisualStudio.Component.VC.ATL ^ @@ -28,13 +27,7 @@ The following [link](https://docs.microsoft.com/visualstudio/install/workload-co ### Python -The command above already installs Python 2 and 3. Alternatively, in the Visual Studio installation program, under *Individual Components* - -1. Install *Python 2*, either the 32-bit version (C:\Python27\\) or the 64-bit version (C:\Python27amd64\\) - - **Note:** If you install the 64-bit version only, you will need to adjust `PYTHON_EXECUTABLE` below to `C:\Python27amd64\python.exe` - -2. Install *Python 3 64 bits (3.7.x)* +The command above already installs Python 3. Alternatively, in the Visual Studio installation program, under *Individual Components*, install *Python 3 64 bits (3.7.x)*. If you are building a debug version of Swift, you should also install the Python debug binaries. @@ -69,9 +62,13 @@ git clone https://github.com/apple/swift-cmark cmark git clone https://github.com/apple/swift-corelibs-libdispatch swift-corelibs-libdispatch git clone https://github.com/apple/swift-corelibs-foundation swift-corelibs-foundation git clone https://github.com/apple/swift-corelibs-xctest swift-corelibs-xctest -git clone https://github.com/apple/swift-llbuild llbuild git clone https://github.com/apple/swift-tools-support-core swift-tools-support-core -git clone -c core.autocrlf=input https://github.com/apple/swift-package-manager swiftpm +git clone -c core.symlinks=true https://github.com/apple/swift-llbuild swift-llbuild +git clone https://github.com/JPSim/Yams Yams +git clone https://github.com/apple/swift-driver swift-driver +git clone https://github.com/apple/swift-argument-parser swift-argument-parser +git clone -c core.autocrlf=input https://github.com/apple/swift-package-manager swift-package-manager +git clone https://github.com/apple/indexstore-db indexstore-db ``` ## Dependencies (ICU, SQLite3, curl, libxml2 and zlib) @@ -119,119 +116,266 @@ Warning: Creating the above links usually requires administrator privileges. The ## Build the toolchain ```cmd -cmake -B "S:\b\toolchain" ^ +cmake -B "S:\b\1" ^ -C S:\swift\cmake\caches\Windows-x86_64.cmake ^ -D CMAKE_BUILD_TYPE=Release ^ - -D SWIFT_PATH_TO_LIBDISPATCH_SOURCE=S:\swift-corelibs-libdispatch ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D LLVM_DEFAULT_TARGET_TRIPLE=x86_64-unknown-windows-msvc ^ -D LLVM_ENABLE_PDB=YES ^ - -D LLVM_EXTERNAL_SWIFT_SOURCE_DIR=S:\swift ^ -D LLVM_EXTERNAL_CMARK_SOURCE_DIR=S:\cmark ^ - -D SWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE=S:\Library\icu-67\usr\include ^ - -D SWIFT_WINDOWS_x86_64_ICU_UC=S:\Library\icu-67\usr\lib\icuuc67.lib ^ + -D LLVM_EXTERNAL_SWIFT_SOURCE_DIR=S:\swift ^ + -D SWIFT_PATH_TO_LIBDISPATCH_SOURCE=S:\swift-corelibs-libdispatch ^ -D SWIFT_WINDOWS_x86_64_ICU_I18N_INCLUDE=S:\Library\icu-67\usr\include ^ -D SWIFT_WINDOWS_x86_64_ICU_I18N=S:\Library\icu-67\usr\lib\icuin67.lib ^ - -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D SWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE=S:\Library\icu-67\usr\include ^ + -D SWIFT_WINDOWS_x86_64_ICU_UC=S:\Library\icu-67\usr\lib\icuuc67.lib ^ -G Ninja ^ -S S:\llvm-project\llvm -ninja -C S:\b\toolchain +ninja -C S:\b\1 ``` -**Note:** If you installed only the 64-bit version of Python, you will need to adjust `PYTHON_EXECUTABLE` argument to `C:\Python27amd64\python.exe` - - ## Running Swift tests on Windows ```cmd -path S:\Library\icu-67\usr\bin;S:\b\toolchain\bin;S:\b\toolchain\tools\swift\libdispatch-prefix\bin;%PATH%;%ProgramFiles%\Git\usr\bin +path S:\Library\icu-67\usr\bin;S:\b\1\bin;S:\b\1\tools\swift\libdispatch-prefix\bin;%PATH%;%ProgramFiles%\Git\usr\bin ninja -C S:\b\toolchain check-swift ``` ## Build swift-corelibs-libdispatch ```cmd -cmake -B S:\b\libdispatch -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_C_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_CXX_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D ENABLE_SWIFT=YES -G Ninja -S S:\swift-corelibs-libdispatch -ninja -C S:\b\libdispatch +cmake -B S:\b\2 ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_C_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_CXX_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D ENABLE_SWIFT=YES ^ + -G Ninja ^ + -S S:\swift-corelibs-libdispatch + +ninja -C S:\b\2 ``` ## Test swift-corelibs-libdispatch ```cmd -ninja -C S:\b\libdispatch check +ninja -C S:\b\2 check ``` ## Build swift-corelibs-foundation ```cmd -cmake -B S:\b\foundation -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_C_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D CURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib" -D CURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include" -D ICU_ROOT="S:/Library/icu-67" -D ICU_INCLUDE_DIR=S:/Library/icu-67/usr/include -D LIBXML2_LIBRARY="S:/Library/libxml2-development/usr/lib/libxml2s.lib" -D LIBXML2_INCLUDE_DIR="S:/Library/libxml2-development/usr/include/libxml2" -D ENABLE_TESTING=NO -D dispatch_DIR=S:/b/libdispatch/cmake/modules -G Ninja -S S:\swift-corelibs-foundation -ninja -C S:\b\foundation +cmake -B S:\b\3 ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_C_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D CURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib" ^ + -D CURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include" ^ + -D ICU_I18N_LIBRARY_RELEASE=S:\library\icu-67\usr\lib\icuin67.lib ^ + -D ICU_ROOT=S:\Library\icu-67\usr ^ + -D ICU_UC_LIBRARY_RELEASE=S:\Library\icu-67\usr\lib\icuuc67.lib ^ + -D LIBXML2_LIBRARY=S:\Library\libxml2-development\usr\lib\libxml2s.lib ^ + -D LIBXML2_INCLUDE_DIR=S:\Library\libxml2-development\usr\include\libxml2 ^ + -D ENABLE_TESTING=NO ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -G Ninja ^ + -S S:\swift-corelibs-foundation + +ninja -C S:\b\3 ``` - Add Foundation to your path: ```cmd -path S:\b\foundation\Foundation;%PATH% +path S:\b\3\bin;%PATH% ``` ## Build swift-corelibs-xctest ```cmd -cmake -B S:\b\xctest -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D dispatch_DIR=S:\b\dispatch\cmake\modules -D Foundation_DIR=S:\b\foundation\cmake\modules -D LIT_COMMAND=S:\toolchain\llvm\utils\lit\lit.py -D PYTHON_EXECUTABLE=C:\Python27\python.exe -G Ninja -S S:\swift-corelibs-xctest -ninja -C S:\b\xctest +cmake -B S:\b\4 ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D LIT_COMMAND=S:\llvm-project\llvm\utils\lit\lit.py ^ + -G Ninja ^ + -S S:\swift-corelibs-xctest + +ninja -C S:\b\4 ``` - Add XCTest to your path: ```cmd -path S:\b\xctest;%PATH% + +path S:\b\4;%PATH% ``` ## Test XCTest ```cmd -ninja -C S:\b\xctest check-xctest +ninja -C S:\b\4 check-xctest ``` ## Rebuild Foundation ```cmd -cmake -B S:\b\foundation -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_C_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D CURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib" -D CURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include" -D ICU_ROOT="S:/Library/icu-67" -D LIBXML2_LIBRARY="S:/Library/libxml2-development/usr/lib/libxml2.lib" -D LIBXML2_INCLUDE_DIR="S:/Library/libxml2-development/usr/include" -D ENABLE_TESTING=YES -D dispatch_DIR=S:/b/libdispatch/cmake/modules -D XCTest_DIR=S:/b/xctest/cmake/modules -G Ninja -S S:\swift-corelibs-foundation -ninja -C S:\b\foundation +cmake -B S:\b\3 ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_C_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D CURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib" ^ + -D CURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include" ^ + -D ICU_I18N_LIBRARY_RELEASE=S:\library\icu-67\usr\lib\icuin67.lib ^ + -D ICU_ROOT=S:\Library\icu-67\usr ^ + -D ICU_UC_LIBRARY_RELEASE=S:\Library\icu-67\usr\lib\icuuc67.lib ^ + -D LIBXML2_LIBRARY=S:\Library\libxml2-development\usr\lib\libxml2s.lib ^ + -D LIBXML2_INCLUDE_DIR=S:\Library\libxml2-development\usr\include\libxml2 ^ + -D ENABLE_TESTING=YES ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D XCTest_DIR=S:\b\4\cmake\modules ^ + -G Ninja ^ + -S S:\swift-corelibs-foundation + +ninja -C S:\b\3 ``` ## Test Foundation ```cmd -cmake --build S:\b\foundation -ninja -C S:\b\foundation test +ninja -C S:\b\3 test ``` -## Build llbuild +## Build swift-tools-core-support ```cmd -set AR=llvm-ar -cmake -B S:\b\llbuild -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_CXX_COMPILER=cl -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D Foundation_DIR=S:/b/foundation/cmake/modules -D dispatch_DIR=S:/b/libdispatch/cmake/modules -D SQLite3_INCLUDE_DIR=S:\Library\sqlite-3.28.0\usr\include -D SQLite3_LIBRARY=S:\Library\sqlite-3.28.0\usr\lib\sqlite3.lib -D LLBUILD_SUPPORT_BINDINGS=Swift -G Ninja -S S:\llbuild -ninja -C S:\b\llbuild +cmake -B S:\b\5 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_C_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D SQLite3_INCLUDE_DIR=S:\Library\sqlite-3.28.0\usr\include ^ + -D SQLite3_LIBRARY=S:\Library\sqlite-3.28.0\usr\lib\SQLite3.lib ^ + -G Ninja ^ + -S S:\swift-tools-support-core + +ninja -C S:\b\5 +``` + +## Build swift-llbuild + +```cmd +cmake -B S:\b\6 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_CXX_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D CMAKE_CXX_FLAGS="-Xclang -fno-split-cold-code" ^ + -D LLBUILD_SUPPORT_BINDINGS=Swift ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D SQLite3_INCLUDE_DIR=S:\Library\sqlite-3.28.0\usr\include ^ + -D SQLite3_LIBRARY=S:\Library\sqlite-3.28.0\usr\lib\sqlite3.lib ^ + -G Ninja ^ + -S S:\swift-llbuild + +ninja -C S:\b\6 ``` - Add llbuild to your path: ```cmd -path S:\b\llbuild\bin;%PATH% +path S:\b\6\bin;%PATH% ``` -## Build swift-tools-core-support +## Build Yams ```cmd -cmake -B S:\b\tsc -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_C_COMPILER=cl -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D Foundation_DIR=S:/b/foundation/cmake/modules -D dispatch_DIR=S:/b/libdispatch/cmake/modules -G Ninja -S S:\swift-tools-support-core -ninja -C S:\b\tsc +cmake -B S:\b\7 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=Release ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D XCTest_DIR=S:\b\4\cmake\modules ^ + -G Ninja ^ + -S S:\swift-llbuild + +ninja -C S:\b\7 +``` + +## Build swift-driver + +```cmd +cmake -B S:\b\8 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=Release ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D TSC_DIR=S:\b\5\cmake\modules ^ + -D LLBuild_DIR=S:\b\6\cmake\modules ^ + -D Yams_DIR=S:\b\7\cmake\modules ^ + -G Ninja ^ + -S S:\swift-driver + +ninja -C S:\b\8 +``` + +## Build swift-argument-parser + +```cmd +cmake -B S:\b\9 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=Release ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D XCTest_DIR=S:\b\4\cmake\modules ^ + -G Ninja ^ + -S S:\swift-argument-parser + +ninja -C S:\b\9 ``` ## Build swift-package-manager ```cmd -cmake -B S:\b\spm -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_C_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_CXX_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D USE_VENDORED_TSC=YES -D Foundation_DIR=S:/b/foundation/cmake/modules -D dispatch_DIR=S:/b/libdispatch/cmake/modules -D LLBuild_DIR=S:/b/llbuild/cmake/modules -G Ninja -S S:\swiftpm -ninja -C S:\b\spm +cmake -B S:\b\10 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=Release ^ + -D CMAKE_C_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D TSC_DIR=S:\b\5\cmake\modules ^ + -D LLBuild_DIR=S:\b\6\cmake\modules ^ + -D Yams_DIR=S:\b\7\cmake\modules ^ + -D SwiftDriver_DIR=S:\b\8\cmake\modules ^ + -D ArgumentParser_DIR=S:\b\9\cmake\modules ^ + -G Ninja ^ + -S S:\swift-package-manager + +ninja -C S:\b\10 +``` + +Indicate to swift-package-manager where to find the Package Description before installation: +```cmd +set SWIFTPM_PD_LIBS=S:\b\10\pm ``` ## Install the Swift toolchain on Windows diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 2f6d07561224b..0ac4ab8943c42 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -3772,6 +3772,21 @@ struct TargetSingletonMetadataInitialization { const TargetTypeContextDescriptor *description) const; }; +template +struct TargetCanonicalSpecializedMetadatasListCount { + uint32_t count; +}; + +template +struct TargetCanonicalSpecializedMetadatasListEntry { + TargetRelativeDirectPointer, /*Nullable*/ false> metadata; +}; + +template +struct TargetCanonicalSpecializedMetadataAccessorsListEntry { + TargetRelativeDirectPointer accessor; +}; + template class TargetTypeContextDescriptor : public TargetContextDescriptor { @@ -3821,6 +3836,10 @@ class TargetTypeContextDescriptor return getTypeContextDescriptorFlags().hasForeignMetadataInitialization(); } + bool hasCanonicicalMetadataPrespecializations() const { + return getTypeContextDescriptorFlags().hasCanonicalMetadataPrespecializations(); + } + /// Given that this type has foreign metadata initialization, return the /// control structure for it. const TargetForeignMetadataInitialization & @@ -3853,6 +3872,9 @@ class TargetTypeContextDescriptor return words + offset; } + const llvm::ArrayRef, /*Nullable*/ false>> + getCanonicicalMetadataPrespecializations() const; + static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() >= ContextDescriptorKind::Type_First && cd->getKind() <= ContextDescriptorKind::Type_Last; @@ -3990,7 +4012,10 @@ class TargetClassDescriptor final TargetMethodDescriptor, TargetOverrideTableHeader, TargetMethodOverrideDescriptor, - TargetObjCResilientClassStubInfo> { + TargetObjCResilientClassStubInfo, + TargetCanonicalSpecializedMetadatasListCount, + TargetCanonicalSpecializedMetadatasListEntry, + TargetCanonicalSpecializedMetadataAccessorsListEntry> { private: using TrailingGenericContextObjects = swift::TrailingGenericContextObjects, @@ -4002,7 +4027,10 @@ class TargetClassDescriptor final TargetMethodDescriptor, TargetOverrideTableHeader, TargetMethodOverrideDescriptor, - TargetObjCResilientClassStubInfo>; + TargetObjCResilientClassStubInfo, + TargetCanonicalSpecializedMetadatasListCount, + TargetCanonicalSpecializedMetadatasListEntry, + TargetCanonicalSpecializedMetadataAccessorsListEntry>; using TrailingObjects = typename TrailingGenericContextObjects::TrailingObjects; @@ -4020,6 +4048,16 @@ class TargetClassDescriptor final TargetSingletonMetadataInitialization; using ObjCResilientClassStubInfo = TargetObjCResilientClassStubInfo; + using Metadata = + TargetRelativeDirectPointer, /*Nullable*/ false>; + using MetadataListCount = + TargetCanonicalSpecializedMetadatasListCount; + using MetadataListEntry = + TargetCanonicalSpecializedMetadatasListEntry; + using MetadataAccessor = + TargetRelativeDirectPointer; + using MetadataAccessorListEntry = + TargetCanonicalSpecializedMetadataAccessorsListEntry; using StoredPointer = typename Runtime::StoredPointer; using StoredPointerDifference = typename Runtime::StoredPointerDifference; @@ -4139,6 +4177,24 @@ class TargetClassDescriptor final return hasObjCResilientClassStub() ? 1 : 0; } + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + 1 + : 0; + } + + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + this->template getTrailingObjects()->count + : 0; + } + + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + this->template getTrailingObjects()->count + : 0; + } + public: const TargetRelativeDirectPointer & getResilientSuperclass() const { @@ -4276,6 +4332,32 @@ class TargetClassDescriptor final ->Stub.get(); } + llvm::ArrayRef getCanonicicalMetadataPrespecializations() const { + if (!this->hasCanonicicalMetadataPrespecializations()) { + return {}; + } + + auto *listCount = this->template getTrailingObjects(); + auto *list = this->template getTrailingObjects(); + return llvm::ArrayRef( + reinterpret_cast(list), + listCount->count + ); + } + + llvm::ArrayRef getCanonicalMetadataPrespecializationAccessors() const { + if (!this->hasCanonicicalMetadataPrespecializations()) { + return {}; + } + + auto *listCount = this->template getTrailingObjects(); + auto *list = this->template getTrailingObjects(); + return llvm::ArrayRef( + reinterpret_cast(list), + listCount->count + ); + } + static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Class; } @@ -4301,19 +4383,29 @@ class TargetStructDescriptor final TargetTypeGenericContextDescriptorHeader, /*additional trailing objects*/ TargetForeignMetadataInitialization, - TargetSingletonMetadataInitialization> { + TargetSingletonMetadataInitialization, + TargetCanonicalSpecializedMetadatasListCount, + TargetCanonicalSpecializedMetadatasListEntry> { public: using ForeignMetadataInitialization = TargetForeignMetadataInitialization; using SingletonMetadataInitialization = TargetSingletonMetadataInitialization; + using Metadata = + TargetRelativeDirectPointer, /*Nullable*/ false>; + using MetadataListCount = + TargetCanonicalSpecializedMetadatasListCount; + using MetadataListEntry = + TargetCanonicalSpecializedMetadatasListEntry; private: using TrailingGenericContextObjects = swift::TrailingGenericContextObjects, TargetTypeGenericContextDescriptorHeader, ForeignMetadataInitialization, - SingletonMetadataInitialization>; + SingletonMetadataInitialization, + MetadataListCount, + MetadataListEntry>; using TrailingObjects = typename TrailingGenericContextObjects::TrailingObjects; @@ -4331,6 +4423,18 @@ class TargetStructDescriptor final return this->hasSingletonMetadataInitialization() ? 1 : 0; } + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + 1 + : 0; + } + + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + this->template getTrailingObjects()->count + : 0; + } + public: using TrailingGenericContextObjects::getGenericContext; using TrailingGenericContextObjects::getGenericContextHeader; @@ -4363,6 +4467,19 @@ class TargetStructDescriptor final return TargetStructMetadata::getGenericArgumentOffset(); } + llvm::ArrayRef getCanonicicalMetadataPrespecializations() const { + if (!this->hasCanonicicalMetadataPrespecializations()) { + return {}; + } + + auto *listCount = this->template getTrailingObjects(); + auto *list = this->template getTrailingObjects(); + return llvm::ArrayRef( + reinterpret_cast(list), + listCount->count + ); + } + static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Struct; } @@ -4377,19 +4494,29 @@ class TargetEnumDescriptor final TargetTypeGenericContextDescriptorHeader, /*additional trailing objects*/ TargetForeignMetadataInitialization, - TargetSingletonMetadataInitialization> { + TargetSingletonMetadataInitialization, + TargetCanonicalSpecializedMetadatasListCount, + TargetCanonicalSpecializedMetadatasListEntry> { public: using SingletonMetadataInitialization = TargetSingletonMetadataInitialization; using ForeignMetadataInitialization = TargetForeignMetadataInitialization; + using Metadata = + TargetRelativeDirectPointer, /*Nullable*/ false>; + using MetadataListCount = + TargetCanonicalSpecializedMetadatasListCount; + using MetadataListEntry = + TargetCanonicalSpecializedMetadatasListEntry; private: using TrailingGenericContextObjects = swift::TrailingGenericContextObjects, TargetTypeGenericContextDescriptorHeader, ForeignMetadataInitialization, - SingletonMetadataInitialization>; + SingletonMetadataInitialization, + MetadataListCount, + MetadataListEntry>; using TrailingObjects = typename TrailingGenericContextObjects::TrailingObjects; @@ -4407,6 +4534,18 @@ class TargetEnumDescriptor final return this->hasSingletonMetadataInitialization() ? 1 : 0; } + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + 1 + : 0; + } + + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + this->template getTrailingObjects()->count + : 0; + } + public: using TrailingGenericContextObjects::getGenericContext; using TrailingGenericContextObjects::getGenericContextHeader; @@ -4453,6 +4592,19 @@ class TargetEnumDescriptor final return *this->template getTrailingObjects(); } + llvm::ArrayRef getCanonicicalMetadataPrespecializations() const { + if (!this->hasCanonicicalMetadataPrespecializations()) { + return {}; + } + + auto *listCount = this->template getTrailingObjects(); + auto *list = this->template getTrailingObjects(); + return llvm::ArrayRef( + reinterpret_cast(list), + listCount->count + ); + } + static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Enum; } @@ -4587,6 +4739,24 @@ TargetTypeContextDescriptor::getSingletonMetadataInitialization() const } } +template +inline const llvm::ArrayRef, /*Nullable*/ false>> +TargetTypeContextDescriptor::getCanonicicalMetadataPrespecializations() const { + switch (this->getKind()) { + case ContextDescriptorKind::Enum: + return llvm::cast>(this) + ->getCanonicicalMetadataPrespecializations(); + case ContextDescriptorKind::Struct: + return llvm::cast>(this) + ->getCanonicicalMetadataPrespecializations(); + case ContextDescriptorKind::Class: + return llvm::cast>(this) + ->getCanonicicalMetadataPrespecializations(); + default: + swift_runtime_unreachable("Not a type context descriptor."); + } +} + /// An entry in the chain of dynamic replacement functions. struct DynamicReplacementChainEntry { void *implementationFunction; diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index b5b62a7edf5f0..54232972ca9fd 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -1326,6 +1326,10 @@ class TypeContextDescriptorFlags : public FlagSet { /// Meaningful for all type-descriptor kinds. HasImportInfo = 2, + /// Set if the type descriptor has a pointer to a list of canonical + /// prespecializations. + HasCanonicalMetadataPrespecializations = 3, + // Type-specific flags: /// The kind of reference that this class makes to its resilient superclass @@ -1393,6 +1397,8 @@ class TypeContextDescriptorFlags : public FlagSet { FLAGSET_DEFINE_FLAG_ACCESSORS(HasImportInfo, hasImportInfo, setHasImportInfo) + FLAGSET_DEFINE_FLAG_ACCESSORS(HasCanonicalMetadataPrespecializations, hasCanonicalMetadataPrespecializations, setHasCanonicalMetadataPrespecializations) + FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable, class_hasVTable, class_setHasVTable) diff --git a/include/swift/ABI/ObjectFile.h b/include/swift/ABI/ObjectFile.h new file mode 100644 index 0000000000000..cd570132cdc0a --- /dev/null +++ b/include/swift/ABI/ObjectFile.h @@ -0,0 +1,99 @@ +//===--- ObjectFile.h - Object File Related Information ------*- C++ -*-===// +// +// Object File related data structures. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_ABI_OBJECTFILE_H +#define SWIFT_ABI_OBJECTFILE_H + +#include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/StringRef.h" + +namespace swift { + +/// Represents the six reflection sections used by Swift +enum ReflectionSectionKind : uint8_t { + fieldmd, + assocty, + builtin, + capture, + typeref, + reflstr +}; + +/// Abstract base class responsible for providing the correct reflection section +/// string identifier for a given object file type (Mach-O, ELF, COFF). +class SwiftObjectFileFormat { +public: + virtual ~SwiftObjectFileFormat() {} + virtual llvm::StringRef getSectionName(ReflectionSectionKind section) = 0; +}; + +/// Responsible for providing the Mach-O reflection section identifiers. +class SwiftObjectFileFormatMachO : SwiftObjectFileFormat { +public: + llvm::StringRef getSectionName(ReflectionSectionKind section) override { + switch (section) { + case fieldmd: + return "__swift5_fieldmd"; + case assocty: + return "__swift5_assocty"; + case builtin: + return "__swift5_builtin"; + case capture: + return "__swift5_capture"; + case typeref: + return "__swift5_typeref"; + case reflstr: + return "__swift5_reflstr"; + } + llvm_unreachable("Section type not found."); + } +}; + +/// Responsible for providing the ELF reflection section identifiers. +class SwiftObjectFileFormatELF : SwiftObjectFileFormat { +public: + llvm::StringRef getSectionName(ReflectionSectionKind section) override { + switch (section) { + case fieldmd: + return "swift5_fieldmd"; + case assocty: + return "swift5_assocty"; + case builtin: + return "swift5_builtin"; + case capture: + return "swift5_capture"; + case typeref: + return "swift5_typeref"; + case reflstr: + return "swift5_reflstr"; + } + llvm_unreachable("Section type not found."); + } +}; + +/// Responsible for providing the COFF reflection section identifiers +class SwiftObjectFileFormatCOFF : SwiftObjectFileFormat { +public: + llvm::StringRef getSectionName(ReflectionSectionKind section) override { + switch (section) { + case fieldmd: + return ".sw5flmd"; + case assocty: + return ".sw5asty"; + case builtin: + return ".sw5bltn"; + case capture: + return ".sw5cptr"; + case typeref: + return ".sw5tyrf"; + case reflstr: + return ".sw5rfst"; + } + llvm_unreachable("Section not found."); + } +}; +} // namespace swift +#endif // SWIFT_ABI_OBJECTFILE_H diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index e3745be52d7b2..fd020c6eb703b 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -62,6 +62,7 @@ namespace swift { class BoundGenericType; class ClangModuleLoader; class ClangNode; + class ClangTypeConverter; class ConcreteDeclRef; class ConstructorDecl; class Decl; @@ -213,7 +214,9 @@ class ASTContext final { void operator=(const ASTContext&) = delete; ASTContext(LangOptions &langOpts, TypeCheckerOptions &typeckOpts, - SearchPathOptions &SearchPathOpts, SourceManager &SourceMgr, + SearchPathOptions &SearchPathOpts, + ClangImporterOptions &ClangImporterOpts, + SourceManager &SourceMgr, DiagnosticEngine &Diags); public: @@ -227,6 +230,7 @@ class ASTContext final { static ASTContext *get(LangOptions &langOpts, TypeCheckerOptions &typeckOpts, SearchPathOptions &SearchPathOpts, + ClangImporterOptions &ClangImporterOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags); ~ASTContext(); @@ -245,6 +249,9 @@ class ASTContext final { /// The search path options used by this AST context. SearchPathOptions &SearchPathOpts; + /// The clang importer options used by this AST context. + ClangImporterOptions &ClangImporterOpts; + /// The source manager object. SourceManager &SourceMgr; @@ -586,6 +593,10 @@ class ASTContext final { Type getBridgedToObjC(const DeclContext *dc, Type type, Type *bridgedValueType = nullptr) const; +private: + ClangTypeConverter &getClangTypeConverter(); + +public: /// Get the Clang type corresponding to a Swift function type. /// /// \param params The function parameters. @@ -595,6 +606,14 @@ class ASTContext final { getClangFunctionType(ArrayRef params, Type resultTy, FunctionTypeRepresentation trueRep); + /// Get the canonical Clang type corresponding to a SIL function type. + /// + /// SIL analog of \c ASTContext::getClangFunctionType . + const clang::Type * + getCanonicalClangFunctionType( + ArrayRef params, Optional result, + SILFunctionType::Representation trueRep); + /// Get the Swift declaration that a Clang declaration was exported from, /// if applicable. const Decl *getSwiftDeclForExportedClangDecl(const clang::Decl *decl); @@ -669,6 +688,10 @@ class ASTContext final { /// compiler for the target platform. AvailabilityContext getSwift53Availability(); + /// Get the runtime availability of features introduced in the Swift 5.4 + /// compiler for the target platform. + AvailabilityContext getSwift54Availability(); + /// Get the runtime availability of features that have been introduced in the /// Swift compiler for future versions of the target platform. AvailabilityContext getSwiftFutureAvailability(); @@ -735,6 +758,12 @@ class ASTContext final { ModuleDependenciesCache &cache, InterfaceSubContextDelegate &delegate); + /// Retrieve the module dependencies for the Swift module with the given name. + Optional getSwiftModuleDependencies( + StringRef moduleName, + ModuleDependenciesCache &cache, + InterfaceSubContextDelegate &delegate); + /// Load extensions to the given nominal type from the external /// module loaders. /// diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index 50c401e7ee2bc..b244e766ffc52 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -146,7 +146,8 @@ class ASTMangler : public Mangler { std::string mangleGlobalVariableFull(const VarDecl *decl); - std::string mangleGlobalInit(const VarDecl *decl, int counter, + std::string mangleGlobalInit(const PatternBindingDecl *decl, + unsigned entry, bool isInitFunc); std::string mangleReabstractionThunkHelper(CanSILFunctionType ThunkType, diff --git a/include/swift/AST/ASTPrinter.h b/include/swift/AST/ASTPrinter.h index 3c28d725ab6bb..3273d3ec4d7f4 100644 --- a/include/swift/AST/ASTPrinter.h +++ b/include/swift/AST/ASTPrinter.h @@ -325,7 +325,7 @@ class ExtraIndentStreamPrinter : public StreamPrinter { ExtraIndentStreamPrinter(raw_ostream &out, StringRef extraIndent) : StreamPrinter(out), ExtraIndent(extraIndent) { } - virtual void printIndent() { + virtual void printIndent() override { printText(ExtraIndent); StreamPrinter::printIndent(); } diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 0cac9c8e61277..2f3588ec3f92c 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -44,11 +44,10 @@ /// try disabling it. /// \p message must be a string literal #define ASTScopeAssert(predicate, message) \ - assert((predicate) && message \ - " Try compiling with '-disable-astscope-lookup'.") + assert((predicate) && message) #define ASTScope_unreachable(message) \ - llvm_unreachable(message " Try compiling with '-disable-astscope-lookup'.") + llvm_unreachable(message) namespace swift { diff --git a/include/swift/AST/ASTTypeIDZone.def b/include/swift/AST/ASTTypeIDZone.def index bf6aeaf1e65dc..fa9dd1d3a8d3c 100644 --- a/include/swift/AST/ASTTypeIDZone.def +++ b/include/swift/AST/ASTTypeIDZone.def @@ -28,6 +28,7 @@ SWIFT_TYPEID(Requirement) SWIFT_TYPEID(ResilienceExpansion) SWIFT_TYPEID(FragileFunctionKind) SWIFT_TYPEID(TangentPropertyInfo) +SWIFT_TYPEID(SymbolSourceMap) SWIFT_TYPEID(Type) SWIFT_TYPEID(TypePair) SWIFT_TYPEID(TypeWitnessAndDecl) diff --git a/include/swift/AST/ASTTypeIDs.h b/include/swift/AST/ASTTypeIDs.h index 973f7dc2c9836..6fc964d6fa305 100644 --- a/include/swift/AST/ASTTypeIDs.h +++ b/include/swift/AST/ASTTypeIDs.h @@ -60,6 +60,7 @@ class Requirement; enum class ResilienceExpansion : unsigned; struct FragileFunctionKind; class SourceFile; +class SymbolSourceMap; struct TangentPropertyInfo; class Type; class TypeAliasDecl; diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index b6fea6459d533..2c744e4c0769a 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -53,6 +53,7 @@ TYPE_ATTR(noescape) TYPE_ATTR(escaping) TYPE_ATTR(differentiable) TYPE_ATTR(noDerivative) +TYPE_ATTR(async) // SIL-specific attributes TYPE_ATTR(block_storage) @@ -560,6 +561,11 @@ SIMPLE_DECL_ATTR(noDerivative, NoDerivative, ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove, 100) +SIMPLE_DECL_ATTR(asyncHandler, AsyncHandler, + OnFunc | UserInaccessible | + ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove, + 101) + #undef TYPE_ATTR #undef DECL_ATTR_ALIAS #undef CONTEXTUAL_DECL_ATTR_ALIAS diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 25fa621adf0bc..0c67ece50d09f 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -1427,7 +1427,7 @@ class SpecializeAttr : public DeclAttribute { TrailingWhereClause *getTrailingWhereClause() const; - GenericSignature getSpecializedSgnature() const { + GenericSignature getSpecializedSignature() const { return specializedSignature; } diff --git a/include/swift/AST/Builtins.h b/include/swift/AST/Builtins.h index 1654e7cc4cc3d..516f7dce7376a 100644 --- a/include/swift/AST/Builtins.h +++ b/include/swift/AST/Builtins.h @@ -26,7 +26,7 @@ #include "llvm/Support/ErrorHandling.h" namespace llvm { -enum class AtomicOrdering; +enum class AtomicOrdering : unsigned; } namespace swift { diff --git a/include/swift/AST/ClangModuleLoader.h b/include/swift/AST/ClangModuleLoader.h index 64bc7e7d58413..06c41a3d8e61e 100644 --- a/include/swift/AST/ClangModuleLoader.h +++ b/include/swift/AST/ClangModuleLoader.h @@ -109,7 +109,7 @@ class StableSerializationPath { class ClangModuleLoader : public ModuleLoader { private: - virtual void anchor(); + virtual void anchor() override; protected: using ModuleLoader::ModuleLoader; diff --git a/include/swift/AST/ClangNode.h b/include/swift/AST/ClangNode.h index cbf120840b661..ec8299843ac1d 100644 --- a/include/swift/AST/ClangNode.h +++ b/include/swift/AST/ClangNode.h @@ -13,6 +13,7 @@ #ifndef SWIFT_CLANGNODE_H #define SWIFT_CLANGNODE_H +#include "swift/Basic/Debug.h" #include "llvm/ADT/PointerUnion.h" namespace clang { @@ -48,8 +49,8 @@ class ClangNode { template using Box = detail::ClangNodeBox; - llvm::PointerUnion4, Box, - Box, Box> Ptr; + llvm::PointerUnion, Box, + Box, Box> Ptr; public: ClangNode() = default; @@ -98,6 +99,8 @@ class ClangNode { clang::SourceLocation getLocation() const; clang::SourceRange getSourceRange() const; + SWIFT_DEBUG_DUMP; + void *getOpaqueValue() const { return Ptr.getOpaqueValue(); } static inline ClangNode getFromOpaqueValue(void *VP) { ClangNode N; diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index e3fb02109d10b..48d31fcafcb92 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -63,6 +63,7 @@ namespace swift { class Type; class Expr; class DeclRefExpr; + class ForeignAsyncConvention; class ForeignErrorConvention; class LiteralExpr; class BraceStmt; @@ -300,7 +301,13 @@ class alignas(1 << DeclAlignInBits) Decl { /// Whether this declaration was added to the surrounding /// DeclContext of an active #if config clause. - EscapedFromIfConfig : 1 + EscapedFromIfConfig : 1, + + /// Whether this declaration is syntactically scoped inside of + /// a local context, but should behave like a top-level + /// declaration for name lookup purposes. This is used by + /// lldb. + Hoisted : 1 ); SWIFT_INLINE_BITFIELD_FULL(PatternBindingDecl, Decl, 1+2+16, @@ -385,7 +392,7 @@ class alignas(1 << DeclAlignInBits) Decl { SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2, StaticSpelling : 2 ); - SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1+1, + SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1, /// \see AbstractFunctionDecl::BodyKind BodyKind : 3, @@ -689,6 +696,7 @@ class alignas(1 << DeclAlignInBits) Decl { Bits.Decl.Implicit = false; Bits.Decl.FromClang = false; Bits.Decl.EscapedFromIfConfig = false; + Bits.Decl.Hoisted = false; } /// Get the Clang node associated with this declaration. @@ -836,6 +844,16 @@ class alignas(1 << DeclAlignInBits) Decl { /// Mark this declaration as implicit. void setImplicit(bool implicit = true) { Bits.Decl.Implicit = implicit; } + /// Determine whether this declaration is syntactically scoped inside of + /// a local context, but should behave like a top-level declaration + /// for name lookup purposes. This is used by lldb. + bool isHoisted() const { return Bits.Decl.Hoisted; } + + /// Set whether this declaration should be syntactically scoped inside + /// of a local context, but should behave like a top-level declaration, + /// but should behave like a top-level declaration. This is used by lldb. + void setHoisted(bool hoisted = true) { Bits.Decl.Hoisted = hoisted; } + public: bool escapedFromIfConfig() const { return Bits.Decl.EscapedFromIfConfig; @@ -2996,11 +3014,29 @@ class TypeAliasDecl : public GenericTypeDecl { /// Retrieve a sugared interface type containing the structure of the interface /// type before any semantic validation has occured. Type getStructuralType() const; - + + /// Whether the typealias forwards perfectly to its underlying type. + /// + /// If true, this typealias was created by ClangImporter to preserve source + /// compatibility with a previous language version's name for a type. Many + /// checks in Sema look through compatibility aliases even when they would + /// operate on other typealiases. + /// + /// \warning This has absolutely nothing to do with the Objective-C + /// \c compatibility_alias keyword. bool isCompatibilityAlias() const { return Bits.TypeAliasDecl.IsCompatibilityAlias; } + /// Sets whether the typealias forwards perfectly to its underlying type. + /// + /// Marks this typealias as having been created by ClangImporter to preserve + /// source compatibility with a previous language version's name for a type. + /// Many checks in Sema look through compatibility aliases even when they + /// would operate on other typealiases. + /// + /// \warning This has absolutely nothing to do with the Objective-C + /// \c compatibility_alias keyword. void markAsCompatibilityAlias(bool newValue = true) { Bits.TypeAliasDecl.IsCompatibilityAlias = newValue; } @@ -3867,7 +3903,7 @@ class ClassDecl final : public NominalTypeDecl { friend class SuperclassDeclRequest; friend class SuperclassTypeRequest; - friend class EmittedMembersRequest; + friend class SemanticMembersRequest; friend class HasMissingDesignatedInitializersRequest; friend class InheritsSuperclassInitializersRequest; @@ -4055,10 +4091,6 @@ class ClassDecl final : public NominalTypeDecl { /// Record the presence of an @objc method with the given selector. void recordObjCMethod(AbstractFunctionDecl *method, ObjCSelector selector); - /// Get all the members of this class, synthesizing any implicit members - /// that appear in the vtable if needed. - ArrayRef getEmittedMembers() const; - // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == DeclKind::Class; @@ -4851,9 +4883,9 @@ enum class PropertyWrapperSynthesizedPropertyKind { /// The backing storage property, which is a stored property of the /// wrapper type. Backing, - /// A storage wrapper (e.g., `$foo`), which is a wrapper over the - /// wrapper instance's `projectedValue` property. - StorageWrapper, + /// A projection (e.g., `$foo`), which is a computed property to access the + /// wrapper instance's \c projectedValue property. + Projection, }; /// VarDecl - 'var' and 'let' declarations. @@ -5176,9 +5208,9 @@ class VarDecl : public AbstractStorageDecl { /// bound generic version. VarDecl *getPropertyWrapperBackingProperty() const; - /// Retreive the storage wrapper for a property that has an attached - /// property wrapper. - VarDecl *getPropertyWrapperStorageWrapper() const; + /// Retreive the projection var for a property that has an attached + /// property wrapper with a \c projectedValue . + VarDecl *getPropertyWrapperProjectionVar() const; /// Retrieve the backing storage property for a lazy property. VarDecl *getLazyStorageProperty() const; @@ -5598,17 +5630,20 @@ enum class ObjCSubscriptKind { /// signatures (indices and element type) are distinct. /// class SubscriptDecl : public GenericContext, public AbstractStorageDecl { + friend class ResultTypeRequest; + SourceLoc StaticLoc; SourceLoc ArrowLoc; SourceLoc EndLoc; ParameterList *Indices; TypeLoc ElementTy; -public: + void setElementInterfaceType(Type type); + SubscriptDecl(DeclName Name, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc SubscriptLoc, ParameterList *Indices, - SourceLoc ArrowLoc, TypeLoc ElementTy, DeclContext *Parent, + SourceLoc ArrowLoc, TypeRepr *ElementTyR, DeclContext *Parent, GenericParamList *GenericParams) : GenericContext(DeclContextKind::SubscriptDecl, Parent, GenericParams), AbstractStorageDecl(DeclKind::Subscript, @@ -5616,10 +5651,31 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl { Parent, Name, SubscriptLoc, /*will be overwritten*/ StorageIsNotMutable), StaticLoc(StaticLoc), ArrowLoc(ArrowLoc), - Indices(nullptr), ElementTy(ElementTy) { + Indices(nullptr), ElementTy(ElementTyR) { Bits.SubscriptDecl.StaticSpelling = static_cast(StaticSpelling); setIndices(Indices); } + +public: + /// Factory function only for use by deserialization. + static SubscriptDecl *createDeserialized(ASTContext &Context, DeclName Name, + StaticSpellingKind StaticSpelling, + Type ElementTy, DeclContext *Parent, + GenericParamList *GenericParams); + + static SubscriptDecl *create(ASTContext &Context, DeclName Name, + SourceLoc StaticLoc, + StaticSpellingKind StaticSpelling, + SourceLoc SubscriptLoc, ParameterList *Indices, + SourceLoc ArrowLoc, TypeRepr *ElementTyR, + DeclContext *Parent, + GenericParamList *GenericParams); + + static SubscriptDecl *createImported(ASTContext &Context, DeclName Name, + SourceLoc SubscriptLoc, + ParameterList *Indices, + SourceLoc ArrowLoc, Type ElementTy, + DeclContext *Parent, ClangNode ClangN); /// \returns the way 'static'/'class' was spelled in the source. StaticSpellingKind getStaticSpelling() const { @@ -5646,8 +5702,11 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl { /// Retrieve the type of the element referenced by a subscript /// operation. Type getElementInterfaceType() const; - TypeLoc &getElementTypeLoc() { return ElementTy; } - const TypeLoc &getElementTypeLoc() const { return ElementTy; } + + TypeRepr *getElementTypeRepr() const { return ElementTy.getTypeRepr(); } + SourceRange getElementTypeSourceRange() const { + return ElementTy.getSourceRange(); + } /// Determine the kind of Objective-C subscripting this declaration /// implies. @@ -5888,6 +5947,16 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// type of the function will be `async` as well. bool hasAsync() const { return Bits.AbstractFunctionDecl.Async; } + /// Returns true if the function is a suitable 'async' context. + /// + /// Functions that are an 'async' context can make calls to 'async' functions. + bool isAsyncContext() const { + return hasAsync() || isAsyncHandler(); + } + + /// Returns true if the function is an @asyncHandler. + bool isAsyncHandler() const; + /// Returns true if the function body throws. bool hasThrows() const { return Bits.AbstractFunctionDecl.Throws; } @@ -5935,13 +6004,14 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// Note that parsing for the body was delayed. void setBodyDelayed(SourceRange bodyRange) { - assert(getBodyKind() == BodyKind::None || - getBodyKind() == BodyKind::Skipped); + assert(getBodyKind() == BodyKind::None); assert(bodyRange.isValid()); BodyRange = bodyRange; setBodyKind(BodyKind::Unparsed); } + void setBodyToBeReparsed(SourceRange bodyRange); + /// Provide the parsed body for the function. void setBodyParsed(BraceStmt *S) { setBody(S, BodyKind::Parsed); @@ -6007,6 +6077,19 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// Retrieve the source range of the function body. SourceRange getBodySourceRange() const; + /// Keep current \c getBodySourceRange() as the "original" body source range + /// iff the this method hasn't been called on this object. The current body + /// source range must be in the same buffer as the location of the declaration + /// itself. + void keepOriginalBodySourceRange(); + + /// Retrieve the source range of the *original* function body. + /// + /// This may be different from \c getBodySourceRange() that returns the source + /// range of the *current* body. It happens when the body is parsed from other + /// source buffers for e.g. code-completion. + SourceRange getOriginalBodySourceRange() const; + /// Retrieve the source range of the function declaration name + patterns. SourceRange getSignatureSourceRange() const; @@ -6079,7 +6162,15 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// being dropped altogether. `None` is returned for a normal function /// or method. Optional getForeignFunctionAsMethodSelfParameterIndex() const; - + + /// Set information about the foreign async convention used by this + /// declaration. + void setForeignAsyncConvention(const ForeignAsyncConvention &convention); + + /// Get information about the foreign async convention used by this + /// declaration, given that it is @objc and 'async'. + Optional getForeignAsyncConvention() const; + static bool classof(const Decl *D) { return D->getKind() >= DeclKind::First_AbstractFunctionDecl && D->getKind() <= DeclKind::Last_AbstractFunctionDecl; @@ -6122,6 +6213,7 @@ class FuncDecl : public AbstractFunctionDecl { friend class AbstractFunctionDecl; friend class SelfAccessKindRequest; friend class IsStaticRequest; + friend class ResultTypeRequest; SourceLoc StaticLoc; // Location of the 'static' token or invalid. SourceLoc FuncLoc; // Location of the 'func' token. @@ -6156,6 +6248,8 @@ class FuncDecl : public AbstractFunctionDecl { Bits.FuncDecl.HasTopLevelLocalContextCaptures = false; } + void setResultInterfaceType(Type type); + private: static FuncDecl *createImpl(ASTContext &Context, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, @@ -6183,25 +6277,32 @@ class FuncDecl : public AbstractFunctionDecl { public: /// Factory function only for use by deserialization. - static FuncDecl *createDeserialized(ASTContext &Context, SourceLoc StaticLoc, + static FuncDecl *createDeserialized(ASTContext &Context, StaticSpellingKind StaticSpelling, - SourceLoc FuncLoc, - DeclName Name, SourceLoc NameLoc, - bool Async, SourceLoc AsyncLoc, - bool Throws, SourceLoc ThrowsLoc, + DeclName Name, bool Async, bool Throws, GenericParamList *GenericParams, - DeclContext *Parent); + Type FnRetType, DeclContext *Parent); static FuncDecl *create(ASTContext &Context, SourceLoc StaticLoc, - StaticSpellingKind StaticSpelling, - SourceLoc FuncLoc, - DeclName Name, SourceLoc NameLoc, - bool Async, SourceLoc AsyncLoc, - bool Throws, SourceLoc ThrowsLoc, + StaticSpellingKind StaticSpelling, SourceLoc FuncLoc, + DeclName Name, SourceLoc NameLoc, bool Async, + SourceLoc AsyncLoc, bool Throws, SourceLoc ThrowsLoc, GenericParamList *GenericParams, - ParameterList *ParameterList, - TypeLoc FnRetType, DeclContext *Parent, - ClangNode ClangN = ClangNode()); + ParameterList *BodyParams, TypeRepr *ResultTyR, + DeclContext *Parent); + + static FuncDecl *createImplicit(ASTContext &Context, + StaticSpellingKind StaticSpelling, + DeclName Name, SourceLoc NameLoc, bool Async, + bool Throws, GenericParamList *GenericParams, + ParameterList *BodyParams, Type FnRetType, + DeclContext *Parent); + + static FuncDecl *createImported(ASTContext &Context, SourceLoc FuncLoc, + DeclName Name, SourceLoc NameLoc, + bool Async, bool Throws, + ParameterList *BodyParams, Type FnRetType, + DeclContext *Parent, ClangNode ClangN); bool isStatic() const; @@ -6245,8 +6346,10 @@ class FuncDecl : public AbstractFunctionDecl { } SourceRange getSourceRange() const; - TypeLoc &getBodyResultTypeLoc() { return FnRetType; } - const TypeLoc &getBodyResultTypeLoc() const { return FnRetType; } + TypeRepr *getResultTypeRepr() const { return FnRetType.getTypeRepr(); } + SourceRange getResultTypeSourceRange() const { + return FnRetType.getSourceRange(); + } /// Retrieve the result interface type of this function. Type getResultInterfaceType() const; @@ -6367,15 +6470,12 @@ class AccessorDecl final : public FuncDecl { public: static AccessorDecl *createDeserialized(ASTContext &ctx, - SourceLoc declLoc, - SourceLoc accessorKeywordLoc, - AccessorKind accessorKind, - AbstractStorageDecl *storage, - SourceLoc staticLoc, - StaticSpellingKind staticSpelling, - bool throws, SourceLoc throwsLoc, - GenericParamList *genericParams, - DeclContext *parent); + AccessorKind accessorKind, + AbstractStorageDecl *storage, + StaticSpellingKind staticSpelling, + bool throws, + GenericParamList *genericParams, + Type fnRetType, DeclContext *parent); static AccessorDecl *create(ASTContext &ctx, SourceLoc declLoc, SourceLoc accessorKeywordLoc, @@ -6386,7 +6486,7 @@ class AccessorDecl final : public FuncDecl { bool throws, SourceLoc throwsLoc, GenericParamList *genericParams, ParameterList *parameterList, - TypeLoc fnRetType, DeclContext *parent, + Type fnRetType, DeclContext *parent, ClangNode clangNode = ClangNode()); SourceLoc getAccessorKeywordLoc() const { return AccessorKeywordLoc; } diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index 36e1f07a2db56..c41eaa46a8b40 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -783,6 +783,16 @@ class IterableDeclContext { /// Retrieve the set of members in this context. DeclRange getMembers() const; + /// Get the members that were syntactically present in the source code, + /// and will not contain any members that are implicitly synthesized by + /// the implementation. + ArrayRef getParsedMembers() const; + + /// Get all the members that are semantically within this context, + /// including any implicitly-synthesized members. + /// The resulting list of members will be stable across translation units. + ArrayRef getSemanticMembers() const; + /// Retrieve the set of members in this context without loading any from the /// associated lazy loader; this should only be used as part of implementing /// abstractions on top of member loading, such as a name lookup table. diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index ee3c776cd9db6..338f146922b5e 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -20,8 +20,9 @@ #include "swift/AST/DeclNameLoc.h" #include "swift/AST/DiagnosticConsumer.h" -#include "swift/AST/LocalizationFormat.h" #include "swift/AST/TypeLoc.h" +#include "swift/Localization/LocalizationFormat.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/FileSystem.h" @@ -987,7 +988,8 @@ namespace swift { void emitTentativeDiagnostics(); public: - const char *diagnosticStringFor(const DiagID id, bool printDiagnosticName); + llvm::StringRef diagnosticStringFor(const DiagID id, + bool printDiagnosticName); /// If there is no clear .dia file for a diagnostic, put it in the one /// corresponding to the SourceLoc given here. @@ -1056,6 +1058,21 @@ namespace swift { } } + bool hasErrors() const { + ArrayRef diagnostics(Engine.TentativeDiagnostics.begin() + + PrevDiagnostics, + Engine.TentativeDiagnostics.end()); + + for (auto &diagnostic : diagnostics) { + auto behavior = Engine.state.determineBehavior(diagnostic.getID()); + if (behavior == DiagnosticState::Behavior::Fatal || + behavior == DiagnosticState::Behavior::Error) + return true; + } + + return false; + } + /// Abort and close this transaction and erase all diagnostics /// record while it was open. void abort() { diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index cdeef09e3058e..72d8d64bbecb7 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -185,5 +185,22 @@ WARNING(cross_imported_by_both_modules, none, ERROR(scanner_find_cycle, none, "dependency scanner detected dependency cycle: '%0'", (StringRef)) +ERROR(scanner_arguments_invalid, none, + "dependencies scanner cannot be configured with arguments: '%0'", (StringRef)) + +//------------------------------------------------------------------------------ +// MARK: custom attribute diagnostics +//------------------------------------------------------------------------------ + +ERROR(ambiguous_custom_attribute_ref,none, + "ambiguous use of attribute %0", (Identifier)) +NOTE(ambiguous_custom_attribute_ref_fix,none, + "use '%0.' to reference the attribute %1 in module %2", + (StringRef, Identifier, Identifier)) +NOTE(found_attribute_candidate,none, + "found this attribute", ()) +ERROR(unknown_attribute,none, + "unknown attribute '%0'", (StringRef)) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 6f88d42b6b517..5f15d3a2bde46 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -121,6 +121,8 @@ ERROR(error_mode_cannot_emit_module_source_info,none, "this mode does not support emitting module source info files", ()) ERROR(error_mode_cannot_emit_interface,none, "this mode does not support emitting module interface files", ()) +ERROR(error_mode_cannot_emit_module_summary,none, + "this mode does not support emitting module summary files", ()) ERROR(cannot_emit_ir_skipping_function_bodies,none, "-experimental-skip-non-inlinable-function-bodies does not support " "emitting IR", ()) @@ -270,6 +272,14 @@ ERROR(placeholder_dependency_module_map_corrupted,none, "Swift placeholder dependency module map from %0 is malformed", (StringRef)) +ERROR(batch_scan_input_file_missing,none, + "cannot open batch dependencies scan input file from %0", + (StringRef)) + +ERROR(batch_scan_input_file_corrupted,none, + "batch dependencies scan input file from %0 is malformed", + (StringRef)) + REMARK(default_previous_install_name, none, "default previous install name for %0 is %1", (StringRef, StringRef)) @@ -316,11 +326,11 @@ ERROR(error_optimization_remark_pattern, none, "%0 in '%1'", (StringRef, StringRef)) ERROR(error_invalid_debug_prefix_map, none, - "invalid argument '%0' to -debug-prefix-map; it must be of the form " - "'original=remapped'", (StringRef)) + "values for '-debug-prefix-map' must be in the format 'original=remapped'" + ", but '%0' was provided", (StringRef)) ERROR(error_invalid_coverage_prefix_map, none, - "invalid argument '%0' to -coverage-prefix-map; it must be of the form " - "'original=remapped'", (StringRef)) + "values for '-coverage-prefix-map' must be in the format " + "'original=remapped', but '%0' was provided", (StringRef)) ERROR(error_unable_to_write_swift_ranges_file, none, @@ -354,6 +364,9 @@ ERROR(error_extracting_flags_from_module_interface,none, "error extracting flags from module interface", ()) REMARK(rebuilding_module_from_interface,none, "rebuilding module '%0' from interface '%1'", (StringRef, StringRef)) +NOTE(sdk_version_pbm_version,none, + "SDK build version is '%0'; prebuilt modules were " + "built using SDK build version: '%1'", (StringRef, StringRef)) NOTE(out_of_date_module_here,none, "%select{compiled|cached|forwarding|prebuilt}0 module is out of date: '%1'", (unsigned, StringRef)) diff --git a/include/swift/AST/DiagnosticsModuleDiffer.def b/include/swift/AST/DiagnosticsModuleDiffer.def index d4aba30553186..dbcc194ba4ca6 100644 --- a/include/swift/AST/DiagnosticsModuleDiffer.def +++ b/include/swift/AST/DiagnosticsModuleDiffer.def @@ -74,7 +74,7 @@ ERROR(param_ownership_change,none,"%0 has %1 changing from %2 to %3", (StringRef ERROR(type_witness_change,none,"%0 has type witness type for %1 changing from %2 to %3", (StringRef, StringRef, StringRef, StringRef)) -ERROR(decl_new_witness_table_entry,none,"%0 now requires %select{|no}1 new witness table entry", (StringRef, bool)) +ERROR(decl_new_witness_table_entry,none,"%0 now requires%select{| no}1 new witness table entry", (StringRef, bool)) ERROR(new_decl_without_intro,none,"%0 is a new API without @available attribute", (StringRef)) @@ -88,5 +88,7 @@ ERROR(not_inheriting_convenience_inits,none,"%0 no longer inherits convenience i ERROR(enum_case_added,none,"%0 has been added as a new enum case", (StringRef)) +WARNING(cannot_read_allowlist,none,"cannot read breakage allowlist at '%0'", (StringRef)) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 6c7f4e6533b04..eaae1b7f858be 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -882,8 +882,6 @@ ERROR(expected_parameter_colon,PointsToFirstBadToken, "expected ':' following argument label and parameter name", ()) ERROR(expected_assignment_instead_of_comparison_operator,none, "expected '=' instead of '==' to assign default value for parameter", ()) -ERROR(multiple_parameter_ellipsis,none, - "only a single variadic parameter '...' is permitted", ()) ERROR(parameter_vararg_default,none, "variadic parameter cannot have a default value", ()) ERROR(parameter_specifier_as_attr_disallowed,none, @@ -916,6 +914,8 @@ ERROR(initializer_as_typed_pattern,none, ERROR(unlabeled_parameter_following_variadic_parameter,none, "a parameter following a variadic parameter requires a label", ()) +ERROR(closure_unlabeled_parameter_following_variadic_parameter,none, + "no parameters may follow a variadic parameter in a closure", ()) ERROR(enum_element_empty_arglist,none, "enum element with associated values must have at least one " @@ -1324,8 +1324,6 @@ ERROR(replace_equal_with_colon_for_value,none, "'=' has been replaced with ':' in attribute arguments", ()) ERROR(expected_attribute_name,none, "expected an attribute name", ()) -ERROR(unknown_attribute,none, - "unknown attribute '%0'", (StringRef)) ERROR(unexpected_lparen_in_attribute,none, "unexpected '(' in attribute '%0'", (StringRef)) ERROR(duplicate_attribute,none, diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 1998449474d87..5de6c959c74fc 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -112,6 +112,9 @@ ERROR(expected_argument_in_contextual_member,none, "member %0 expects argument of type %1", (DeclName, Type)) ERROR(expected_parens_in_contextual_member,none, "member %0 is a function; did you mean to call it?", (DeclName)) +ERROR(expected_parens_in_contextual_member_type,none, + "member %0 is a function that produces expected type %1; did you mean to " + "call it?", (DeclName, Type)) ERROR(expected_result_in_contextual_member,none, "member %0 in %2 produces result of type %1, but context expects %2", @@ -453,6 +456,10 @@ ERROR(cannot_convert_closure_result_nil,none, ERROR(cannot_convert_parent_type,none, "cannot convert parent type %0 to expected type %1", (Type, Type)) +ERROR(cannot_convert_chain_result_type,none, + "member chain produces result of type %0 but contextual base was " + "inferred as %1", + (Type, Type)) NOTE(generic_argument_mismatch,none, "arguments to generic parameter %0 (%1 and %2) are expected to be equal", @@ -708,12 +715,12 @@ ERROR(sema_opening_import,Fatal, ERROR(serialization_load_failed,Fatal, "failed to load module '%0'", (StringRef)) ERROR(module_interface_build_failed,Fatal, - "failed to build module '%0' from its module interface; " - "%select{the compiler that produced it, '%2', may have used features " - "that aren't supported by this compiler, '%3'" - "|it may have been damaged or it may have triggered a bug in the Swift " - "compiler when it was produced}1", - (StringRef, bool, StringRef, StringRef)) + "failed to %select{build module '%1' from its module interface|verify " + "module interface of '%1'}0; %select{the compiler that produced it, " + "'%3', may have used features that aren't supported by this compiler, " + "'%4'|it may have been damaged or it may have triggered a bug in the " + "Swift compiler when it was produced}2", + (bool, StringRef, bool, StringRef, StringRef)) ERROR(serialization_malformed_module,Fatal, "malformed compiled module: %0", (StringRef)) ERROR(serialization_module_too_new,Fatal, @@ -1038,9 +1045,6 @@ WARNING(downcast_to_unrelated,none, "cast from %0 to unrelated type %1 always fails", (Type, Type)) NOTE(downcast_to_unrelated_fixit,none, "did you mean to call %0 with '()'?", (Identifier)) -ERROR(downcast_to_more_optional,none, - "cannot downcast from %0 to a more optional type %1", - (Type, Type)) ERROR(optional_chain_noop,none, "optional chain has no effect, expression already produces %0", (Type)) @@ -1082,6 +1086,9 @@ NOTE(unwrap_with_guard,none, ERROR(optional_base_not_unwrapped,none, "value of optional type %0 must be unwrapped to refer to member %1 of " "wrapped base type %2", (Type, DeclNameRef, Type)) +ERROR(invalid_optional_infered_keypath_root, none, + "key path root inferred as optional type %0 must be unwrapped to refer to member %1 " + "of unwrapped type %2", (Type, DeclNameRef, Type)) NOTE(optional_base_chain,none, "chain the optional using '?' to access member %0 only for non-'nil' " "base values", (DeclNameRef)) @@ -1089,6 +1096,12 @@ NOTE(optional_base_remove_optional_for_keypath_root, none, "use unwrapped type %0 as key path root", (Type)) NOTE(optional_keypath_application_base, none, "use '?' to access key path subscript only for non-'nil' base values", ()) +NOTE(optional_key_path_root_base_chain, none, + "chain the optional using '?.' to access unwrapped type member %0", + (DeclNameRef)) +NOTE(optional_key_path_root_base_unwrap, none, + "unwrap the optional using '!.' to access unwrapped type member %0", + (DeclNameRef)) ERROR(missing_unwrap_optional_try,none, "value of optional type %0 not unwrapped; did you mean to use 'try!' " @@ -1294,8 +1307,9 @@ ERROR(nominal_type_not_attribute,none, ERROR(mutating_invalid_global_scope,none, "%0 is only valid on methods", (SelfAccessKind)) -ERROR(mutating_invalid_classes,none, "%0 isn't valid on methods in " - "classes or class-bound protocols", (SelfAccessKind)) +ERROR(mutating_invalid_classes,none, "%0 is not valid on %1s in " + "%select{classes|class-bound protocols}2", + (SelfAccessKind, DescriptiveDeclKind, bool)) ERROR(functions_mutating_and_not,none, "method must not be declared both %0 and %1", @@ -1370,6 +1384,8 @@ ERROR(cdecl_empty_name,none, "@_cdecl symbol name cannot be empty", ()) ERROR(cdecl_throws,none, "raising errors from @_cdecl functions is not supported", ()) +ERROR(cdecl_async,none, + "@_cdecl functions cannot be asynchronous", ()) ERROR(attr_methods_only,none, "only methods can be declared %0", (DeclAttribute)) @@ -2174,9 +2190,6 @@ NOTE(protocol_witness_settable_conflict,none, "candidate is not settable, but protocol requires it", ()) NOTE(protocol_witness_rethrows_conflict,none, "candidate is not 'rethrows', but protocol requires it", ()) -NOTE(protocol_witness_async_conflict,none, - "candidate is %select{not |}0'async', but protocol requirement is%select{| not}0", - (bool)) NOTE(protocol_witness_throws_conflict,none, "candidate throws, but protocol does not allow it", ()) NOTE(protocol_witness_not_objc,none, @@ -2728,13 +2741,17 @@ WARNING(decl_from_hidden_module_warn,none, ERROR(conformance_from_implementation_only_module,none, "cannot use conformance of %0 to %1 %select{here|as property wrapper here|" "in an extension with public or '@usableFromInline' members|" - "in an extension with conditional conformances}2; %3 has been imported " - "as implementation-only", - (Type, Identifier, unsigned, Identifier)) + "in an extension with conditional conformances}2; " + "%select{%3 has been imported as implementation-only|" + "the conformance is declared as SPI in %3|" + "the conformance is declared as SPI}4", + (Type, Identifier, unsigned, Identifier, unsigned)) ERROR(assoc_conformance_from_implementation_only_module,none, "cannot use conformance of %0 to %1 in associated type %3 (inferred as " - "%4); %2 has been imported as implementation-only", - (Type, Identifier, Identifier, Type, Type)) + "%4); %select{%2 has been imported as implementation-only|" + "the conformance is declared as SPI in %2|" + "the conformance is declared as SPI}5", + (Type, Identifier, Identifier, Type, Type, unsigned)) ERROR(unexportable_clang_function_type,none, "cannot export the underlying C type of the function type %0; " "it may use anonymous types or types defined outside of a module", @@ -2765,8 +2782,9 @@ ERROR(cannot_synthesize_init_in_extension_of_nonfinal,none, "be satisfied by a 'required' initializer in the class definition", (Type, DeclName)) ERROR(cannot_synthesize_in_crossfile_extension,none, - "implementation of %0 cannot be automatically synthesized in an extension " - "in a different file to the type", (Type)) + "extension outside of file declaring %0 %1 prevents automatic synthesis " + "of %2 for protocol %3", + (DescriptiveDeclKind, DeclName, DeclName, Type)) ERROR(broken_additive_arithmetic_requirement,none, "AdditiveArithmetic protocol is broken: unexpected requirement", ()) @@ -2808,15 +2826,16 @@ WARNING(differentiable_nondiff_type_implicit_noderivative_fixit,none, /*nominalCanDeriveAdditiveArithmetic*/ bool)) WARNING(differentiable_immutable_wrapper_implicit_noderivative_fixit,none, "synthesis of the 'Differentiable.move(along:)' requirement for %1 " - "requires 'wrappedValue' in property wrapper %0 to be mutable; " - "add an explicit '@noDerivative' attribute" + "requires 'wrappedValue' in property wrapper %0 to be mutable or have a " + "non-mutating 'move(along:)'; add an explicit '@noDerivative' attribute" "%select{|, or conform %1 to 'AdditiveArithmetic'}2", (/*wrapperType*/ Identifier, /*nominalName*/ Identifier, /*nominalCanDeriveAdditiveArithmetic*/ bool)) WARNING(differentiable_let_property_implicit_noderivative_fixit,none, "synthesis of the 'Differentiable.move(along:)' requirement for %0 " "requires all stored properties not marked with `@noDerivative` to be " - "mutable; use 'var' instead, or add an explicit '@noDerivative' attribute" + "mutable or have a non-mutating 'move(along:)'; use 'var' instead, or " + "add an explicit '@noDerivative' attribute " "%select{|, or conform %0 to 'AdditiveArithmetic'}1", (/*nominalName*/ Identifier, /*nominalCanDeriveAdditiveArithmetic*/ bool)) @@ -4016,10 +4035,13 @@ ERROR(throw_in_nonexhaustive_catch,none, "error is not handled because the enclosing catch is not exhaustive", ()) ERROR(throwing_call_in_illegal_context,none, - "call can throw, but errors cannot be thrown out of %0", - (StringRef)) + "call can throw, but errors cannot be thrown out of " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) ERROR(throw_in_illegal_context,none, - "errors cannot be thrown out of %0", (StringRef)) + "errors cannot be thrown out of " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) ERROR(throwing_operator_without_try,none, "operator can throw but expression is not marked with 'try'", ()) @@ -4033,10 +4055,6 @@ NOTE(note_error_to_optional,none, "did you mean to handle error as optional value?", ()) NOTE(note_disable_error_propagation,none, "did you mean to disable error propagation?", ()) -ERROR(async_call_without_await,none, - "call is 'async' but is not marked with 'await'", ()) -WARNING(no_async_in_await,none, - "no calls to 'async' functions occur within 'await' expression", ()) WARNING(no_throw_in_try,none, "no calls to throwing functions occur within 'try' expression", ()) @@ -4044,6 +4062,76 @@ WARNING(no_throw_in_try,none, WARNING(no_throw_in_do_with_catch,none, "'catch' block is unreachable because no errors are thrown in 'do' block", ()) +//------------------------------------------------------------------------------ +// MARK: Concurrency +//------------------------------------------------------------------------------ +ERROR(async_call_without_await,none, + "call is 'async' but is not marked with 'await'", ()) +ERROR(async_call_without_await_in_autoclosure,none, + "call is 'async' in an autoclosure argument that is not marked with 'await'", ()) +WARNING(no_async_in_await,none, + "no calls to 'async' functions occur within 'await' expression", ()) +ERROR(async_call_in_illegal_context,none, + "'async' call cannot occur in " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) +ERROR(await_in_illegal_context,none, + "'await' operation cannot occur in " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) +ERROR(async_in_nonasync_function,none, + "%select{'async'|'await'}0 in %select{a function|an autoclosure}1 that " + "does not support concurrency", + (bool, bool)) +NOTE(note_add_async_to_function,none, + "add 'async' to function %0 to make it asynchronous", (DeclName)) +NOTE(note_add_asynchandler_to_function,none, + "add '@asyncHandler' to function %0 to create an implicit asynchronous context", (DeclName)) +ERROR(not_objc_function_async,none, + "'async' function cannot be represented in Objective-C", ()) +NOTE(not_objc_function_type_async,none, + "'async' function types cannot be represented in Objective-C", ()) +NOTE(protocol_witness_async_conflict,none, + "candidate is %select{not |}0'async', but protocol requirement is%select{| not}0", + (bool)) +ERROR(async_autoclosure_nonasync_function,none, + "'async' autoclosure parameter in a non-'async' function", ()) + +ERROR(asynchandler_attr_requires_concurrency,none, + "'@asyncHandler' is only valid when experimental concurrency is enabled", + ()) +ERROR(asynchandler_non_func,none, + "'@asyncHandler' can only be applied to functions", + ()) +ERROR(asynchandler_returns_value,none, + "'@asyncHandler' function can only return 'Void'", + ()) +ERROR(asynchandler_throws,none, + "'@asyncHandler' function cannot throw", + ()) +ERROR(asynchandler_async,none, + "'@asyncHandler' function cannot be 'async' itself", + ()) +ERROR(asynchandler_inout_parameter,none, + "'inout' parameter is not allowed in '@asyncHandler' function", + ()) +ERROR(asynchandler_mutating,none, + "'@asyncHandler' function cannot be 'mutating'", + ()) + +ERROR(objc_ambiguous_async_convention,none, + "%0 overrides or implements protocol requirements for Objective-C " + "declarations with incompatible async conventions", + (DeclName)) +NOTE(objc_ambiguous_async_convention_candidate,none, + "%0 provides async here", (DeclName)) + +ERROR(satisfy_async_objc,none, + "satisfying an asychronous @objc %select{method|initializer}0 with " + "a synchronous %select{method|initializer}0 is not supported", (bool)) +ERROR(async_objc_dynamic_self,none, + "asynchronous method returning 'Self' cannot be '@objc'", ()) + //------------------------------------------------------------------------------ // MARK: Type Check Types //------------------------------------------------------------------------------ @@ -4398,10 +4486,6 @@ NOTE(not_objc_generic_type_param,none, NOTE(not_objc_function_type_param,none, "function types cannot be represented in Objective-C unless their " "parameters and returns can be", ()) -ERROR(not_objc_function_async,none, - "'async' function cannot be represented in Objective-C", ()) -NOTE(not_objc_function_type_async,none, - "'async' function types cannot be represented in Objective-C", ()) NOTE(not_objc_function_type_throwing,none, "throwing function types cannot be represented in Objective-C", ()) NOTE(objc_inferring_on_objc_protocol_member,none, @@ -5181,6 +5265,16 @@ WARNING(function_builder_missing_limited_availability, none, "function builder %0 does not implement 'buildLimitedAvailability'; " "this code may crash on earlier versions of the OS", (Type)) +ERROR(function_builder_static_buildblock, none, + "function builder must provide at least one static 'buildBlock' " + "method", ()) +NOTE(function_builder_non_static_buildblock, none, + "did you mean to make instance method 'buildBlock' static?", ()) +NOTE(function_builder_buildblock_enum_case, none, + "enum case 'buildBlock' cannot be used to satisfy the function builder " + "requirement", ()) +NOTE(function_builder_buildblock_not_static_method, none, + "potential match 'buildBlock' is not a static method", ()) //------------------------------------------------------------------------------ // MARK: Tuple Shuffle Diagnostics diff --git a/include/swift/AST/Evaluator.h b/include/swift/AST/Evaluator.h index 5235343ebe779..212682d0bc121 100644 --- a/include/swift/AST/Evaluator.h +++ b/include/swift/AST/Evaluator.h @@ -65,7 +65,7 @@ class PrettyStackTraceRequest : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceRequest(const Request &request) : request(request) { } - void print(llvm::raw_ostream &out) const { + void print(llvm::raw_ostream &out) const override { out << "While evaluating request "; simple_display(out, request); out << "\n"; @@ -85,9 +85,9 @@ struct CyclicalRequestError : CyclicalRequestError(const Request &request, const Evaluator &evaluator) : request(request), evaluator(evaluator) {} - virtual void log(llvm::raw_ostream &out) const; + virtual void log(llvm::raw_ostream &out) const override; - virtual std::error_code convertToErrorCode() const { + virtual std::error_code convertToErrorCode() const override { // This is essentially unused, but is a temporary requirement for // llvm::ErrorInfo subclasses. llvm_unreachable("shouldn't get std::error_code from CyclicalRequestError"); diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index a75d9d56b39e4..b53a279a93b4c 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -249,17 +249,8 @@ class alignas(8) Expr { NumArgLabels : 16 ); - SWIFT_INLINE_BITFIELD_FULL(UnresolvedMemberExpr, Expr, 1+1+1+16, - /// Whether the UnresolvedMemberExpr has arguments. - HasArguments : 1, - /// Whether the UnresolvedMemberExpr also has source locations for the - /// argument label. - HasArgLabelLocs : 1, - /// Whether the last argument is a trailing closure. - HasTrailingClosure : 1, - : NumPadBits, - /// # of argument labels stored after the UnresolvedMemberExpr. - NumArgLabels : 16 + SWIFT_INLINE_BITFIELD_FULL(UnresolvedMemberExpr, Expr, 2, + FunctionRefKind : 2 ); SWIFT_INLINE_BITFIELD(OverloadSetRefExpr, Expr, 2, @@ -1841,71 +1832,49 @@ class DynamicSubscriptExpr final /// member, which is to be resolved with context sensitive type information into /// bar.foo. These always have unresolved type. class UnresolvedMemberExpr final - : public Expr, - public TrailingCallArguments { + : public Expr { SourceLoc DotLoc; DeclNameLoc NameLoc; DeclNameRef Name; - Expr *Argument; - - UnresolvedMemberExpr(SourceLoc dotLoc, DeclNameLoc nameLoc, - DeclNameRef name, Expr *argument, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, - bool implicit); public: - /// Create a new unresolved member expression with no arguments. - static UnresolvedMemberExpr *create(ASTContext &ctx, SourceLoc dotLoc, - DeclNameLoc nameLoc, DeclNameRef name, - bool implicit); - - /// Create a new unresolved member expression. - static UnresolvedMemberExpr *create(ASTContext &ctx, SourceLoc dotLoc, - DeclNameLoc nameLoc, DeclNameRef name, - SourceLoc lParenLoc, - ArrayRef args, - ArrayRef argLabels, - ArrayRef argLabelLocs, - SourceLoc rParenLoc, - ArrayRef trailingClosures, - bool implicit); + UnresolvedMemberExpr(SourceLoc dotLoc, DeclNameLoc nameLoc, DeclNameRef name, + bool implicit) + : Expr(ExprKind::UnresolvedMember, implicit), DotLoc(dotLoc), + NameLoc(nameLoc), Name(name) { + // FIXME: Really, we should be setting this to `FunctionRefKind::Compound` + // if `NameLoc` is compound, but this would be a source break for cases like + // ``` + // struct S { + // static func makeS(_: Int) -> S! { S() } + // } + // + // let s: S = .makeS(_:)(0) + // ``` + // Instead, we should store compound-ness as a separate bit from applied/ + // unapplied. + Bits.UnresolvedMemberExpr.FunctionRefKind = + static_cast(FunctionRefKind::Unapplied); + } DeclNameRef 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; } - - /// Whether this reference has arguments. - bool hasArguments() const { - return Bits.UnresolvedMemberExpr.HasArguments; - } - unsigned getNumArguments() const { - return Bits.UnresolvedMemberExpr.NumArgLabels; - } - - bool hasArgumentLabelLocs() const { - return Bits.UnresolvedMemberExpr.HasArgLabelLocs; - } + SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } - /// Whether this call with written with a trailing closure. - bool hasTrailingClosure() const { - return Bits.UnresolvedMemberExpr.HasTrailingClosure; - } + SourceLoc getStartLoc() const { return DotLoc; } + SourceLoc getEndLoc() const { return NameLoc.getSourceRange().End; } - /// Return the index of the unlabeled trailing closure argument. - Optional getUnlabeledTrailingClosureIndex() const { - return getArgument()->getUnlabeledTrailingClosureIndexOfPackedArgument(); + /// Retrieve the kind of function reference. + FunctionRefKind getFunctionRefKind() const { + return static_cast( + Bits.UnresolvedMemberExpr.FunctionRefKind); } - SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } - - SourceLoc getStartLoc() const { return DotLoc; } - SourceLoc getEndLoc() const { - return (Argument ? Argument->getEndLoc() : NameLoc.getSourceRange().End); + /// Set the kind of function reference. + void setFunctionRefKind(FunctionRefKind refKind) { + Bits.UnresolvedMemberExpr.FunctionRefKind = static_cast(refKind); } static bool classof(const Expr *E) { @@ -2088,6 +2057,31 @@ class ParenExpr : public IdentityExpr { static bool classof(const Expr *E) { return E->getKind() == ExprKind::Paren; } }; + +/// Represents the result of a chain of accesses or calls hanging off of an +/// \c UnresolvedMemberExpr at the root. This is only used during type checking +/// to give the result type of such a chain representation in the AST. This +/// expression type is always implicit. +class UnresolvedMemberChainResultExpr : public IdentityExpr { + /// The base of this chain of member accesses. + UnresolvedMemberExpr *ChainBase; +public: + UnresolvedMemberChainResultExpr(Expr *subExpr, UnresolvedMemberExpr *base, + Type ty = Type()) + : IdentityExpr(ExprKind::UnresolvedMemberChainResult, subExpr, ty, + /*isImplicit=*/true), + ChainBase(base) { + assert(base); + } + + UnresolvedMemberExpr *getChainBase() const { return ChainBase; } + + SWIFT_FORWARD_SOURCE_LOCS_TO(getSubExpr()) + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::UnresolvedMemberChainResult; + } +}; /// AwaitExpr - An 'await' surrounding an expression, marking that the /// expression contains code which is a coroutine that may block. @@ -3815,6 +3809,9 @@ class ClosureExpr : public AbstractClosureExpr { /// this information directly on the ClosureExpr. VarDecl * CapturedSelfDecl; + /// The location of the "async", if present. + SourceLoc AsyncLoc; + /// The location of the "throws", if present. SourceLoc ThrowsLoc; @@ -3833,14 +3830,15 @@ class ClosureExpr : public AbstractClosureExpr { llvm::PointerIntPair Body; public: ClosureExpr(SourceRange bracketRange, VarDecl *capturedSelfDecl, - ParameterList *params, SourceLoc throwsLoc, SourceLoc arrowLoc, - SourceLoc inLoc, TypeExpr *explicitResultType, + ParameterList *params, SourceLoc asyncLoc, SourceLoc throwsLoc, + SourceLoc arrowLoc, SourceLoc inLoc, TypeExpr *explicitResultType, unsigned discriminator, DeclContext *parent) : AbstractClosureExpr(ExprKind::Closure, Type(), /*Implicit=*/false, discriminator, parent), BracketRange(bracketRange), CapturedSelfDecl(capturedSelfDecl), - ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), InLoc(inLoc), + AsyncLoc(asyncLoc), ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), + InLoc(inLoc), ExplicitResultTypeAndBodyState(explicitResultType, BodyState::Parsed), Body(nullptr) { setParameterList(params); @@ -3888,7 +3886,12 @@ class ClosureExpr : public AbstractClosureExpr { SourceLoc getInLoc() const { return InLoc; } - + + /// Retrieve the location of the 'async' for a closure that has it. + SourceLoc getAsyncLoc() const { + return AsyncLoc; + } + /// Retrieve the location of the 'throws' for a closure that has it. SourceLoc getThrowsLoc() const { return ThrowsLoc; @@ -5648,7 +5651,13 @@ class KeyPathExpr : public Expr { /// components from the argument array. void resolveComponents(ASTContext &C, ArrayRef resolvedComponents); - + + /// Indicates if the key path expression is composed by a single invalid + /// component. e.g. missing component `\Root` + bool hasSingleInvalidComponent() const { + return Components.size() == 1 && !Components.front().isValid(); + } + /// Retrieve the string literal expression, which will be \c NULL prior to /// type checking and a string literal after type checking for an /// @objc key path. diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index 53ee2da310a42..7c98a83c0afd9 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -104,7 +104,8 @@ ABSTRACT_EXPR(Identity, Expr) EXPR(Paren, IdentityExpr) EXPR(DotSelf, IdentityExpr) EXPR(Await, IdentityExpr) - EXPR_RANGE(Identity, Paren, Await) + EXPR(UnresolvedMemberChainResult, IdentityExpr) + EXPR_RANGE(Identity, Paren, UnresolvedMemberChainResult) ABSTRACT_EXPR(AnyTry, Expr) EXPR(Try, AnyTryExpr) EXPR(ForceTry, AnyTryExpr) diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index 639b982d25e73..6f258723fb887 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -30,6 +30,7 @@ namespace clang { class Type; +class ASTContext; } // namespace clang namespace swift { @@ -77,7 +78,7 @@ class ClangTypeInfo { /// Use the ClangModuleLoader to print the Clang type as a string. void printType(ClangModuleLoader *cml, llvm::raw_ostream &os) const; - void dump(llvm::raw_ostream &os) const; + void dump(llvm::raw_ostream &os, const clang::ASTContext &ctx) const; }; // MARK: - FunctionTypeRepresentation @@ -194,16 +195,8 @@ class ASTExtInfoBuilder { using Representation = FunctionTypeRepresentation; - static void assertIsFunctionType(const clang::Type *); - ASTExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo) - : bits(bits), clangTypeInfo(clangTypeInfo) { - // TODO: [clang-function-type-serialization] Once we start serializing - // the Clang type, we should also assert that the pointer is non-null. - auto Rep = Representation(bits & RepresentationMask); - if ((Rep == Representation::CFunctionPointer) && clangTypeInfo.type) - assertIsFunctionType(clangTypeInfo.type); - } + : bits(bits), clangTypeInfo(clangTypeInfo) {} public: // Constructor with all defaults. @@ -254,10 +247,7 @@ class ASTExtInfoBuilder { DifferentiabilityKind::NonDifferentiable; } - /// Get the underlying ClangTypeInfo value if it is not the default value. - Optional getClangTypeInfo() const { - return clangTypeInfo.empty() ? Optional() : clangTypeInfo; - } + ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; } constexpr SILFunctionTypeRepresentation getSILRepresentation() const { unsigned rawRep = bits & RepresentationMask; @@ -404,9 +394,7 @@ class ASTExtInfo { constexpr bool isDifferentiable() const { return builder.isDifferentiable(); } - Optional getClangTypeInfo() const { - return builder.getClangTypeInfo(); - } + ClangTypeInfo getClangTypeInfo() const { return builder.getClangTypeInfo(); } constexpr bool hasSelfParam() const { return builder.hasSelfParam(); } @@ -436,6 +424,14 @@ class ASTExtInfo { return builder.withThrows(throws).build(); } + /// Helper method for changing only the async field. + /// + /// Prefer using \c ASTExtInfoBuilder::withAsync for chaining. + LLVM_NODISCARD + ASTExtInfo withAsync(bool async = true) const { + return builder.withAsync(async).build(); + } + bool isEqualTo(ASTExtInfo other, bool useClangTypes) const { return builder.isEqualTo(other.builder, useClangTypes); } @@ -487,16 +483,17 @@ class SILExtInfoBuilder { // If bits are added or removed, then TypeBase::SILFunctionTypeBits // and NumMaskBits must be updated, and they must match. - // |representation|pseudogeneric| noescape |differentiability| - // | 0 .. 3 | 4 | 5 | 6 .. 7 | + // |representation|pseudogeneric| noescape | async | differentiability| + // | 0 .. 3 | 4 | 5 | 6 | 7 .. 8 | // enum : unsigned { RepresentationMask = 0xF << 0, PseudogenericMask = 1 << 4, NoEscapeMask = 1 << 5, - DifferentiabilityMaskOffset = 6, + AsyncMask = 1 << 6, + DifferentiabilityMaskOffset = 7, DifferentiabilityMask = 0x3 << DifferentiabilityMaskOffset, - NumMaskBits = 8 + NumMaskBits = 9 }; unsigned bits; // Naturally sized for speed. @@ -509,19 +506,32 @@ class SILExtInfoBuilder { SILExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo) : bits(bits), clangTypeInfo(clangTypeInfo) {} + static constexpr unsigned makeBits(Representation rep, bool isPseudogeneric, + bool isNoEscape, bool isAsync, + DifferentiabilityKind diffKind) { + return ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) | + (isNoEscape ? NoEscapeMask : 0) | (isAsync ? AsyncMask : 0) | + (((unsigned)diffKind << DifferentiabilityMaskOffset) & + DifferentiabilityMask); + } + public: // Constructor with all defaults. - SILExtInfoBuilder() : bits(0), clangTypeInfo(ClangTypeInfo(nullptr)) {} + SILExtInfoBuilder() : SILExtInfoBuilder(0, ClangTypeInfo(nullptr)) {} // Constructor for polymorphic type. SILExtInfoBuilder(Representation rep, bool isPseudogeneric, bool isNoEscape, - DifferentiabilityKind diffKind, const clang::Type *type) - : SILExtInfoBuilder( - ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) | - (isNoEscape ? NoEscapeMask : 0) | - (((unsigned)diffKind << DifferentiabilityMaskOffset) & - DifferentiabilityMask), - ClangTypeInfo(type)) {} + bool isAsync, DifferentiabilityKind diffKind, + const clang::Type *type) + : SILExtInfoBuilder(makeBits(rep, isPseudogeneric, isNoEscape, isAsync, + diffKind), + ClangTypeInfo(type)) {} + + SILExtInfoBuilder(ASTExtInfoBuilder info, bool isPseudogeneric) + : SILExtInfoBuilder(makeBits(info.getSILRepresentation(), isPseudogeneric, + info.isNoEscape(), info.isAsync(), + info.getDifferentiabilityKind()), + info.getClangTypeInfo()) {} void checkInvariants() const; @@ -544,6 +554,8 @@ class SILExtInfoBuilder { // Is this function guaranteed to be no-escape by the type system? constexpr bool isNoEscape() const { return bits & NoEscapeMask; } + constexpr bool isAsync() const { return bits & AsyncMask; } + constexpr DifferentiabilityKind getDifferentiabilityKind() const { return DifferentiabilityKind((bits & DifferentiabilityMask) >> DifferentiabilityMaskOffset); @@ -554,10 +566,8 @@ class SILExtInfoBuilder { DifferentiabilityKind::NonDifferentiable; } - /// Get the underlying ClangTypeInfo value if it is not the default value. - Optional getClangTypeInfo() const { - return clangTypeInfo.empty() ? Optional() : clangTypeInfo; - } + /// Get the underlying ClangTypeInfo value. + ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; } constexpr bool hasSelfParam() const { switch (getRepresentation()) { @@ -608,6 +618,10 @@ class SILExtInfoBuilder { : (bits & ~NoEscapeMask), clangTypeInfo); } + SILExtInfoBuilder withAsync(bool isAsync = true) const { + return SILExtInfoBuilder(isAsync ? (bits | AsyncMask) : (bits & ~AsyncMask), + clangTypeInfo); + } SILExtInfoBuilder withDifferentiabilityKind(DifferentiabilityKind differentiability) const { return SILExtInfoBuilder( @@ -649,8 +663,8 @@ class SILExtInfo { static SILExtInfo getThin() { return SILExtInfoBuilder(SILExtInfoBuilder::Representation::Thin, false, - false, DifferentiabilityKind::NonDifferentiable, - nullptr) + false, false, + DifferentiabilityKind::NonDifferentiable, nullptr) .build(); } @@ -673,15 +687,15 @@ class SILExtInfo { constexpr bool isNoEscape() const { return builder.isNoEscape(); } + constexpr bool isAsync() const { return builder.isAsync(); } + constexpr DifferentiabilityKind getDifferentiabilityKind() const { return builder.getDifferentiabilityKind(); } constexpr bool isDifferentiable() const { return builder.isDifferentiable(); } - Optional getClangTypeInfo() const { - return builder.getClangTypeInfo(); - } + ClangTypeInfo getClangTypeInfo() const { return builder.getClangTypeInfo(); } constexpr bool hasSelfParam() const { return builder.hasSelfParam(); } diff --git a/include/swift/AST/ForeignAsyncConvention.h b/include/swift/AST/ForeignAsyncConvention.h new file mode 100644 index 0000000000000..35b6c64b6304c --- /dev/null +++ b/include/swift/AST/ForeignAsyncConvention.h @@ -0,0 +1,124 @@ +//===--- ForeignAsyncConvention.h - Async conventions -----------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines the ForeignAsyncConvention structure, which +// describes the rules for how to detect that a foreign API is asynchronous. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_FOREIGN_ASYNC_CONVENTION_H +#define SWIFT_FOREIGN_ASYNC_CONVENTION_H + +#include "swift/AST/Type.h" + +namespace swift { + +/// A small structure describing the async convention of a foreign declaration. +class ForeignAsyncConvention { +public: + struct Info { + /// The index of the completion handler parameters. + unsigned CompletionHandlerParamIndex; + + /// When non-zero, indicates which parameter to the completion handler is + /// the Error? parameter (minus one) that makes this async function also + /// throwing. + unsigned CompletionHandlerErrorParamIndex; + + Info() + : CompletionHandlerParamIndex(0), CompletionHandlerErrorParamIndex(0) { } + + Info( + unsigned completionHandlerParamIndex, + Optional completionHandlerErrorParamIndex) + : CompletionHandlerParamIndex(completionHandlerParamIndex), + CompletionHandlerErrorParamIndex( + completionHandlerErrorParamIndex + ? *completionHandlerErrorParamIndex + 1 + : 0) {} + + /// Retrieve the index of the \c Error? parameter in the completion handler's + /// parameter list. When argument passed to this parameter is non-null, the + /// provided error will be thrown by the async function. + Optional completionHandlerErrorParamIndex() const { + if (CompletionHandlerErrorParamIndex == 0) + return None; + + return CompletionHandlerErrorParamIndex - 1; + } + + /// Whether the async function is throwing due to the completion handler + /// having an \c Error? parameter. + /// + /// Equivalent to \c static_cast(completionHandlerErrorParamIndex()). + bool isThrowing() const { + return CompletionHandlerErrorParamIndex != 0; + } + }; + + /// The type of the completion handler parameter. + CanType CompletionHandlerType; + + /// Information about the async convention that can be determined from an + /// Objective-C declaration by itself. + Info TheInfo; + +public: + ForeignAsyncConvention() : TheInfo() { } + + ForeignAsyncConvention(CanType completionHandlerType, + unsigned completionHandlerParamIndex, + Optional completionHandlerErrorParamIndex) + : CompletionHandlerType(completionHandlerType), + TheInfo(completionHandlerParamIndex, completionHandlerErrorParamIndex) + { } + + /// Retrieve the type of the completion handler parameter. + CanType completionHandlerType() const { return CompletionHandlerType; } + + /// Retrieve the index of the completion handler parameter, which will be + /// erased from the Swift signature of the imported async function. + unsigned completionHandlerParamIndex() const { + return TheInfo.CompletionHandlerParamIndex; + } + + /// Retrieve the index of the \c Error? parameter in the completion handler's + /// parameter list. When argument passed to this parameter is non-null, the + /// provided error will be thrown by the async function. + Optional completionHandlerErrorParamIndex() const { + return TheInfo.completionHandlerErrorParamIndex(); + } + + /// Whether the async function is throwing due to the completion handler + /// having an \c Error? parameter. + /// + /// Equivalent to \c static_cast(completionHandlerErrorParamIndex()). + bool isThrowing() const { + return TheInfo.isThrowing(); + } + + bool operator==(ForeignAsyncConvention other) const { + return CompletionHandlerType == other.CompletionHandlerType + && TheInfo.CompletionHandlerParamIndex == + other.TheInfo.CompletionHandlerParamIndex + && TheInfo.CompletionHandlerErrorParamIndex == + other.TheInfo.CompletionHandlerErrorParamIndex; + } + + bool operator!=(ForeignAsyncConvention other) const { + return !(*this == other); + } +}; + +} + +#endif diff --git a/include/swift/AST/ForeignErrorConvention.h b/include/swift/AST/ForeignErrorConvention.h index 48d65d4612856..d09a7a80c0d86 100644 --- a/include/swift/AST/ForeignErrorConvention.h +++ b/include/swift/AST/ForeignErrorConvention.h @@ -81,6 +81,10 @@ class ForeignErrorConvention { } Info() = default; + + Kind getKind() const { + return static_cast(TheKind); + } }; private: @@ -178,11 +182,24 @@ class ForeignErrorConvention { /// Returns the physical result type of the function, for functions /// that completely erase this information. CanType getResultType() const { - assert(getKind() == ZeroResult || - getKind() == NonZeroResult); + assert(resultTypeErasedToVoid(getKind())); return ResultType; } - + + /// Whether this kind of error import erases the result type to 'Void'. + static bool resultTypeErasedToVoid(Kind kind) { + switch (kind) { + case ZeroResult: + case NonZeroResult: + return true; + + case ZeroPreservedResult: + case NilResult: + case NonNilError: + return false; + } + } + bool operator==(ForeignErrorConvention other) const { return info.TheKind == other.info.TheKind && info.ErrorIsOwned == other.info.ErrorIsOwned diff --git a/include/swift/AST/GenericEnvironment.h b/include/swift/AST/GenericEnvironment.h index 144ed20c6621e..a47067b940fa7 100644 --- a/include/swift/AST/GenericEnvironment.h +++ b/include/swift/AST/GenericEnvironment.h @@ -149,13 +149,6 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final std::pair mapConformanceRefIntoContext(Type conformingType, ProtocolConformanceRef conformance) const; - - /// Get the sugared form of a generic parameter type. - GenericTypeParamType *getSugaredType(GenericTypeParamType *type) const; - - /// Get the sugared form of a type by substituting any - /// generic parameter types by their sugared form. - Type getSugaredType(Type type) const; SubstitutionMap getForwardingSubstitutionMap() const; diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h index 6f840022dba9a..3a29d21fbd890 100644 --- a/include/swift/AST/GenericSignature.h +++ b/include/swift/AST/GenericSignature.h @@ -397,11 +397,18 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final /// /// then this will return 0 for t_0_0, 1 for t_0_1, and 2 for t_1_0. unsigned getGenericParamOrdinal(GenericTypeParamType *param) const; - + /// Get a substitution map that maps all of the generic signature's /// generic parameters to themselves. SubstitutionMap getIdentitySubstitutionMap() const; + /// Get the sugared form of a generic parameter type. + GenericTypeParamType *getSugaredType(GenericTypeParamType *type) const; + + /// Get the sugared form of a type by substituting any + /// generic parameter types by their sugared form. + Type getSugaredType(Type type) const; + /// Whether this generic signature involves a type variable. bool hasTypeVariable() const; diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index a9e0f46cb4783..37898169a6707 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -33,7 +33,6 @@ IDENTIFIER(atIndexedSubscript) IDENTIFIER_(bridgeToObjectiveC) IDENTIFIER(buildArray) IDENTIFIER(buildBlock) -IDENTIFIER(buildDo) IDENTIFIER(buildEither) IDENTIFIER(buildExpression) IDENTIFIER(buildFinalResult) diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 0a1ff8f42ba2a..5a9334a41b8f0 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -685,6 +685,12 @@ class ModuleDecl : public DeclContext, public TypeDecl { void getImportedModulesForLookup(SmallVectorImpl &imports) const; + /// Has \p module been imported via an '@_implementationOnly' import + /// instead of another kind of import? + /// + /// This assumes that \p module was imported. + bool isImportedImplementationOnly(const ModuleDecl *module) const; + /// Uniques the items in \p imports, ignoring the source locations of the /// access paths. /// diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 44cceb47af7ba..5eab3844b32d8 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -107,6 +107,9 @@ class SwiftModuleDependenciesStorage : public ModuleDependenciesStorageBase { /// The hash value that will be used for the generated module const std::string contextHash; + /// A flag that indicates this dependency is a framework + const bool isFramework; + /// Bridging header file, if there is one. Optional bridgingHeaderFile; @@ -125,7 +128,8 @@ class SwiftModuleDependenciesStorage : public ModuleDependenciesStorageBase { ArrayRef compiledModuleCandidates, ArrayRef buildCommandLine, ArrayRef extraPCMArgs, - StringRef contextHash + StringRef contextHash, + bool isFramework ) : ModuleDependenciesStorageBase(ModuleDependenciesKind::Swift, compiledModulePath), swiftInterfaceFile(swiftInterfaceFile), @@ -133,7 +137,7 @@ class SwiftModuleDependenciesStorage : public ModuleDependenciesStorageBase { compiledModuleCandidates.end()), buildCommandLine(buildCommandLine.begin(), buildCommandLine.end()), extraPCMArgs(extraPCMArgs.begin(), extraPCMArgs.end()), - contextHash(contextHash) { } + contextHash(contextHash), isFramework(isFramework) { } ModuleDependenciesStorageBase *clone() const override { return new SwiftModuleDependenciesStorage(*this); @@ -242,21 +246,22 @@ class ModuleDependencies { ArrayRef compiledCandidates, ArrayRef buildCommands, ArrayRef extraPCMArgs, - StringRef contextHash) { + StringRef contextHash, + bool isFramework) { std::string compiledModulePath; return ModuleDependencies( std::make_unique( compiledModulePath, swiftInterfaceFile, compiledCandidates, buildCommands, - extraPCMArgs, contextHash)); + extraPCMArgs, contextHash, isFramework)); } /// Describe the module dependencies for a serialized or parsed Swift module. static ModuleDependencies forSwiftModule( - const std::string &compiledModulePath) { + const std::string &compiledModulePath, bool isFramework) { return ModuleDependencies( std::make_unique( compiledModulePath, None, ArrayRef(), ArrayRef(), - ArrayRef(), StringRef())); + ArrayRef(), StringRef(), isFramework)); } /// Describe the main Swift module. @@ -265,7 +270,7 @@ class ModuleDependencies { return ModuleDependencies( std::make_unique( compiledModulePath, None, ArrayRef(), - ArrayRef(), extraPCMArgs, StringRef())); + ArrayRef(), extraPCMArgs, StringRef(), false)); } /// Describe the module dependencies for a Clang module that can be diff --git a/include/swift/AST/ModuleLoader.h b/include/swift/AST/ModuleLoader.h index 1460daf9f44c1..3660f00461f94 100644 --- a/include/swift/AST/ModuleLoader.h +++ b/include/swift/AST/ModuleLoader.h @@ -24,6 +24,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/ADT/TinyPtrVector.h" #include "swift/AST/ModuleDependencies.h" +#include namespace llvm { class FileCollector; @@ -103,17 +104,18 @@ struct SubCompilerInstanceInfo { /// Abstract interface to run an action in a sub ASTContext. struct InterfaceSubContextDelegate { - virtual bool runInSubContext(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref, - ArrayRef, StringRef)> action) = 0; - virtual bool runInSubCompilerInstance(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref action) = 0; + virtual std::error_code runInSubContext(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref, + ArrayRef, StringRef)> action) = 0; + virtual std::error_code runInSubCompilerInstance(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref action) = 0; virtual ~InterfaceSubContextDelegate() = default; }; diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index ea847ce01c1ba..3411da322aa83 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -375,7 +375,7 @@ class LambdaDeclConsumer : public VisibleDeclConsumer { public: LambdaDeclConsumer(Fn &&callback) : Callback(std::move(callback)) {} - void foundDecl(ValueDecl *VD, DeclVisibilityKind reason, DynamicLookupInfo) { + void foundDecl(ValueDecl *VD, DeclVisibilityKind reason, DynamicLookupInfo) override { Callback(VD, reason); } }; @@ -741,8 +741,6 @@ class ASTScope { return Mem; } - static bool areInactiveIfConfigClausesSupported(); - private: static ast_scope::ASTSourceFileScope *createScopeTree(SourceFile *); diff --git a/include/swift/AST/Pattern.h b/include/swift/AST/Pattern.h index 6424dd12a72f2..13630507bb3a5 100644 --- a/include/swift/AST/Pattern.h +++ b/include/swift/AST/Pattern.h @@ -554,6 +554,9 @@ class EnumElementPattern : public Pattern { bool hasUnresolvedOriginalExpr() const { return ElementDeclOrUnresolvedOriginalExpr.is(); } + void setUnresolvedOriginalExpr(Expr *e) { + ElementDeclOrUnresolvedOriginalExpr = e; + } DeclNameLoc getNameLoc() const { return NameLoc; } SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } diff --git a/include/swift/AST/PrettyStackTrace.h b/include/swift/AST/PrettyStackTrace.h index 51d047ecbb1b5..001c7609cb9f6 100644 --- a/include/swift/AST/PrettyStackTrace.h +++ b/include/swift/AST/PrettyStackTrace.h @@ -26,6 +26,7 @@ namespace clang { class Type; + class ASTContext; } namespace swift { @@ -51,7 +52,7 @@ class PrettyStackTraceLocation : public llvm::PrettyStackTraceEntry { PrettyStackTraceLocation(const ASTContext &C, const char *action, SourceLoc loc) : Context(C), Loc(loc), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printDeclDescription(llvm::raw_ostream &out, const Decl *D, @@ -65,7 +66,7 @@ class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceDecl(const char *action, const Decl *D) : TheDecl(D), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; /// PrettyStackTraceAnyFunctionRef - Observe that we are processing a specific @@ -76,7 +77,7 @@ class PrettyStackTraceAnyFunctionRef : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceAnyFunctionRef(const char *action, AnyFunctionRef ref) : TheRef(ref), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printExprDescription(llvm::raw_ostream &out, Expr *E, @@ -91,7 +92,7 @@ class PrettyStackTraceExpr : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceExpr(const ASTContext &C, const char *action, Expr *E) : Context(C), TheExpr(E), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printStmtDescription(llvm::raw_ostream &out, Stmt *S, @@ -106,7 +107,7 @@ class PrettyStackTraceStmt : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceStmt(const ASTContext &C, const char *action, Stmt *S) : Context(C), TheStmt(S), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printPatternDescription(llvm::raw_ostream &out, Pattern *P, @@ -121,7 +122,7 @@ class PrettyStackTracePattern : public llvm::PrettyStackTraceEntry { public: PrettyStackTracePattern(const ASTContext &C, const char *action, Pattern *P) : Context(C), ThePattern(P), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printTypeDescription(llvm::raw_ostream &out, Type T, @@ -135,18 +136,20 @@ class PrettyStackTraceType : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceType(const ASTContext &C, const char *action, Type type) : Context(C), TheType(type), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; /// PrettyStackTraceClangType - Observe that we are processing a /// specific Clang type. class PrettyStackTraceClangType : public llvm::PrettyStackTraceEntry { + const clang::ASTContext &Context; const clang::Type *TheType; const char *Action; public: - PrettyStackTraceClangType(const char *action, const clang::Type *type) - : TheType(type), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + PrettyStackTraceClangType(clang::ASTContext &ctx, + const char *action, const clang::Type *type) + : Context(ctx), TheType(type), Action(action) {} + virtual void print(llvm::raw_ostream &OS) const override; }; /// Observe that we are processing a specific type representation. @@ -158,7 +161,7 @@ class PrettyStackTraceTypeRepr : public llvm::PrettyStackTraceEntry { PrettyStackTraceTypeRepr(const ASTContext &C, const char *action, TypeRepr *type) : Context(C), TheType(type), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; /// PrettyStackTraceConformance - Observe that we are processing a @@ -171,7 +174,7 @@ class PrettyStackTraceConformance : public llvm::PrettyStackTraceEntry { PrettyStackTraceConformance(const ASTContext &C, const char *action, const ProtocolConformance *conformance) : Context(C), Conformance(conformance), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printConformanceDescription(llvm::raw_ostream &out, @@ -217,7 +220,7 @@ class PrettyStackTraceDifferentiabilityWitness PrettyStackTraceDifferentiabilityWitness( const char *action, const SILDifferentiabilityWitnessKey key) : Key(key), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printDifferentiabilityWitnessDescription( @@ -232,7 +235,7 @@ class PrettyStackTraceDeclContext : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceDeclContext(const char *action, const DeclContext *DC) : DC(DC), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; } // end namespace swift diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index 38611e1245b56..2b99e4ac1e66b 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -24,7 +24,7 @@ namespace swift { class ASTPrinter; -class GenericEnvironment; +class GenericSignatureImpl; class CanType; class Decl; class Pattern; @@ -380,10 +380,13 @@ struct PrintOptions { /// has no associated doc-comment by itself. bool CascadeDocComment = false; + static const std::function + defaultPrintExtensionContentAsMembers; + /// Whether to print the content of an extension decl inside the type decl where it /// extends from. std::function printExtensionContentAsMembers = - [] (const ExtensionDecl *) { return false; }; + PrintOptions::defaultPrintExtensionContentAsMembers; /// How to print the keyword argument and parameter name in functions. ArgAndParamPrintingMode ArgAndParamPrinting = @@ -423,8 +426,8 @@ struct PrintOptions { /// Replaces the name of private and internal properties of types with '_'. bool OmitNameOfInaccessibleProperties = false; - /// Print dependent types as references into this generic environment. - GenericEnvironment *GenericEnv = nullptr; + /// Use this signature to re-sugar dependent types. + const GenericSignatureImpl *GenericSig = nullptr; /// Print types with alternative names from their canonical names. llvm::DenseMap *AlternativeTypeNames = nullptr; diff --git a/include/swift/AST/PropertyWrappers.h b/include/swift/AST/PropertyWrappers.h index f1a1b57490234..2f78ad4123d76 100644 --- a/include/swift/AST/PropertyWrappers.h +++ b/include/swift/AST/PropertyWrappers.h @@ -145,9 +145,9 @@ struct PropertyWrapperBackingPropertyInfo { /// The backing property. VarDecl *backingVar = nullptr; - /// The storage wrapper property, if any. When present, this takes the name - /// '$foo' from `backingVar`. - VarDecl *storageWrapperVar = nullptr; + /// The synthesized projection property, if any. When present, this takes the name + /// of the original wrapped property prefixed with \c $ + VarDecl *projectionVar = nullptr; /// An expression that initializes the backing property from a value of /// the original property's type (e.g., via `init(wrappedValue:)`), or @@ -161,10 +161,10 @@ struct PropertyWrapperBackingPropertyInfo { PropertyWrapperBackingPropertyInfo() { } PropertyWrapperBackingPropertyInfo(VarDecl *backingVar, - VarDecl *storageWrapperVar, + VarDecl *projectionVar, Expr *initializeFromOriginal, PropertyWrapperValuePlaceholderExpr *placeholder) - : backingVar(backingVar), storageWrapperVar(storageWrapperVar), + : backingVar(backingVar), projectionVar(projectionVar), initializeFromOriginal(initializeFromOriginal), wrappedValuePlaceholder(placeholder) { } diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h index 1136fb5be73cd..1f61cdf438175 100644 --- a/include/swift/AST/ProtocolConformance.h +++ b/include/swift/AST/ProtocolConformance.h @@ -465,21 +465,22 @@ class NormalProtocolConformance : public RootProtocolConformance, uint64_t LoaderContextData; friend class ASTContext; + void resolveLazyInfo() const; + + void differenceAndStoreConditionalRequirements() const; + +public: NormalProtocolConformance(Type conformingType, ProtocolDecl *protocol, SourceLoc loc, DeclContext *dc, ProtocolConformanceState state) - : RootProtocolConformance(ProtocolConformanceKind::Normal, conformingType), - ProtocolAndState(protocol, state), Loc(loc), ContextAndInvalid(dc, false) - { + : RootProtocolConformance(ProtocolConformanceKind::Normal, + conformingType), + ProtocolAndState(protocol, state), Loc(loc), + ContextAndInvalid(dc, false) { assert(!conformingType->hasArchetype() && "ProtocolConformances should store interface types"); } - void resolveLazyInfo() const; - - void differenceAndStoreConditionalRequirements() const; - -public: /// Get the protocol being conformed to. ProtocolDecl *getProtocol() const { return ProtocolAndState.getPointer(); } diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index af8d8c29f2c69..5eaac7a1cf721 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -128,6 +128,11 @@ class SILOptions { /// Assume that code will be executed in a single-threaded environment. bool AssumeSingleThreaded = false; + /// Turn @inline(__always) attributes into no-ops. + /// + /// For experimentation around code size reduction. + bool IgnoreAlwaysInline = false; + /// Indicates which sanitizer is turned on. OptionSet Sanitizers; diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index 08757ffd796de..52eeace6a1460 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -93,6 +93,9 @@ class SearchPathOptions { /// A map of placeholder Swift module dependency information. std::string PlaceholderDependencyModuleMap; + + /// A file containing modules we should perform batch scanning. + std::string BatchScanInputFilePath; private: static StringRef pathStringFromFrameworkSearchPath(const FrameworkSearchPath &next) { diff --git a/include/swift/AST/SimpleRequest.h b/include/swift/AST/SimpleRequest.h index 42751e142682c..d59c61618079e 100644 --- a/include/swift/AST/SimpleRequest.h +++ b/include/swift/AST/SimpleRequest.h @@ -24,6 +24,7 @@ #include "swift/Basic/TypeID.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Error.h" #include #include diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index ca305f8675db8..5fc32b5983f94 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -172,7 +172,7 @@ class SourceFile final : public FileUnit { bool IsPrimary; /// The scope map that describes this source file. - std::unique_ptr Scope; + NullablePtr Scope = nullptr; /// The set of validated opaque return type decls in the source file. llvm::SmallVector OpaqueReturnTypes; @@ -187,6 +187,10 @@ class SourceFile final : public FileUnit { /// have been removed, this can become an optional ArrayRef. Optional> Decls; + /// The list of hoisted declarations. See Decl::isHoisted(). + /// This is only used by lldb. + std::vector Hoisted; + using SeparatelyImportedOverlayMap = llvm::SmallDenseMap>; @@ -231,9 +235,16 @@ class SourceFile final : public FileUnit { Decls->insert(Decls->begin(), d); } + /// Add a hoisted declaration. See Decl::isHoisted(). + void addHoistedDecl(Decl *d); + /// Retrieves an immutable view of the list of top-level decls in this file. ArrayRef getTopLevelDecls() const; + /// Retrieves an immutable view of the list of hoisted decls in this file. + /// See Decl::isHoisted(). + ArrayRef getHoistedDecls() const; + /// Retrieves an immutable view of the top-level decls if they have already /// been parsed, or \c None if they haven't. Should only be used for dumping. Optional> getCachedTopLevelDecls() const { @@ -468,6 +479,10 @@ class SourceFile final : public FileUnit { /// Retrieve the scope that describes this source file. ASTScope &getScope(); + void clearScope() { + Scope = nullptr; + } + /// Retrieves the previously set delayed parser state, asserting that it /// exists. PersistentParserState *getDelayedParserState() { @@ -688,9 +703,11 @@ struct DenseMapInfo { StringRefDMI::getTombstoneKey()); } static inline unsigned getHashValue(const ImportedModuleDesc &import) { - return combineHashValue(ImportedModuleDMI::getHashValue(import.module), - combineHashValue(ImportOptionsDMI::getHashValue(import.importOptions), - StringRefDMI::getHashValue(import.filename))); + return detail::combineHashValue( + ImportedModuleDMI::getHashValue(import.module), + detail::combineHashValue( + ImportOptionsDMI::getHashValue(import.importOptions), + StringRefDMI::getHashValue(import.filename))); } static bool isEqual(const ImportedModuleDesc &a, const ImportedModuleDesc &b) { diff --git a/include/swift/AST/TBDGenRequests.h b/include/swift/AST/TBDGenRequests.h index 66ac0ef814e04..413f79b326568 100644 --- a/include/swift/AST/TBDGenRequests.h +++ b/include/swift/AST/TBDGenRequests.h @@ -19,6 +19,9 @@ #include "swift/AST/ASTTypeIDs.h" #include "swift/AST/SimpleRequest.h" +#include "swift/IRGen/Linking.h" +#include "swift/SIL/SILDeclRef.h" +#include "swift/TBDGen/TBDGen.h" namespace llvm { @@ -37,12 +40,11 @@ namespace swift { class FileUnit; class ModuleDecl; -struct TBDGenOptions; class TBDGenDescriptor final { using FileOrModule = llvm::PointerUnion; FileOrModule Input; - const TBDGenOptions &Opts; + TBDGenOptions Opts; TBDGenDescriptor(FileOrModule input, const TBDGenOptions &opts) : Input(input), Opts(opts) { @@ -62,6 +64,7 @@ class TBDGenDescriptor final { /// Returns the TBDGen options. const TBDGenOptions &getOptions() const { return Opts; } + TBDGenOptions &getOptions() { return Opts; } const llvm::DataLayout &getDataLayout() const; const llvm::Triple &getTarget() const; @@ -117,6 +120,123 @@ class PublicSymbolsRequest evaluate(Evaluator &evaluator, TBDGenDescriptor desc) const; }; +/// Describes the origin of a particular symbol, including the stage of +/// compilation it is introduced, as well as information on what decl introduces +/// it. +class SymbolSource { +public: + enum class Kind { + /// A symbol introduced when emitting a SIL decl. + SIL, + + /// A symbol introduced when emitting LLVM IR. + IR, + + /// A symbol used to customize linker behavior, introduced by TBDGen. + LinkerDirective, + + /// A symbol with an unknown origin. + // FIXME: This should be eliminated. + Unknown + }; + Kind kind; + +private: + union { + SILDeclRef silDeclRef; + irgen::LinkEntity irEntity; + }; + + explicit SymbolSource(SILDeclRef ref) : kind(Kind::SIL) { + silDeclRef = ref; + } + explicit SymbolSource(irgen::LinkEntity entity) : kind(Kind::IR) { + irEntity = entity; + } + explicit SymbolSource(Kind kind) : kind(kind) { + assert(kind == Kind::LinkerDirective || kind == Kind::Unknown); + } + +public: + static SymbolSource forSILDeclRef(SILDeclRef ref) { + return SymbolSource{ref}; + } + static SymbolSource forIRLinkEntity(irgen::LinkEntity entity) { + return SymbolSource{entity}; + } + static SymbolSource forLinkerDirective() { + return SymbolSource{Kind::LinkerDirective}; + } + static SymbolSource forUnknown() { + return SymbolSource{Kind::Unknown}; + } + + bool isLinkerDirective() const { + return kind == Kind::LinkerDirective; + } + + SILDeclRef getSILDeclRef() const { + assert(kind == Kind::SIL); + return silDeclRef; + } + irgen::LinkEntity getIRLinkEntity() const { + assert(kind == Kind::IR); + return irEntity; + } +}; + +/// Maps a symbol back to its source for lazy compilation. +class SymbolSourceMap { + friend class SymbolSourceMapRequest; + + using Storage = llvm::StringMap; + const Storage *storage; + + explicit SymbolSourceMap(const Storage *storage) : storage(storage) { + assert(storage); + } + +public: + Optional find(StringRef symbol) const { + auto result = storage->find(symbol); + if (result == storage->end()) + return None; + return result->second; + } + + friend bool operator==(const SymbolSourceMap &lhs, + const SymbolSourceMap &rhs) { + return lhs.storage == rhs.storage; + } + friend bool operator!=(const SymbolSourceMap &lhs, + const SymbolSourceMap &rhs) { + return !(lhs == rhs); + } + + friend void simple_display(llvm::raw_ostream &out, const SymbolSourceMap &) { + out << "(symbol storage map)"; + } +}; + +/// Computes a map of symbols to their SymbolSource for a file or module. +class SymbolSourceMapRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + SymbolSourceMap evaluate(Evaluator &evaluator, TBDGenDescriptor desc) const; + +public: + // Cached. + bool isCached() const { return true; } +}; + /// Report that a request of the given kind is being evaluated, so it /// can be recorded by the stats reporter. template diff --git a/include/swift/AST/TBDGenTypeIDZone.def b/include/swift/AST/TBDGenTypeIDZone.def index b175b8ac19bd3..71eb7ad25a68a 100644 --- a/include/swift/AST/TBDGenTypeIDZone.def +++ b/include/swift/AST/TBDGenTypeIDZone.def @@ -19,3 +19,6 @@ SWIFT_REQUEST(TBDGen, GenerateTBDRequest, TBDFile(TBDGenDescriptor), SWIFT_REQUEST(TBDGen, PublicSymbolsRequest, std::vector(TBDGenDescriptor), Uncached, NoLocationInfo) +SWIFT_REQUEST(TBDGen, SymbolSourceMapRequest, + SymbolSourceMap(TBDGenDescriptor), + Cached, NoLocationInfo) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index f067218db105e..8e03a00338a45 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -781,6 +781,24 @@ class SelfAccessKindRequest : void cacheResult(SelfAccessKind value) const; }; +/// Determine whether the given function is an @asyncHandler. +class IsAsyncHandlerRequest : + public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + bool evaluate(Evaluator &evaluator, FuncDecl *func) const; + +public: + // Caching + bool isCached() const { return true; } +}; + /// Request whether the storage has a mutating getter. class IsGetterMutatingRequest : public SimpleRequest(ClassDecl *), +class SemanticMembersRequest : + public SimpleRequest(IterableDeclContext *), RequestFlags::Cached> { public: using SimpleRequest::SimpleRequest; @@ -1074,7 +1092,7 @@ class EmittedMembersRequest : // Evaluation. ArrayRef - evaluate(Evaluator &evaluator, ClassDecl *classDecl) const; + evaluate(Evaluator &evaluator, IterableDeclContext *idc) const; public: bool isCached() const { return true; } @@ -1431,8 +1449,6 @@ class ResultTypeRequest private: friend SimpleRequest; - TypeLoc &getResultTypeLoc() const; - // Evaluation. Type evaluate(Evaluator &evaluator, ValueDecl *decl) const; @@ -1825,6 +1841,7 @@ class ValueWitnessRequest struct PreCheckFunctionBuilderDescriptor { AnyFunctionRef Fn; + bool SuppressDiagnostics; private: // NOTE: Since source tooling (e.g. code completion) might replace the body, @@ -1834,8 +1851,8 @@ struct PreCheckFunctionBuilderDescriptor { BraceStmt *Body; public: - PreCheckFunctionBuilderDescriptor(AnyFunctionRef Fn) - : Fn(Fn), Body(Fn.getBody()) {} + PreCheckFunctionBuilderDescriptor(AnyFunctionRef Fn, bool suppressDiagnostics) + : Fn(Fn), SuppressDiagnostics(suppressDiagnostics), Body(Fn.getBody()) {} friend llvm::hash_code hash_value(const PreCheckFunctionBuilderDescriptor &owner) { diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 0252352960631..bcc4148926da7 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -65,8 +65,8 @@ SWIFT_REQUEST(TypeChecker, TypeEraserHasViableInitRequest, SWIFT_REQUEST(TypeChecker, DynamicallyReplacedDeclRequest, ValueDecl *(ValueDecl *), Cached, NoLocationInfo) -SWIFT_REQUEST(TypeChecker, EmittedMembersRequest, ArrayRef(ClassDecl *), - Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, SemanticMembersRequest, + ArrayRef(IterableDeclContext *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, EnumRawValuesRequest, evaluator::SideEffect (EnumDecl *, TypeResolutionStage), SeparatelyCached, NoLocationInfo) @@ -81,6 +81,8 @@ SWIFT_REQUEST(TypeChecker, ExtendedTypeRequest, Type(ExtensionDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, FunctionBuilderTypeRequest, Type(ValueDecl *), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, IsAsyncHandlerRequest, bool(FuncDecl *), + Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, FunctionOperatorRequest, OperatorDecl *(FuncDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(NameLookup, GenericSignatureRequest, diff --git a/include/swift/AST/TypeLoc.h b/include/swift/AST/TypeLoc.h index 2f8007dda9900..9cdab2c61be43 100644 --- a/include/swift/AST/TypeLoc.h +++ b/include/swift/AST/TypeLoc.h @@ -62,7 +62,6 @@ class alignas(1 << TypeReprAlignInBits) TypeLoc final { bool isNull() const { return getType().isNull() && TyR == nullptr; } - void setInvalidType(ASTContext &C); void setType(Type Ty); friend llvm::hash_code hash_value(const TypeLoc &owner) { diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index b04f82bb9a8de..f827339dd5064 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -89,6 +89,7 @@ TYPE(Error, Type) UNCHECKED_TYPE(Unresolved, Type) +UNCHECKED_TYPE(Hole, Type) ABSTRACT_TYPE(Builtin, Type) ABSTRACT_TYPE(AnyBuiltinInteger, BuiltinType) BUILTIN_TYPE(BuiltinInteger, AnyBuiltinIntegerType) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 0f911f4fb5ae4..328f4c0aff762 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -148,7 +148,10 @@ class RecursiveTypeProperties { /// This type contains an OpaqueTypeArchetype. HasOpaqueArchetype = 0x400, - Last_Property = HasOpaqueArchetype + /// This type contains a type hole. + HasTypeHole = 0x800, + + Last_Property = HasTypeHole }; enum { BitWidth = countBitsUsed(Property::Last_Property) }; @@ -203,6 +206,10 @@ class RecursiveTypeProperties { /// generic type? bool hasUnboundGeneric() const { return Bits & HasUnboundGeneric; } + /// Does a type with these properties structurally contain a + /// type hole? + bool hasTypeHole() const { return Bits & HasTypeHole; } + /// Returns the set of properties present in either set. friend RecursiveTypeProperties operator|(Property lhs, Property rhs) { return RecursiveTypeProperties(unsigned(lhs) | unsigned(rhs)); @@ -308,7 +315,7 @@ class alignas(1 << TypeAlignInBits) TypeBase { protected: enum { NumAFTExtInfoBits = 9 }; - enum { NumSILExtInfoBits = 8 }; + enum { NumSILExtInfoBits = 9 }; union { uint64_t OpaqueBits; SWIFT_INLINE_BITFIELD_BASE(TypeBase, bitmax(NumTypeKindBits,8) + @@ -573,9 +580,7 @@ class alignas(1 << TypeAlignInBits) TypeBase { } /// Determine whether this type involves a hole. - bool hasHole() const { - return getRecursiveProperties().hasUnresolvedType(); - } + bool hasHole() const { return getRecursiveProperties().hasTypeHole(); } /// Determine whether the type involves a context-dependent archetype. bool hasArchetype() const { @@ -2872,7 +2877,7 @@ class AnyFunctionType : public TypeBase { unsigned NumParams, ExtInfo Info) : TypeBase(Kind, CanTypeContext, properties), Output(Output) { Bits.AnyFunctionType.ExtInfoBits = Info.getBits(); - Bits.AnyFunctionType.HasClangTypeInfo = Info.getClangTypeInfo().hasValue(); + Bits.AnyFunctionType.HasClangTypeInfo = !Info.getClangTypeInfo().empty(); Bits.AnyFunctionType.NumParams = NumParams; assert(Bits.AnyFunctionType.NumParams == NumParams && "Params dropped!"); // The use of both assert() and static_assert() is intentional. @@ -4046,6 +4051,8 @@ class SILFunctionType final return SILCoroutineKind(Bits.SILFunctionType.CoroutineKind); } + bool isAsync() const { return getExtInfo().isAsync(); } + /// Return the array of all the yields. ArrayRef getYields() const { return const_cast(this)->getMutableYields(); @@ -5724,6 +5731,31 @@ TypeVariableType : public TypeBase { }; DEFINE_EMPTY_CAN_TYPE_WRAPPER(TypeVariableType, Type) +/// HoleType - This represents a placeholder type for a type variable +/// or dependent member type that cannot be resolved to a concrete type +/// because the expression is ambiguous. This type is only used by the +/// constraint solver and transformed into UnresolvedType to be used in AST. +class HoleType : public TypeBase { + using OriginatorType = + llvm::PointerUnion; + + OriginatorType Originator; + + HoleType(ASTContext &C, OriginatorType originator, + RecursiveTypeProperties properties) + : TypeBase(TypeKind::Hole, &C, properties), Originator(originator) {} + +public: + static Type get(ASTContext &ctx, OriginatorType originatorType); + + OriginatorType getOriginatorType() const { return Originator; } + + static bool classof(const TypeBase *T) { + return T->getKind() == TypeKind::Hole; + } +}; +DEFINE_EMPTY_CAN_TYPE_WRAPPER(HoleType, Type) + inline bool TypeBase::isTypeVariableOrMember() { if (is()) return true; diff --git a/include/swift/Basic/FileTypes.def b/include/swift/Basic/FileTypes.def index 1435813ae6e6c..2a051381ec0fe 100644 --- a/include/swift/Basic/FileTypes.def +++ b/include/swift/Basic/FileTypes.def @@ -51,6 +51,7 @@ TYPE("swiftmodule", SwiftModuleFile, "swiftmodule", "") TYPE("swiftdoc", SwiftModuleDocFile, "swiftdoc", "") TYPE("swiftinterface", SwiftModuleInterfaceFile, "swiftinterface", "") TYPE("private-swiftinterface", PrivateSwiftModuleInterfaceFile, "private.swiftinterface", "") +TYPE("swiftmodulesummary", SwiftModuleSummaryFile, "swiftmodulesummary", "") TYPE("swiftsourceinfo", SwiftSourceInfoFile, "swiftsourceinfo", "") TYPE("assembly", Assembly, "s", "") TYPE("raw-sil", RawSIL, "sil", "") diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 6531ecdf0e5c8..6810676539819 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -248,28 +248,12 @@ namespace swift { /// This is a staging flag; eventually it will be removed. bool EnableDeserializationRecovery = true; - /// Should we use \c ASTScope-based resolution for unqualified name lookup? - /// Default is in \c ParseLangArgs - /// - /// This is a staging flag; eventually it will be removed. - bool EnableASTScopeLookup = true; - /// Someday, ASTScopeLookup will supplant lookup in the parser bool DisableParserLookup = false; - /// Should we compare to ASTScope-based resolution for debugging? - bool CrosscheckUnqualifiedLookup = false; - /// Should we stress ASTScope-based resolution for debugging? bool StressASTScopeLookup = false; - /// Since some tests fail if the warning is output, use a flag to decide - /// whether it is. The warning is useful for testing. - bool WarnIfASTScopeLookup = false; - - /// Build the ASTScope tree lazily - bool LazyASTScopes = true; - /// Whether to enable the new operator decl and precedencegroup lookup /// behavior. This is a staging flag, and will be removed in the future. bool EnableNewOperatorLookup = false; @@ -577,6 +561,115 @@ namespace swift { /// parameters of closures. bool EnableOneWayClosureParameters = false; }; + + /// Options for controlling the behavior of the Clang importer. + class ClangImporterOptions final { + public: + /// The module cache path which the Clang importer should use. + std::string ModuleCachePath; + + /// Extra arguments which should be passed to the Clang importer. + std::vector ExtraArgs; + + /// A directory for overriding Clang's resource directory. + std::string OverrideResourceDir; + + /// The target CPU to compile for. + /// + /// Equivalent to Clang's -mcpu=. + std::string TargetCPU; + + /// The path to which we should store indexing data, if any. + std::string IndexStorePath; + + /// The bridging header or PCH that will be imported. + std::string BridgingHeader; + + /// When automatically generating a precompiled header from the bridging + /// header, place it in this directory. + std::string PrecompiledHeaderOutputDir; + + /// The optimizaton setting. This doesn't typically matter for + /// import, but it can affect Clang's IR generation of static functions. + std::string Optimization; + + /// Disable validating the persistent PCH. + bool PCHDisableValidation = false; + + /// \see Mode + enum class Modes : uint8_t { + /// Set up Clang for importing modules into Swift and generating IR from + /// Swift code. + Normal, + /// Set up Clang for backend compilation only. + EmbedBitcode, + /// Set up Clang to emit a precompiled module from a C/Objective-C module + /// map or dump debugging info about a precompiled module. + PrecompiledModule + }; + + /// Controls how Clang is initially set up. + Modes Mode = Modes::Normal; + + /// When set, preserves more information during import. + /// + /// Also \em disables some information that is only needed for object file + /// generation. + bool DetailedPreprocessingRecord = false; + + /// If true, Clang diagnostics will be dumped to stderr using Clang's + /// diagnostic printer as well as being passed to Swift's diagnostic engine. + bool DumpClangDiagnostics = false; + + /// If true, forward declarations will be imported using unavailable types + /// instead of dropped altogether when possible. + bool ImportForwardDeclarations = false; + + /// Whether to use the import as member inference system + /// + /// When importing a global, try to infer whether we can import it as a + /// member of some type instead. This includes inits, computed properties, + /// and methods. + bool InferImportAsMember = false; + + /// If true ignore the swift bridged attribute. + bool DisableSwiftBridgeAttr = false; + + /// When set, don't look for or load overlays. + bool DisableOverlayModules = false; + + /// When set, don't enforce warnings with -Werror. + bool DebuggerSupport = false; + + /// When set, ClangImporter is disabled, and all requests go to the + /// DWARFImporter delegate. + bool DisableSourceImport = false; + + /// When set, use ExtraArgs alone to configure clang instance because ExtraArgs + /// contains the full option set. + bool ExtraArgsOnly = false; + + /// Return a hash code of any components from these options that should + /// contribute to a Swift Bridging PCH hash. + llvm::hash_code getPCHHashComponents() const { + using llvm::hash_combine; + using llvm::hash_combine_range; + + return hash_combine(ModuleCachePath, + hash_combine_range(ExtraArgs.begin(), ExtraArgs.end()), + OverrideResourceDir, + TargetCPU, + BridgingHeader, + PrecompiledHeaderOutputDir, + static_cast(Mode), + DetailedPreprocessingRecord, + ImportForwardDeclarations, + InferImportAsMember, + DisableSwiftBridgeAttr, + DisableOverlayModules); + } + }; + } // end namespace swift #endif // SWIFT_BASIC_LANGOPTIONS_H diff --git a/include/swift/Basic/Lazy.h b/include/swift/Basic/Lazy.h index 521227f4db231..87eecbe295c3c 100644 --- a/include/swift/Basic/Lazy.h +++ b/include/swift/Basic/Lazy.h @@ -14,7 +14,9 @@ #define SWIFT_BASIC_LAZY_H #include -#ifdef __APPLE__ +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +// No dependencies on single-threaded environments. +#elif defined(__APPLE__) #include #elif defined(__wasi__) // No pthread on wasi, see https://bugs.swift.org/browse/SR-12097 for more details. @@ -44,7 +46,11 @@ inline void wasi_call_once(int *flag, void *context, void (*func)(void *)) { namespace swift { -#ifdef __APPLE__ +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + using OnceToken_t = bool; +# define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ + if (!TOKEN) { TOKEN = true; (FUNC)(CONTEXT); } +#elif defined(__APPLE__) using OnceToken_t = dispatch_once_t; # define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ ::dispatch_once_f(&TOKEN, CONTEXT, FUNC) diff --git a/include/swift/Basic/Platform.h b/include/swift/Basic/Platform.h index 2595b68af0b34..fecd96b91e10c 100644 --- a/include/swift/Basic/Platform.h +++ b/include/swift/Basic/Platform.h @@ -106,6 +106,13 @@ namespace swift { /// Retrieve the target SDK version for the given SDKInfo and target triple. llvm::VersionTuple getTargetSDKVersion(clang::driver::DarwinSDKInfo &SDKInfo, const llvm::Triple &triple); + + /// Get SDK build version. + std::string getSDKBuildVersion(StringRef SDKPath); + std::string getSDKBuildVersionFromPlist(StringRef Path); + + /// Get SDK name. + std::string getSDKName(StringRef SDKPath); } // end namespace swift #endif // SWIFT_BASIC_PLATFORM_H diff --git a/include/swift/Basic/PrimarySpecificPaths.h b/include/swift/Basic/PrimarySpecificPaths.h index 1e73810ed61c1..f21ec9e46e9fb 100644 --- a/include/swift/Basic/PrimarySpecificPaths.h +++ b/include/swift/Basic/PrimarySpecificPaths.h @@ -49,6 +49,9 @@ class PrimarySpecificPaths { return !SupplementaryOutputs.ModuleOutputPath.empty() || !SupplementaryOutputs.ModuleDocOutputPath.empty(); } + bool haveModuleSummaryOutputPath() const { + return !SupplementaryOutputs.ModuleSummaryOutputPath.empty(); + } }; } // namespace swift diff --git a/include/swift/Basic/STLExtras.h b/include/swift/Basic/STLExtras.h index fa06044937165..21d2993bbaa90 100644 --- a/include/swift/Basic/STLExtras.h +++ b/include/swift/Basic/STLExtras.h @@ -69,51 +69,6 @@ struct function_traits { using argument_types = std::tuple; }; -} // end namespace swift - -#if !defined(swiftCore_EXPORTS) -namespace llvm { - -/// @{ - -/// An STL-style algorithm similar to std::for_each that applies a second -/// functor between every pair of elements. -/// -/// This provides the control flow logic to, for example, print a -/// comma-separated list: -/// \code -/// interleave(names.begin(), names.end(), -/// [&](StringRef name) { OS << name; }, -/// [&] { OS << ", "; }); -/// \endcode -template -inline void interleave(ForwardIterator begin, ForwardIterator end, - UnaryFunctor each_fn, - NullaryFunctor between_fn) { - if (begin == end) - return; - each_fn(*begin); - ++begin; - for (; begin != end; ++begin) { - between_fn(); - each_fn(*begin); - } -} - -template -inline void interleave(const Container &c, UnaryFunctor each_fn, - NullaryFunctor between_fn) { - interleave(c.begin(), c.end(), each_fn, between_fn); -} - -/// @} - -} // end namespace llvm -#endif - -namespace swift { - /// @{ /// The equivalent of std::for_each, but for two lists at once. diff --git a/include/swift/Basic/SourceManager.h b/include/swift/Basic/SourceManager.h index e26e44e78cef9..a12aa169f7c51 100644 --- a/include/swift/Basic/SourceManager.h +++ b/include/swift/Basic/SourceManager.h @@ -38,6 +38,20 @@ class SourceManager { /// to speed up stats. mutable llvm::DenseMap StatusCache; + struct ReplacedRangeType { + SourceRange Original; + SourceRange New; + ReplacedRangeType() {} + ReplacedRangeType(NoneType) {} + ReplacedRangeType(SourceRange Original, SourceRange New) + : Original(Original), New(New) { + assert(Original.isValid() && New.isValid()); + } + + explicit operator bool() const { return Original.isValid(); } + }; + ReplacedRangeType ReplacedRange; + // \c #sourceLocation directive handling. struct VirtualFile { CharSourceRange Range; @@ -89,6 +103,9 @@ class SourceManager { SourceLoc getCodeCompletionLoc() const; + const ReplacedRangeType &getReplacedRange() const { return ReplacedRange; } + void setReplacedRange(const ReplacedRangeType &val) { ReplacedRange = val; } + /// Returns true if \c LHS is before \c RHS in the source buffer. bool isBeforeInBuffer(SourceLoc LHS, SourceLoc RHS) const { return LHS.Value.getPointer() < RHS.Value.getPointer(); diff --git a/include/swift/Basic/SupplementaryOutputPaths.h b/include/swift/Basic/SupplementaryOutputPaths.h index c1d0494a95891..3649d4dbe7ae3 100644 --- a/include/swift/Basic/SupplementaryOutputPaths.h +++ b/include/swift/Basic/SupplementaryOutputPaths.h @@ -165,6 +165,9 @@ struct SupplementaryOutputPaths { /// name per symbol, we should eventually remove this. std::string LdAddCFilePath; + /// The path to which we should emit module summary file. + std::string ModuleSummaryOutputPath; + SupplementaryOutputPaths() = default; SupplementaryOutputPaths(const SupplementaryOutputPaths &) = default; diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 128886f6c0bed..42896fd21b190 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -115,7 +115,7 @@ class ClangImporter final : public ClangModuleLoader { private: Implementation &Impl; - ClangImporter(ASTContext &ctx, const ClangImporterOptions &clangImporterOpts, + ClangImporter(ASTContext &ctx, DependencyTracker *tracker, DWARFImporterDelegate *dwarfImporterDelegate); @@ -137,8 +137,6 @@ class ClangImporter final : public ClangModuleLoader { /// \param ctx The ASTContext into which the module will be imported. /// The ASTContext's SearchPathOptions will be used for the Clang importer. /// - /// \param importerOpts The options to use for the Clang importer. - /// /// \param swiftPCHHash A hash of Swift's various options in a compiler /// invocation, used to create a unique Bridging PCH if requested. /// @@ -150,12 +148,12 @@ class ClangImporter final : public ClangModuleLoader { /// \returns a new Clang module importer, or null (with a diagnostic) if /// an error occurred. static std::unique_ptr - create(ASTContext &ctx, const ClangImporterOptions &importerOpts, + create(ASTContext &ctx, std::string swiftPCHHash = "", DependencyTracker *tracker = nullptr, DWARFImporterDelegate *dwarfImporterDelegate = nullptr); static std::vector - getClangArguments(ASTContext &ctx, const ClangImporterOptions &importerOpts); + getClangArguments(ASTContext &ctx); static std::unique_ptr createClangInvocation(ClangImporter *importer, @@ -378,6 +376,7 @@ class ClangImporter final : public ClangModuleLoader { /// construction of the replica. bool dumpPrecompiledModule(StringRef modulePath, StringRef outputPath); + bool runPreprocessor(StringRef inputPath, StringRef outputPath); const clang::Module *getClangOwningModule(ClangNode Node) const; bool hasTypedef(const clang::Decl *typeDecl) const; @@ -473,7 +472,6 @@ class ClangImporter final : public ClangModuleLoader { bool isSerializable(const clang::Type *type, bool checkCanonical) const override; - ArrayRef getExtraClangArgs() const; }; ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN, diff --git a/include/swift/ClangImporter/ClangImporterOptions.h b/include/swift/ClangImporter/ClangImporterOptions.h deleted file mode 100644 index 173abc210f560..0000000000000 --- a/include/swift/ClangImporter/ClangImporterOptions.h +++ /dev/null @@ -1,133 +0,0 @@ -//===--- ClangImporterOptions.h ---------------------------------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_CLANGIMPORTER_CLANGIMPORTEROPTIONS_H -#define SWIFT_CLANGIMPORTER_CLANGIMPORTEROPTIONS_H - -#include "llvm/ADT/Hashing.h" - -#include -#include - -namespace swift { - -/// Options for controlling the behavior of the Clang importer. -class ClangImporterOptions { -public: - /// The module cache path which the Clang importer should use. - std::string ModuleCachePath; - - /// Extra arguments which should be passed to the Clang importer. - std::vector ExtraArgs; - - /// A directory for overriding Clang's resource directory. - std::string OverrideResourceDir; - - /// The target CPU to compile for. - /// - /// Equivalent to Clang's -mcpu=. - std::string TargetCPU; - - /// The path to which we should store indexing data, if any. - std::string IndexStorePath; - - /// The bridging header or PCH that will be imported. - std::string BridgingHeader; - - /// When automatically generating a precompiled header from the bridging - /// header, place it in this directory. - std::string PrecompiledHeaderOutputDir; - - /// The optimizaton setting. This doesn't typically matter for - /// import, but it can affect Clang's IR generation of static functions. - std::string Optimization; - - /// Disable validating the persistent PCH. - bool PCHDisableValidation = false; - - /// \see Mode - enum class Modes : uint8_t { - /// Set up Clang for importing modules into Swift and generating IR from - /// Swift code. - Normal, - /// Set up Clang for backend compilation only. - EmbedBitcode, - /// Set up Clang to emit a precompiled module from a C/Objective-C module - /// map or dump debugging info about a precompiled module. - PrecompiledModule - }; - - /// Controls how Clang is initially set up. - Modes Mode = Modes::Normal; - - /// When set, preserves more information during import. - /// - /// Also \em disables some information that is only needed for object file - /// generation. - bool DetailedPreprocessingRecord = false; - - /// If true, Clang diagnostics will be dumped to stderr using Clang's - /// diagnostic printer as well as being passed to Swift's diagnostic engine. - bool DumpClangDiagnostics = false; - - /// If true, forward declarations will be imported using unavailable types - /// instead of dropped altogether when possible. - bool ImportForwardDeclarations = false; - - /// Whether to use the import as member inference system - /// - /// When importing a global, try to infer whether we can import it as a - /// member of some type instead. This includes inits, computed properties, - /// and methods. - bool InferImportAsMember = false; - - /// If true ignore the swift bridged attribute. - bool DisableSwiftBridgeAttr = false; - - /// When set, don't look for or load overlays. - bool DisableOverlayModules = false; - - /// When set, don't enforce warnings with -Werror. - bool DebuggerSupport = false; - - /// When set, ClangImporter is disabled, and all requests go to the - /// DWARFImporter delegate. - bool DisableSourceImport = false; - - /// When set, use ExtraArgs alone to configure clang instance because ExtraArgs - /// contains the full option set. - bool ExtraArgsOnly = false; - - /// Return a hash code of any components from these options that should - /// contribute to a Swift Bridging PCH hash. - llvm::hash_code getPCHHashComponents() const { - using llvm::hash_combine; - using llvm::hash_combine_range; - - return hash_combine(ModuleCachePath, - hash_combine_range(ExtraArgs.begin(), ExtraArgs.end()), - OverrideResourceDir, - TargetCPU, - BridgingHeader, - PrecompiledHeaderOutputDir, - static_cast(Mode), - DetailedPreprocessingRecord, - ImportForwardDeclarations, - InferImportAsMember, - DisableSwiftBridgeAttr, - DisableOverlayModules); - } -}; - -} // end namespace swift - -#endif diff --git a/include/swift/ClangImporter/ClangModule.h b/include/swift/ClangImporter/ClangModule.h index 90cc2c97c9166..f1f15794a0c76 100644 --- a/include/swift/ClangImporter/ClangModule.h +++ b/include/swift/ClangImporter/ClangModule.h @@ -19,6 +19,7 @@ #include "swift/AST/FileUnit.h" #include "swift/ClangImporter/ClangImporter.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/Basic/Module.h" namespace clang { class ASTContext; @@ -37,7 +38,7 @@ class ClangModuleUnit final : public LoadedFile { llvm::PointerIntPair overlayModule; mutable Optional> importedModulesForLookup; /// The metadata of the underlying Clang module. - clang::ExternalASTSource::ASTSourceDescriptor ASTSourceDescriptor; + clang::ASTSourceDescriptor ASTSourceDescriptor; public: /// True if the given Module contains an imported Clang module unit. @@ -115,8 +116,7 @@ class ClangModuleUnit final : public LoadedFile { /// Returns the ASTSourceDescriptor of the associated Clang module if one /// exists. - Optional - getASTSourceDescriptor() const; + Optional getASTSourceDescriptor() const; virtual StringRef getModuleDefiningPath() const override; diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 468a0711f90f4..1c3c612f9e98a 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -294,6 +294,9 @@ NODE(CanonicalSpecializedGenericTypeMetadataAccessFunction) NODE(MetadataInstantiationCache) NODE(NoncanonicalSpecializedGenericTypeMetadata) NODE(NoncanonicalSpecializedGenericTypeMetadataCache) +NODE(GlobalVariableOnceFunction) +NODE(GlobalVariableOnceToken) +NODE(GlobalVariableOnceDeclList) #undef CONTEXT_NODE #undef NODE diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index e591e978dccd1..f7a5a2247c049 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -18,10 +18,12 @@ #ifndef SWIFT_DEMANGLING_TYPEDECODER_H #define SWIFT_DEMANGLING_TYPEDECODER_H +#include "TypeLookupError.h" #include "swift/ABI/MetadataValues.h" +#include "swift/Basic/LLVM.h" #include "swift/Demangling/Demangler.h" #include "swift/Demangling/NamespaceMacros.h" -#include "swift/Basic/LLVM.h" +#include "swift/Runtime/Portability.h" #include "swift/Runtime/Unreachable.h" #include "swift/Strings.h" #include "llvm/ADT/ArrayRef.h" @@ -238,49 +240,60 @@ class ImplFunctionTypeFlags { unsigned Rep : 3; unsigned Pseudogeneric : 1; unsigned Escaping : 1; + unsigned Async : 1; unsigned DifferentiabilityKind : 2; public: ImplFunctionTypeFlags() - : Rep(0), Pseudogeneric(0), Escaping(0), DifferentiabilityKind(0) {} + : Rep(0), Pseudogeneric(0), Escaping(0), Async(0), + DifferentiabilityKind(0) {} ImplFunctionTypeFlags(ImplFunctionRepresentation rep, bool pseudogeneric, - bool noescape, + bool noescape, bool async, ImplFunctionDifferentiabilityKind diffKind) : Rep(unsigned(rep)), Pseudogeneric(pseudogeneric), Escaping(noescape), - DifferentiabilityKind(unsigned(diffKind)) {} + Async(async), DifferentiabilityKind(unsigned(diffKind)) {} ImplFunctionTypeFlags withRepresentation(ImplFunctionRepresentation rep) const { return ImplFunctionTypeFlags( - rep, Pseudogeneric, Escaping, + rep, Pseudogeneric, Escaping, Async, + ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); + } + + ImplFunctionTypeFlags + withAsync() const { + return ImplFunctionTypeFlags( + ImplFunctionRepresentation(Rep), Pseudogeneric, Escaping, true, ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); } ImplFunctionTypeFlags withEscaping() const { return ImplFunctionTypeFlags( - ImplFunctionRepresentation(Rep), Pseudogeneric, true, + ImplFunctionRepresentation(Rep), Pseudogeneric, true, Async, ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); } ImplFunctionTypeFlags withPseudogeneric() const { return ImplFunctionTypeFlags( - ImplFunctionRepresentation(Rep), true, Escaping, + ImplFunctionRepresentation(Rep), true, Escaping, Async, ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); } ImplFunctionTypeFlags withDifferentiabilityKind(ImplFunctionDifferentiabilityKind diffKind) const { return ImplFunctionTypeFlags(ImplFunctionRepresentation(Rep), Pseudogeneric, - Escaping, diffKind); + Escaping, Async, diffKind); } ImplFunctionRepresentation getRepresentation() const { return ImplFunctionRepresentation(Rep); } + bool isAsync() const { return Async; } + bool isEscaping() const { return Escaping; } bool isPseudogeneric() const { return Pseudogeneric; } @@ -317,6 +330,14 @@ getObjCClassOrProtocolName(NodePointer node) { } #endif +#define MAKE_NODE_TYPE_ERROR(Node, Fmt, ...) \ + TypeLookupError("TypeDecoder.h:%d: Node kind %u \"%.*s\" - " Fmt, __LINE__, \ + Node->getKind(), \ + Node->hasText() ? (int)Node->getText().size() : 0, \ + Node->hasText() ? Node->getText().data() : "", __VA_ARGS__) + +#define MAKE_NODE_TYPE_ERROR0(Node, Str) MAKE_NODE_TYPE_ERROR(Node, "%s", Str) + /// Decode a mangled type to construct an abstract type, forming such /// types by invoking a custom builder. template @@ -328,29 +349,29 @@ class TypeDecoder { BuilderType &Builder; - public: - explicit TypeDecoder(BuilderType &Builder) - : Builder(Builder) {} +public: + explicit TypeDecoder(BuilderType &Builder) : Builder(Builder) {} /// Given a demangle tree, attempt to turn it into a type. - BuiltType decodeMangledType(NodePointer Node) { - if (!Node) return BuiltType(); + TypeLookupErrorOr decodeMangledType(NodePointer Node) { + if (!Node) + return TypeLookupError("Node is NULL"); using NodeKind = Demangle::Node::Kind; switch (Node->getKind()) { case NodeKind::Global: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children."); return decodeMangledType(Node->getChild(0)); case NodeKind::TypeMangling: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children."); return decodeMangledType(Node->getChild(0)); case NodeKind::Type: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children."); return decodeMangledType(Node->getChild(0)); case NodeKind::Class: @@ -369,8 +390,8 @@ class TypeDecoder { BuiltTypeDecl typeDecl = BuiltTypeDecl(); BuiltType parent = BuiltType(); bool typeAlias = false; - if (!decodeMangledTypeDecl(Node, typeDecl, parent, typeAlias)) - return BuiltType(); + if (auto error = decodeMangledTypeDecl(Node, typeDecl, parent, typeAlias)) + return *error; if (typeAlias) return Builder.createTypeAliasType(typeDecl, parent); @@ -384,19 +405,21 @@ class TypeDecoder { case NodeKind::BoundGenericTypeAlias: case NodeKind::BoundGenericOtherNominalType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); llvm::SmallVector args; const auto &genericArgs = Node->getChild(1); if (genericArgs->getKind() != NodeKind::TypeList) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(genericArgs, "is not TypeList"); for (auto genericArg : *genericArgs) { auto paramType = decodeMangledType(genericArg); - if (!paramType) - return BuiltType(); - args.push_back(paramType); + if (paramType.isError()) + return paramType; + args.push_back(paramType.getType()); } auto ChildNode = Node->getChild(0); @@ -413,9 +436,9 @@ class TypeDecoder { BuiltTypeDecl typeDecl = BuiltTypeDecl(); BuiltType parent = BuiltType(); bool typeAlias = false; - if (!decodeMangledTypeDecl(ChildNode, typeDecl, - parent, typeAlias)) - return BuiltType(); + if (auto error = + decodeMangledTypeDecl(ChildNode, typeDecl, parent, typeAlias)) + return *error; return Builder.createBoundGenericType(typeDecl, args, parent); } @@ -445,11 +468,15 @@ class TypeDecoder { // But when resolving it to a type, we want to *keep* the argument // so that the parent type becomes 'S' and not 'P'. if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); const auto &genericArgs = Node->getChild(1); if (genericArgs->getNumChildren() != 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(genericArgs, + "expected 1 generic argument, saw %u", + genericArgs->getNumChildren()); return decodeMangledType(genericArgs->getChild(0)); } @@ -469,7 +496,7 @@ class TypeDecoder { auto reprNode = Node->getChild(i++); if (reprNode->getKind() != NodeKind::MetatypeRepresentation || !reprNode->hasText()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(reprNode, "wrong node kind or no text"); if (reprNode->getText() == "@thin") repr = ImplMetatypeRepresentation::Thin; else if (reprNode->getText() == "@thick") @@ -477,26 +504,28 @@ class TypeDecoder { else if (reprNode->getText() == "@objc_metatype") repr = ImplMetatypeRepresentation::ObjC; } else if (Node->getNumChildren() < 1) { - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); } auto instance = decodeMangledType(Node->getChild(i)); - if (!instance) - return BuiltType(); + if (instance.isError()) + return instance; if (Node->getKind() == NodeKind::Metatype) { - return Builder.createMetatypeType(instance, repr); + return Builder.createMetatypeType(instance.getType(), repr); } else if (Node->getKind() == NodeKind::ExistentialMetatype) { - return Builder.createExistentialMetatypeType(instance, repr); + return Builder.createExistentialMetatypeType(instance.getType(), repr); } else { assert(false); - return nullptr; + return MAKE_NODE_TYPE_ERROR0(Node, + "Metatype/ExistentialMetatype Node " + "had a different kind when re-checked"); } } case NodeKind::ProtocolList: case NodeKind::ProtocolListWithAnyObject: case NodeKind::ProtocolListWithClass: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); // Find the protocol list. llvm::SmallVector Protocols; @@ -511,7 +540,8 @@ class TypeDecoder { if (auto Protocol = decodeMangledProtocolType(componentType)) Protocols.push_back(Protocol); else - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(componentType, + "failed to decode protocol type"); } // Superclass or AnyObject, if present. @@ -519,11 +549,15 @@ class TypeDecoder { auto Superclass = BuiltType(); if (Node->getKind() == NodeKind::ProtocolListWithClass) { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); auto superclassNode = Node->getChild(1); - Superclass = decodeMangledType(superclassNode); - if (!Superclass) return BuiltType(); + auto result = decodeMangledType(superclassNode); + if (result.isError()) + return result; + Superclass = result.getType(); IsClassBound = true; } else if (Node->getKind() == NodeKind::ProtocolListWithAnyObject) { @@ -541,17 +575,18 @@ class TypeDecoder { /*IsClassBound=*/false); } - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "failed to decode protocol type"); } case NodeKind::DynamicSelf: { if (Node->getNumChildren() != 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, "expected 1 child, saw %u", + Node->getNumChildren()); auto selfType = decodeMangledType(Node->getChild(0)); - if (!selfType) - return BuiltType(); + if (selfType.isError()) + return selfType; - return Builder.createDynamicSelfType(selfType); + return Builder.createDynamicSelfType(selfType.getType()); } case NodeKind::DependentGenericParamType: { auto depth = Node->getChild(0)->getIndex(); @@ -571,7 +606,9 @@ class TypeDecoder { case NodeKind::EscapingLinearFunctionType: case NodeKind::FunctionType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); FunctionTypeFlags flags; if (Node->getKind() == NodeKind::ObjCBlock || @@ -611,13 +648,16 @@ class TypeDecoder { flags = flags.withAsync(isAsync).withThrows(isThrow); if (Node->getNumChildren() < firstChildIdx + 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (%u)", + Node->getNumChildren(), firstChildIdx + 2); bool hasParamFlags = false; llvm::SmallVector, 8> parameters; if (!decodeMangledFunctionInputType(Node->getChild(firstChildIdx), parameters, hasParamFlags)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node->getChild(firstChildIdx), + "failed to decode function type"); flags = flags.withNumParameters(parameters.size()) .withParameterFlags(hasParamFlags) @@ -631,8 +671,9 @@ class TypeDecoder { NodeKind::EscapingLinearFunctionType); auto result = decodeMangledType(Node->getChild(firstChildIdx+1)); - if (!result) return BuiltType(); - return Builder.createFunctionType(parameters, result, flags); + if (result.isError()) + return result; + return Builder.createFunctionType(parameters, result.getType(), flags); } case NodeKind::ImplFunctionType: { auto calleeConvention = ImplParameterConvention::Direct_Unowned; @@ -646,7 +687,7 @@ class TypeDecoder { if (child->getKind() == NodeKind::ImplConvention) { if (!child->hasText()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, "expected text"); if (child->getText() == "@convention(thin)") { flags = @@ -656,7 +697,7 @@ class TypeDecoder { } } else if (child->getKind() == NodeKind::ImplFunctionAttribute) { if (!child->hasText()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, "expected text"); StringRef text = child->getText(); if (text == "@convention(c)") { @@ -676,15 +717,18 @@ class TypeDecoder { flags = flags.withEscaping(); } else if (child->getKind() == NodeKind::ImplParameter) { if (decodeImplFunctionParam(child, parameters)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, + "failed to decode function parameter"); } else if (child->getKind() == NodeKind::ImplResult) { if (decodeImplFunctionParam(child, results)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, + "failed to decode function parameter"); } else if (child->getKind() == NodeKind::ImplErrorResult) { if (decodeImplFunctionPart(child, errorResults)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, + "failed to decode function part"); } else { - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, "unexpected kind"); } } @@ -696,7 +740,8 @@ class TypeDecoder { errorResult = errorResults.front(); break; default: - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, "got %zu errors", + errorResults.size()); } // TODO: Some cases not handled above, but *probably* they cannot @@ -711,13 +756,13 @@ class TypeDecoder { case NodeKind::ArgumentTuple: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); return decodeMangledType(Node->getChild(0)); case NodeKind::ReturnType: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); return decodeMangledType(Node->getChild(0)); @@ -726,12 +771,13 @@ class TypeDecoder { std::string labels; for (auto &element : *Node) { if (element->getKind() != NodeKind::TupleElement) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "unexpected kind"); // If the tuple element is labeled, add its label to 'labels'. unsigned typeChildIndex = 0; if (element->getChild(typeChildIndex)->getKind() == NodeKind::VariadicMarker) { - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(element->getChild(typeChildIndex), + "no children"); } if (element->getChild(typeChildIndex)->getKind() == NodeKind::TupleElementName) { // Add spaces to terminate all the previous labels if this @@ -749,22 +795,23 @@ class TypeDecoder { } // Decode the element type. - BuiltType elementType = - decodeMangledType(element->getChild(typeChildIndex)); - if (!elementType) - return BuiltType(); + auto elementType = decodeMangledType(element->getChild(typeChildIndex)); + if (elementType.isError()) + return elementType; - elements.push_back(elementType); + elements.push_back(elementType.getType()); } return Builder.createTupleType(elements, std::move(labels)); } case NodeKind::TupleElement: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); if (Node->getChild(0)->getKind() == NodeKind::TupleElementName) { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); return decodeMangledType(Node->getChild(1)); } @@ -772,68 +819,75 @@ class TypeDecoder { case NodeKind::DependentGenericType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); return decodeMangledType(Node->getChild(1)); } case NodeKind::DependentMemberType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; auto assocTypeChild = Node->getChild(1); auto member = assocTypeChild->getFirstChild()->getText(); if (assocTypeChild->getNumChildren() < 2) - return Builder.createDependentMemberType(member.str(), base); + return Builder.createDependentMemberType(member.str(), base.getType()); auto protocol = decodeMangledProtocolType(assocTypeChild->getChild(1)); if (!protocol) return BuiltType(); - return Builder.createDependentMemberType(member.str(), base, protocol); + return Builder.createDependentMemberType(member.str(), base.getType(), + protocol); } case NodeKind::DependentAssociatedTypeRef: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); return decodeMangledType(Node->getChild(1)); } case NodeKind::Unowned: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createUnownedStorageType(base); + if (base.isError()) + return base; + return Builder.createUnownedStorageType(base.getType()); } case NodeKind::Unmanaged: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createUnmanagedStorageType(base); + if (base.isError()) + return base; + return Builder.createUnmanagedStorageType(base.getType()); } case NodeKind::Weak: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createWeakStorageType(base); + if (base.isError()) + return base; + return Builder.createWeakStorageType(base.getType()); } case NodeKind::SILBoxType: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createSILBoxType(base); + if (base.isError()) + return base; + return Builder.createSILBoxType(base.getType()); } case NodeKind::SILBoxTypeWithLayout: { // TODO: Implement SILBoxTypeRefs with layout. As a stopgap, specify the @@ -842,57 +896,62 @@ class TypeDecoder { } case NodeKind::SugaredOptional: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; - return Builder.createOptionalType(base); + return Builder.createOptionalType(base.getType()); } case NodeKind::SugaredArray: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; - return Builder.createArrayType(base); + return Builder.createArrayType(base.getType()); } case NodeKind::SugaredDictionary: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); auto key = decodeMangledType(Node->getChild(0)); - if (!key) - return BuiltType(); + if (key.isError()) + return key; auto value = decodeMangledType(Node->getChild(1)); - if (!key) - return BuiltType(); + if (value.isError()) + return value; - return Builder.createDictionaryType(key, value); + return Builder.createDictionaryType(key.getType(), value.getType()); } case NodeKind::SugaredParen: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; - return Builder.createParenType(base); + return Builder.createParenType(base.getType()); } case NodeKind::OpaqueType: { if (Node->getNumChildren() < 3) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (3)", + Node->getNumChildren()); auto descriptor = Node->getChild(0); auto ordinalNode = Node->getChild(1); if (ordinalNode->getKind() != NodeKind::Index || !ordinalNode->hasIndex()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(ordinalNode, + "unexpected kind or no index"); auto ordinal = ordinalNode->getIndex(); std::vector genericArgsBuf; @@ -905,9 +964,9 @@ class TypeDecoder { break; for (auto argNode : *genericsNode) { auto arg = decodeMangledType(argNode); - if (!arg) - return BuiltType(); - genericArgsBuf.push_back(arg); + if (arg.isError()) + return arg; + genericArgsBuf.push_back(arg.getType()); } } genericArgsLevels.push_back(genericArgsBuf.size()); @@ -923,7 +982,7 @@ class TypeDecoder { // TODO: Handle OpaqueReturnType, when we're in the middle of reconstructing // the defining decl default: - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "unexpected kind"); } } @@ -943,11 +1002,11 @@ class TypeDecoder { T::getConventionFromString(conventionString); if (!convention) return true; - BuiltType type = decodeMangledType(node->getChild(1)); - if (!type) + auto type = decodeMangledType(node->getChild(1)); + if (type.isError()) return true; - results.emplace_back(type, *convention); + results.emplace_back(type.getType(), *convention); return false; } @@ -968,8 +1027,8 @@ class TypeDecoder { auto convention = T::getConventionFromString(conventionString); if (!convention) return true; - BuiltType type = decodeMangledType(typeNode); - if (!type) + auto result = decodeMangledType(typeNode); + if (result.isError()) return true; auto diffKind = T::DifferentiabilityType::DifferentiableOrNotApplicable; @@ -984,14 +1043,13 @@ class TypeDecoder { diffKind = *optDiffKind; } - results.emplace_back(type, *convention, diffKind); + results.emplace_back(result.getType(), *convention, diffKind); return false; } - bool decodeMangledTypeDecl(Demangle::NodePointer node, - BuiltTypeDecl &typeDecl, - BuiltType &parent, - bool &typeAlias) { + llvm::Optional + decodeMangledTypeDecl(Demangle::NodePointer node, BuiltTypeDecl &typeDecl, + BuiltType &parent, bool &typeAlias) { if (node->getKind() == NodeKind::Type) return decodeMangledTypeDecl(node->getChild(0), typeDecl, parent, typeAlias); @@ -1002,7 +1060,9 @@ class TypeDecoder { declNode = node; } else { if (node->getNumChildren() < 2) - return false; + return MAKE_NODE_TYPE_ERROR( + node, "Number of node children (%u) less than required (2)", + node->getNumChildren()); auto parentContext = node->getChild(0); @@ -1018,11 +1078,14 @@ class TypeDecoder { case Node::Kind::Extension: // Decode the type being extended. if (parentContext->getNumChildren() < 2) - return false; + return MAKE_NODE_TYPE_ERROR(parentContext, + "Number of parentContext children (%u) " + "less than required (2)", + node->getNumChildren()); parentContext = parentContext->getChild(1); LLVM_FALLTHROUGH; default: - parent = decodeMangledType(parentContext); + parent = decodeMangledType(parentContext).getType(); // Remove any generic arguments from the context node, producing a // node that references the nominal type declaration. declNode = Demangle::getUnspecialized(node, Builder.getNodeFactory()); @@ -1030,9 +1093,10 @@ class TypeDecoder { } } typeDecl = Builder.createTypeDecl(declNode, typeAlias); - if (!typeDecl) return false; + if (!typeDecl) + return TypeLookupError("Failed to create type decl"); - return true; + return llvm::None; } BuiltProtocolDecl decodeMangledProtocolType(Demangle::NodePointer node) { @@ -1097,10 +1161,10 @@ class TypeDecoder { } auto paramType = decodeMangledType(node); - if (!paramType) + if (paramType.isError()) return false; - param.setType(paramType); + param.setType(paramType.getType()); return true; }; @@ -1158,14 +1222,12 @@ class TypeDecoder { } }; -template -inline typename BuilderType::BuiltType -decodeMangledType(BuilderType &Builder, - NodePointer Node) { +template +inline TypeLookupErrorOr +decodeMangledType(BuilderType &Builder, NodePointer Node) { return TypeDecoder(Builder).decodeMangledType(Node); } - SWIFT_END_INLINE_NAMESPACE } // end namespace Demangle } // end namespace swift diff --git a/include/swift/Demangling/TypeLookupError.h b/include/swift/Demangling/TypeLookupError.h new file mode 100644 index 0000000000000..c67fc35598be8 --- /dev/null +++ b/include/swift/Demangling/TypeLookupError.h @@ -0,0 +1,198 @@ +//===--- TypeLookupError.h - Type lookup error value. -----------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Provides the TypeLookupError class, which represents errors when demangling +// or looking up types. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_DEMANGLING_TypeLookupError_H +#define SWIFT_DEMANGLING_TypeLookupError_H + +#include "swift/Basic/TaggedUnion.h" +#include "swift/Runtime/Portability.h" + +namespace swift { + +/// An error that occurred while looking up a type at runtime from a mangled +/// name. +/// /// +/// This ultimately just provides a string, but is built to take up minimal +/// space when passed around, and perform as much work lazily as possible. We +/// don't want to spend a lot of time building strings when the caller is going +/// to handle the error gracefully and try a fallback. We only want to waste +/// time/space on that when the error message is actually relevant, so build it +/// as late as possible. +/// /// +/// To be as compact as possible, this type holds a context pointer and a +/// callback function. The callback function uses the context pointer to return +/// an error string when requested. The callback function also does quadruple +/// duty to copy/destroy the context as needed, and free the returned error +/// string if needed. Commands are passed to the callback to request the +/// different operations, which means we only have to store one function pointer +/// instead of four. +class TypeLookupError { +public: + /// The commands that can be passed to the callback function. + enum class Command { + /// Return the error string to the caller, as a char *. + CopyErrorString, + + /// Destroy the error string returned from CopyErrorString, if necessary. + /// The return value is ignored. + DestroyErrorString, + + /// Return a copy of the context pointer (used for copying TypeLookupError + /// objects.) + CopyContext, + + /// Destroy the context pointer. The return value is ignored. + DestroyContext, + }; + + /// The callback used to respond to the commands. The parameters are: + /// - `context`: the context that the value was initialized with, or the + /// context returned from a CopyContext call + /// - `command`: the command to respond to + /// - `param`: when `command` is `DestroyErrorString`, the string pointer to + /// destroy, otherwise NULL + using Callback = void *(*)(void *context, Command command, void *param); + +private: + void *Context; + Callback Fn; + + /// A no-op callback used to avoid a bunch of `if (Fn)` checks. + static void *nop(void *context, Command command, void *param) { + return nullptr; + } + + /// Helper functions for getting a C string from a lambda. These allow us to + /// wrap lambdas returning `char *` or `std::string` and standardize them on + /// `char *`. + static char *getCString(char *str) { return str; } + + static char *getCString(const std::string &str) { + return strdup(str.c_str()); + } + +public: + TypeLookupError(const TypeLookupError &other) { + Fn = other.Fn; + Context = other.Fn(other.Context, Command::CopyContext, nullptr); + } + + TypeLookupError(TypeLookupError &&other) { + Fn = other.Fn; + Context = other.Context; + + other.Fn = nop; + other.Context = nullptr; + } + + ~TypeLookupError() { Fn(Context, Command::DestroyContext, nullptr); } + + TypeLookupError(void *context, Callback fn) : Context(context), Fn(fn ? fn : nop) {} + + TypeLookupError &operator=(const TypeLookupError &other) { + if (this == &other) + return *this; + + Fn(Context, Command::DestroyContext, nullptr); + Fn = other.Fn; + Context = Fn(Context, Command::CopyContext, nullptr); + + return *this; + } + + /// Construct a TypeLookupError that just returns a constant C string. + TypeLookupError(const char *str) + : TypeLookupError([=] { return const_cast(str); }) {} + + /// Construct a TypeLookupError that creates a string using asprintf. The passed-in + /// format string and arguments are passed directly to swift_asprintf when + /// the string is requested. The arguments are captured and the string is only + /// formatted when needed. + template + TypeLookupError(const char *fmt, Args... args) + : TypeLookupError([=] { + char *str; + swift_asprintf(&str, fmt, args...); + return str; + }) {} + + /// Construct a TypeLookupError that wraps a function returning a string. The + /// passed-in function can return either a `std::string` or `char *`. If it + /// returns `char *` then the string will be destroyed with `free()`. + template TypeLookupError(const F &fn) { + Context = new F(fn); + Fn = [](void *context, Command command, void *param) -> void * { + auto castContext = reinterpret_cast(context); + switch (command) { + case Command::CopyErrorString: { + return TypeLookupError::getCString((*castContext)()); + } + case Command::DestroyErrorString: + free(param); + return nullptr; + case Command::CopyContext: + return new F(*castContext); + case Command::DestroyContext: + delete castContext; + return nullptr; + } + }; + } + + /// Get the error string from the error value. The value must be passed to + /// `freeErrorString` when done. (Unless you're just calling a `fatalError` + /// in which case there's no point.) + char *copyErrorString() { + return reinterpret_cast( + Fn(Context, Command::CopyErrorString, nullptr)); + } + + /// Free an error string previously obtained from `copyErrorString`. + void freeErrorString(char *str) { + Fn(Context, Command::DestroyErrorString, str); + } +}; + +/// A value that's either a `TypeLookupError` or some parameterized type value `T`. A +/// convenience wrapper around `TaggedUnion`. +template class TypeLookupErrorOr { + TaggedUnion Value; + +public: + TypeLookupErrorOr(const T &t) : Value(t) { + if (!t) + Value = TypeLookupError("unknown error"); + } + + TypeLookupErrorOr(const TypeLookupError &te) : Value(te) {} + + T getType() { + if (auto *ptr = Value.template dyn_cast()) + return *ptr; + return T(); + } + + TypeLookupError *getError() { + return Value.template dyn_cast(); + } + + bool isError() { return getError() != nullptr; } +}; + +} // namespace swift + +#endif // SWIFT_DEMANGLING_TypeLookupError_H diff --git a/include/swift/Driver/Action.h b/include/swift/Driver/Action.h index 02801d8aece66..7fee378225a2a 100644 --- a/include/swift/Driver/Action.h +++ b/include/swift/Driver/Action.h @@ -51,9 +51,10 @@ class Action { GenerateDSYMJob, VerifyDebugInfoJob, GeneratePCHJob, + VerifyModuleInterfaceJob, JobFirst = CompileJob, - JobLast = GeneratePCHJob + JobLast = VerifyModuleInterfaceJob }; static const char *getClassName(Kind AC); @@ -148,7 +149,7 @@ class CompileJobAction : public JobAction { }; private: - virtual void anchor(); + virtual void anchor() override; InputInfo inputInfo; public: @@ -191,7 +192,7 @@ class CompileJobAction : public JobAction { class InterpretJobAction : public JobAction { private: - virtual void anchor(); + virtual void anchor() override; public: explicit InterpretJobAction() @@ -205,7 +206,7 @@ class InterpretJobAction : public JobAction { class BackendJobAction : public JobAction { private: - virtual void anchor(); + virtual void anchor() override; // In case of multi-threaded compilation, the compile-action produces multiple // output bitcode-files. For each bitcode-file a BackendJobAction is created. @@ -220,7 +221,7 @@ class BackendJobAction : public JobAction { return A->getKind() == Action::Kind::BackendJob; } - virtual size_t getInputIndex() const { return InputIndex; } + virtual size_t getInputIndex() const override { return InputIndex; } }; class REPLJobAction : public JobAction { @@ -231,7 +232,7 @@ class REPLJobAction : public JobAction { RequireLLDB }; private: - virtual void anchor(); + virtual void anchor() override; Mode RequestedMode; public: REPLJobAction(Mode mode) @@ -247,7 +248,7 @@ class REPLJobAction : public JobAction { }; class MergeModuleJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: MergeModuleJobAction(ArrayRef Inputs) : JobAction(Action::Kind::MergeModuleJob, Inputs, @@ -259,7 +260,7 @@ class MergeModuleJobAction : public JobAction { }; class ModuleWrapJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: ModuleWrapJobAction(ArrayRef Inputs) : JobAction(Action::Kind::ModuleWrapJob, Inputs, @@ -271,7 +272,7 @@ class ModuleWrapJobAction : public JobAction { }; class AutolinkExtractJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: AutolinkExtractJobAction(ArrayRef Inputs) : JobAction(Action::Kind::AutolinkExtractJob, Inputs, @@ -283,7 +284,7 @@ class AutolinkExtractJobAction : public JobAction { }; class GenerateDSYMJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: explicit GenerateDSYMJobAction(const Action *Input) : JobAction(Action::Kind::GenerateDSYMJob, Input, @@ -295,7 +296,7 @@ class GenerateDSYMJobAction : public JobAction { }; class VerifyDebugInfoJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: explicit VerifyDebugInfoJobAction(const Action *Input) : JobAction(Action::Kind::VerifyDebugInfoJob, Input, @@ -309,7 +310,7 @@ class VerifyDebugInfoJobAction : public JobAction { class GeneratePCHJobAction : public JobAction { std::string PersistentPCHDir; - virtual void anchor(); + virtual void anchor() override; public: GeneratePCHJobAction(const Action *Input, StringRef persistentPCHDir) : JobAction(Action::Kind::GeneratePCHJob, Input, @@ -326,7 +327,7 @@ class GeneratePCHJobAction : public JobAction { }; class DynamicLinkJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; LinkKind Kind; public: @@ -344,7 +345,7 @@ class DynamicLinkJobAction : public JobAction { }; class StaticLinkJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: StaticLinkJobAction(ArrayRef Inputs, LinkKind K) @@ -357,6 +358,26 @@ class StaticLinkJobAction : public JobAction { } }; +class VerifyModuleInterfaceJobAction : public JobAction { + virtual void anchor(); + file_types::ID inputType; + +public: + VerifyModuleInterfaceJobAction(const Action * ModuleEmitter, + file_types::ID inputType) + : JobAction(Action::Kind::VerifyModuleInterfaceJob, { ModuleEmitter }, + file_types::TY_Nothing), inputType(inputType) { + assert(inputType == file_types::TY_SwiftModuleInterfaceFile || + inputType == file_types::TY_PrivateSwiftModuleInterfaceFile); + } + + file_types::ID getInputType() const { return inputType; } + + static bool classof(const Action *A) { + return A->getKind() == Action::Kind::VerifyModuleInterfaceJob; + } +}; + } // end namespace driver } // end namespace swift diff --git a/include/swift/Driver/Driver.h b/include/swift/Driver/Driver.h index 5e055359d6346..d55121ea2da86 100644 --- a/include/swift/Driver/Driver.h +++ b/include/swift/Driver/Driver.h @@ -366,6 +366,11 @@ class Driver { file_types::ID fileType, CommandOutput *output) const; + void chooseModuleSummaryPath(Compilation &C, const TypeToPathMap *OutputMap, + StringRef workingDirectory, + llvm::SmallString<128> &Buf, + CommandOutput *Output) const; + void chooseRemappingOutputPath(Compilation &C, const TypeToPathMap *OutputMap, CommandOutput *Output) const; diff --git a/include/swift/Driver/ToolChain.h b/include/swift/Driver/ToolChain.h index cd55451a01c8b..7be6dffbe37cf 100644 --- a/include/swift/Driver/ToolChain.h +++ b/include/swift/Driver/ToolChain.h @@ -162,6 +162,9 @@ class ToolChain { virtual InvocationInfo constructInvocation(const VerifyDebugInfoJobAction &job, const JobContext &context) const; + virtual InvocationInfo + constructInvocation(const VerifyModuleInterfaceJobAction &job, + const JobContext &context) const; virtual InvocationInfo constructInvocation(const GeneratePCHJobAction &job, const JobContext &context) const; virtual InvocationInfo diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index f5f75f13e7694..0fa9e0ee1344e 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -30,7 +30,6 @@ #include "swift/Basic/LangOptions.h" #include "swift/Basic/SourceManager.h" #include "swift/ClangImporter/ClangImporter.h" -#include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/Frontend/DiagnosticVerifier.h" #include "swift/Frontend/FrontendOptions.h" #include "swift/Frontend/ModuleInterfaceSupport.h" @@ -329,11 +328,6 @@ class CompilerInvocation { return CodeCompletionOffset != ~0U; } - /// Called from lldb, see rdar://53971116 - void disableASTScopeLookup() { - LangOpts.EnableASTScopeLookup = false; - } - /// Retrieve a module hash string that is suitable for uniquely /// identifying the conditions under which the module was built, for use /// in generating a cached PCH file for the bridging header. @@ -621,7 +615,7 @@ class CompilerInstance { /// /// This is similar to a parse-only invocation, but module imports will also /// be processed. - void performParseAndResolveImportsOnly(); + bool performParseAndResolveImportsOnly(); /// Performs mandatory, diagnostic, and optimization passes over the SIL. /// \param silModule The SIL module that was generated during SILGen. diff --git a/include/swift/Frontend/FrontendInputsAndOutputs.h b/include/swift/Frontend/FrontendInputsAndOutputs.h index 76f5ef125bc14..84a85ec91f56e 100644 --- a/include/swift/Frontend/FrontendInputsAndOutputs.h +++ b/include/swift/Frontend/FrontendInputsAndOutputs.h @@ -17,6 +17,7 @@ #include "swift/Basic/SupplementaryOutputPaths.h" #include "swift/Frontend/InputFile.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringMap.h" #include #include @@ -239,6 +240,7 @@ class FrontendInputsAndOutputs { bool hasModuleSourceInfoOutputPath() const; bool hasModuleInterfaceOutputPath() const; bool hasPrivateModuleInterfaceOutputPath() const; + bool hasModuleSummaryOutputPath() const; bool hasTBDPath() const; bool hasDependencyTrackerPath() const; diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index aef89085fb34b..e2f84da002ea8 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -116,6 +116,8 @@ class FrontendOptions { /// Build from a swiftinterface, as close to `import` as possible CompileModuleFromInterface, + /// Same as CompileModuleFromInterface, but stopping after typechecking + TypecheckModuleFromInterface, EmitSIBGen, ///< Emit serialized AST + raw SIL EmitSIB, ///< Emit serialized AST + canonical SIL @@ -133,7 +135,8 @@ class FrontendOptions { EmitPCM, ///< Emit precompiled Clang module from a module map DumpPCM, ///< Dump information about a precompiled Clang module - ScanDependencies, ///< Scan dependencies of Swift source files + ScanDependencies, ///< Scan dependencies of Swift source files + ScanClangDependencies, ///< Scan dependencies of a Clang module PrintVersion, ///< Print version information. }; @@ -291,9 +294,16 @@ class FrontendOptions { /// '.../lib/swift', otherwise '.../lib/swift_static'. bool UseSharedResourceFolder = true; - /// \return true if action only parses without doing other compilation steps. + /// \return true if the given action only parses without doing other compilation steps. static bool shouldActionOnlyParse(ActionType); + /// \return true if the given action requires the standard library to be + /// loaded before it is run. + static bool doesActionRequireSwiftStandardLibrary(ActionType); + + /// \return true if the given action requires input files to be provided. + static bool doesActionRequireInputs(ActionType action); + /// Return a hash code of any components from these options that should /// contribute to a Swift Bridging PCH hash. llvm::hash_code getPCHHashComponents() const { @@ -330,6 +340,7 @@ class FrontendOptions { static bool canActionEmitLoadedModuleTrace(ActionType); static bool canActionEmitModule(ActionType); static bool canActionEmitModuleDoc(ActionType); + static bool canActionEmitModuleSummary(ActionType); static bool canActionEmitInterface(ActionType); public: diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 78116f109a8e8..9996d8e20d8d4 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -133,13 +133,22 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase { explicit ExplicitSwiftModuleLoader(ASTContext &ctx, DependencyTracker *tracker, ModuleLoadingMode loadMode, bool IgnoreSwiftSourceInfoFile); + + bool findModule(AccessPathElem moduleID, + SmallVectorImpl *moduleInterfacePath, + std::unique_ptr *moduleBuffer, + std::unique_ptr *moduleDocBuffer, + std::unique_ptr *moduleSourceInfoBuffer, + bool &isFramework, bool &isSystemModule) override; + std::error_code findModuleFilesInDirectory( - AccessPathElem ModuleID, - const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override; + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; bool canImportModule(Located mID) override; @@ -172,6 +181,8 @@ struct ExplicitModuleInfo { std::string moduleSourceInfoPath; // Opened buffer for the .swiftmodule file. std::unique_ptr moduleBuffer; + // A flag that indicates whether this module is a framework + bool isFramework; }; /// Parser of explicit module maps passed into the compiler. @@ -181,12 +192,14 @@ struct ExplicitModuleInfo { // "modulePath": "A.swiftmodule", // "docPath": "A.swiftdoc", // "sourceInfoPath": "A.swiftsourceinfo" +// "isFramework": false // }, // { // "moduleName": "B", // "modulePath": "B.swiftmodule", // "docPath": "B.swiftdoc", // "sourceInfoPath": "B.swiftsourceinfo" +// "isFramework": false // } // ] class ExplicitModuleMapParser { @@ -248,6 +261,15 @@ class ExplicitModuleMapParser { result.moduleDocPath = val.str(); } else if (key == "sourceInfoPath") { result.moduleSourceInfoPath = val.str(); + } else if (key == "isFramework") { + auto valStr = val.str(); + valStr.erase(std::remove(valStr.begin(), valStr.end(), '\n'), valStr.end()); + if (valStr.compare("true") == 0) + result.isFramework = true; + else if (valStr.compare("false") == 0) + result.isFramework = false; + else + llvm_unreachable("Unexpected JSON value for isFramework"); } else { // Being forgiving for future fields. continue; @@ -263,6 +285,8 @@ class ExplicitModuleMapParser { }; struct ModuleInterfaceLoaderOptions { + FrontendOptions::ActionType requestedAction = + FrontendOptions::ActionType::EmitModuleOnly; bool remarkOnRebuildFromInterface = false; bool disableInterfaceLock = false; bool disableImplicitSwiftModule = false; @@ -271,7 +295,17 @@ struct ModuleInterfaceLoaderOptions { remarkOnRebuildFromInterface(Opts.RemarkOnRebuildFromModuleInterface), disableInterfaceLock(Opts.DisableInterfaceFileLock), disableImplicitSwiftModule(Opts.DisableImplicitModules), - mainExecutablePath(Opts.MainExecutablePath) {} + mainExecutablePath(Opts.MainExecutablePath) + { + switch (Opts.RequestedAction) { + case FrontendOptions::ActionType::TypecheckModuleFromInterface: + requestedAction = FrontendOptions::ActionType::Typecheck; + break; + default: + requestedAction = FrontendOptions::ActionType::EmitModuleOnly; + break; + } + } ModuleInterfaceLoaderOptions() = default; }; @@ -298,12 +332,13 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase { ModuleInterfaceLoaderOptions Opts; std::error_code findModuleFilesInDirectory( - AccessPathElem ModuleID, - const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override; + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; bool isCached(StringRef DepPath) override; public: @@ -385,24 +420,25 @@ struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate { DiagnosticEngine &Diags, const SearchPathOptions &searchPathOpts, const LangOptions &langOpts, + const ClangImporterOptions &clangImporterOpts, ModuleInterfaceLoaderOptions LoaderOpts, - ClangModuleLoader *clangImporter, bool buildModuleCacheDirIfAbsent, StringRef moduleCachePath, StringRef prebuiltCachePath, bool serializeDependencyHashes, bool trackSystemDependencies); - bool runInSubContext(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref, - ArrayRef, StringRef)> action) override; - bool runInSubCompilerInstance(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref action) override; + std::error_code runInSubContext(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref, ArrayRef, + StringRef)> action) override; + std::error_code runInSubCompilerInstance(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref action) override; ~InterfaceSubContextDelegateImpl() = default; @@ -412,7 +448,6 @@ struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate { llvm::SmallString<256> &OutPath, StringRef &CacheHash); std::string getCacheHash(StringRef useInterfacePath); - void addExtraClangArg(StringRef Arg); }; } diff --git a/include/swift/Frontend/ModuleInterfaceSupport.h b/include/swift/Frontend/ModuleInterfaceSupport.h index df576eb26d19a..f4c97c66c8f62 100644 --- a/include/swift/Frontend/ModuleInterfaceSupport.h +++ b/include/swift/Frontend/ModuleInterfaceSupport.h @@ -41,12 +41,15 @@ struct ModuleInterfaceOptions { /// back .swiftinterface and reconstructing .swiftmodule. std::string Flags; - // Print SPI decls and attributes. + /// Print SPI decls and attributes. bool PrintSPIs = false; /// Print imports with both @_implementationOnly and @_spi, only applies /// when PrintSPIs is true. bool ExperimentalSPIImports = false; + + /// Intentionally print invalid syntax into the file. + bool DebugPrintInvalidSyntax = false; }; extern version::Version InterfaceFormatVersion; diff --git a/include/swift/IDE/CodeCompletionResultPrinter.h b/include/swift/IDE/CodeCompletionResultPrinter.h index 717d6282a4309..86e1233246dc9 100644 --- a/include/swift/IDE/CodeCompletionResultPrinter.h +++ b/include/swift/IDE/CodeCompletionResultPrinter.h @@ -34,6 +34,12 @@ void printCodeCompletionResultTypeName( void printCodeCompletionResultTypeNameAnnotated( const CodeCompletionResult &Result, llvm::raw_ostream &OS); +void printCodeCompletionResultSourceText( + const CodeCompletionResult &Result, llvm::raw_ostream &OS); + +void printCodeCompletionResultFilterName( + const CodeCompletionResult &Result, llvm::raw_ostream &OS); + } // namespace ide } // namespace swift diff --git a/include/swift/IDE/CompletionInstance.h b/include/swift/IDE/CompletionInstance.h index 51687b974b9c0..2c114ee194e4c 100644 --- a/include/swift/IDE/CompletionInstance.h +++ b/include/swift/IDE/CompletionInstance.h @@ -37,8 +37,10 @@ makeCodeCompletionMemoryBuffer(const llvm::MemoryBuffer *origBuf, /// Manages \c CompilerInstance for completion like operations. class CompletionInstance { - unsigned MaxASTReuseCount = 100; - unsigned DependencyCheckIntervalSecond = 5; + struct Options { + unsigned MaxASTReuseCount = 100; + unsigned DependencyCheckIntervalSecond = 5; + } Opts; std::mutex mtx; @@ -59,7 +61,7 @@ class CompletionInstance { /// argument has changed, primary file is not the same, the \c Offset is not /// in function bodies, or the interface hash of the file has changed. bool performCachedOperationIfPossible( - const swift::CompilerInvocation &Invocation, llvm::hash_code ArgsHash, + llvm::hash_code ArgsHash, llvm::IntrusiveRefCntPtr FileSystem, llvm::MemoryBuffer *completionBuffer, unsigned int Offset, DiagnosticConsumer *DiagC, @@ -78,7 +80,9 @@ class CompletionInstance { llvm::function_ref Callback); public: - void setDependencyCheckIntervalSecond(unsigned Value); + CompletionInstance() {} + + void setOptions(Options NewOpts); /// Calls \p Callback with a \c CompilerInstance which is prepared for the /// second pass. \p Callback is resposible to perform the second pass on it. @@ -94,7 +98,7 @@ class CompletionInstance { swift::CompilerInvocation &Invocation, llvm::ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, llvm::MemoryBuffer *completionBuffer, unsigned int Offset, - bool EnableASTCaching, std::string &Error, DiagnosticConsumer *DiagC, + std::string &Error, DiagnosticConsumer *DiagC, llvm::function_ref Callback); }; diff --git a/tools/SourceKit/include/SourceKit/Support/FuzzyStringMatcher.h b/include/swift/IDE/FuzzyStringMatcher.h similarity index 83% rename from tools/SourceKit/include/SourceKit/Support/FuzzyStringMatcher.h rename to include/swift/IDE/FuzzyStringMatcher.h index cb53e962de0d7..af80647e37c3e 100644 --- a/tools/SourceKit/include/SourceKit/Support/FuzzyStringMatcher.h +++ b/include/swift/IDE/FuzzyStringMatcher.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,14 +10,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_SOURCEKIT_LIB_SUPPORT_FUZZYSTRINGMATCHER_H -#define LLVM_SOURCEKIT_LIB_SUPPORT_FUZZYSTRINGMATCHER_H +#ifndef SWIFT_IDE_FUZZYSTRINGMATCHER_H +#define SWIFT_IDE_FUZZYSTRINGMATCHER_H -#include "SourceKit/Core/LLVM.h" +#include "swift/Basic/LLVM.h" #include "llvm/ADT/BitVector.h" #include -namespace SourceKit { +namespace swift { +namespace ide { /// FuzzyStringMatcher compares candidate strings against a pattern /// string using a fuzzy matching algorithm and provides a numerical @@ -49,6 +50,7 @@ class FuzzyStringMatcher { double scoreCandidate(StringRef candidate) const; }; -} // end namespace SourceKit +} // namespace ide +} // namespace swift -#endif // LLVM_SOURCEKIT_LIB_SUPPORT_FUZZYSTRINGMATCHER_H +#endif // SWIFT_IDE_FUZZYSTRINGMATCHER_H diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index f847b188f1b42..c916f7742bb22 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -81,6 +81,14 @@ SourceCompleteResult isSourceInputComplete(std::unique_ptr MemBuf, SourceFileKind SFKind); SourceCompleteResult isSourceInputComplete(StringRef Text, SourceFileKind SFKind); +bool initCompilerInvocation( + CompilerInvocation &Invocation, ArrayRef OrigArgs, + DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, + llvm::IntrusiveRefCntPtr FileSystem, + const std::string &runtimeResourcePath, + const std::string &diagnosticDocumentationPath, + bool shouldOptimizeForIDE, time_t sessionTimestamp, std::string &Error); + bool initInvocationByClangArguments(ArrayRef ArgList, CompilerInvocation &Invok, std::string &Error); @@ -93,10 +101,6 @@ void walkOverriddenDecls(const ValueDecl *VD, void collectModuleNames(StringRef SDKPath, std::vector &Modules); -std::string getSDKName(StringRef Path); - -std::string getSDKVersion(StringRef Path); - struct PlaceholderOccurrence { /// The complete placeholder string. StringRef FullPlaceholder; diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index 3232e0e6881e9..8eb4145bb76b6 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -1231,7 +1231,7 @@ class ApplyIRLinkage { IRLinkage IRL; public: ApplyIRLinkage(IRLinkage IRL) : IRL(IRL) {} - void to(llvm::GlobalValue *GV) const { + void to(llvm::GlobalValue *GV, bool definition = true) const { llvm::Module *M = GV->getParent(); const llvm::Triple Triple(M->getTargetTriple()); @@ -1253,11 +1253,14 @@ class ApplyIRLinkage { return; } - if (IRL.Linkage == llvm::GlobalValue::LinkOnceODRLinkage || - IRL.Linkage == llvm::GlobalValue::WeakODRLinkage) - if (Triple.supportsCOMDAT()) - if (llvm::GlobalObject *GO = dyn_cast(GV)) - GO->setComdat(M->getOrInsertComdat(GV->getName())); + // COMDATs cannot be applied to declarations. If we have a definition, + // apply the COMDAT. + if (definition) + if (IRL.Linkage == llvm::GlobalValue::LinkOnceODRLinkage || + IRL.Linkage == llvm::GlobalValue::WeakODRLinkage) + if (Triple.supportsCOMDAT()) + if (llvm::GlobalObject *GO = dyn_cast(GV)) + GO->setComdat(M->getOrInsertComdat(GV->getName())); } }; diff --git a/include/swift/AST/LocalizationFormat.h b/include/swift/Localization/LocalizationFormat.h similarity index 94% rename from include/swift/AST/LocalizationFormat.h rename to include/swift/Localization/LocalizationFormat.h index efd3d5345467f..ccea86711d6c3 100644 --- a/include/swift/AST/LocalizationFormat.h +++ b/include/swift/Localization/LocalizationFormat.h @@ -17,6 +17,7 @@ #ifndef SWIFT_LOCALIZATIONFORMAT_H #define SWIFT_LOCALIZATIONFORMAT_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" @@ -42,6 +43,20 @@ namespace diag { using namespace llvm::support; +class DefToYAMLConverter { + llvm::ArrayRef IDs; + llvm::ArrayRef Messages; + +public: + DefToYAMLConverter(llvm::ArrayRef ids, + llvm::ArrayRef messages) + : IDs(ids), Messages(messages) { + assert(IDs.size() == Messages.size()); + } + + void convert(llvm::raw_ostream &out); +}; + class LocalizationWriterInfo { public: using key_type = uint32_t; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 5bd693d2ffe7d..cf788d081253d 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -160,12 +160,6 @@ def crosscheck_unqualified_lookup : Flag<["-"], "crosscheck-unqualified-lookup"> def stress_astscope_lookup : Flag<["-"], "stress-astscope-lookup">, HelpText<"Stress ASTScope-based unqualified name lookup (for testing)">; -def warn_if_astscope_lookup : Flag<["-"], "warn-if-astscope-lookup">, - HelpText<"Print a warning if ASTScope lookup is used">; - -def lazy_astscopes : Flag<["-"], "lazy-astscopes">, - HelpText<"Build ASTScopes lazily">; - def use_clang_function_types : Flag<["-"], "use-clang-function-types">, HelpText<"Use stored Clang function types for computing canonical types.">; @@ -228,6 +222,10 @@ def explict_swift_module_map def placeholder_dependency_module_map : Separate<["-"], "placeholder-dependency-module-map-file">, MetaVarName<"">, HelpText<"Specify a JSON file containing information of external Swift module dependencies">; + +def batch_scan_input_file + : Separate<["-"], "batch-scan-input-file">, MetaVarName<"">, + HelpText<"Specify a JSON file containing modules to perform batch dependencies scanning">; } @@ -256,6 +254,9 @@ 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_emit_invalid_swiftinterface_syntax : Flag<["-"], "debug-emit-invalid-swiftinterface-syntax">, + HelpText<"Write an invalid declaration into swiftinterface files">; + def debug_cycles : Flag<["-"], "debug-cycles">, HelpText<"Print out debug dumps when cycles are detected in evaluation">; def build_request_dependency_graph : Flag<["-"], "build-request-dependency-graph">, @@ -594,6 +595,9 @@ def disable_incremental_llvm_codegeneration : Flag<["-"], "disable-incremental-llvm-codegen">, HelpText<"Disable incremental llvm code generation.">; +def ignore_always_inline : Flag<["-"], "ignore-always-inline">, + HelpText<"Ignore @inline(__always) attributes.">; + def emit_sorted_sil : Flag<["-"], "emit-sorted-sil">, HelpText<"When printing SIL, print out all sil entities sorted by name to " "ease diffing">; @@ -641,6 +645,11 @@ def build_module_from_parseable_interface : Alias, ModeOpt; +def typecheck_module_from_interface : + Flag<["-"], "typecheck-module-from-interface">, + HelpText<"Treat the (single) input as a swiftinterface and typecheck it">, + ModeOpt; + def module_interface_preserve_types_as_written : Flag<["-"], "module-interface-preserve-types-as-written">, HelpText<"When emitting a module interface, preserve types as they were " diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 01017c43315eb..e75d2f835ced9 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -443,6 +443,17 @@ def emit_module_path_EQ : Joined<["-"], "emit-module-path=">, ArgumentIsPath, SupplementaryOutput]>, Alias; +def emit_module_summary : + Flag<["-"], "emit-module-summary">, + Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild, + SupplementaryOutput]>, + HelpText<"Output module summary file">; +def emit_module_summary_path : + Separate<["-"], "emit-module-summary-path">, + Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild, + ArgumentIsPath, SupplementaryOutput]>, + MetaVarName<"">, HelpText<"Output module summary file to ">; + def emit_module_interface : Flag<["-"], "emit-module-interface">, Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild, @@ -460,6 +471,15 @@ def emit_private_module_interface_path : DoesNotAffectIncrementalBuild, ArgumentIsPath, SupplementaryOutput]>, MetaVarName<"">, HelpText<"Output private module interface file to ">; +def verify_emitted_module_interface : + Flag<["-"], "verify-emitted-module-interface">, + Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>, + HelpText<"Check that module interfaces emitted during compilation typecheck">; +def no_verify_emitted_module_interface : + Flag<["-"], "no-verify-emitted-module-interface">, + Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>, + HelpText<"Don't check that module interfaces emitted during compilation typecheck">; + def avoid_emit_module_source_info : Flag<["-"], "avoid-emit-module-source-info">, Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>, @@ -1094,13 +1114,9 @@ def scan_dependencies : Flag<["-"], "scan-dependencies">, HelpText<"Scan dependencies of the given Swift sources">, ModeOpt, Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; -def enable_astscope_lookup : Flag<["-"], "enable-astscope-lookup">, - Flags<[FrontendOption]>, - HelpText<"Enable ASTScope-based unqualified name lookup">; - -def disable_astscope_lookup : Flag<["-"], "disable-astscope-lookup">, - Flags<[FrontendOption]>, - HelpText<"Disable ASTScope-based unqualified name lookup">; +def scan_clang_dependencies : Flag<["-"], "scan-clang-dependencies">, + HelpText<"Scan dependencies of the given Clang module">, ModeOpt, + Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; def disable_parser_lookup : Flag<["-"], "disable-parser-lookup">, Flags<[FrontendOption]>, diff --git a/include/swift/Parse/Lexer.h b/include/swift/Parse/Lexer.h index 8cd9b75a415c7..68663f19a3c4e 100644 --- a/include/swift/Parse/Lexer.h +++ b/include/swift/Parse/Lexer.h @@ -352,7 +352,7 @@ class Lexer { static SourceLoc getLocForStartOfLine(SourceManager &SM, SourceLoc Loc); /// Retrieve the source location for the end of the line containing the - /// given token, which is the location of the start of the next line. + /// given location, which is the location of the start of the next line. static SourceLoc getLocForEndOfLine(SourceManager &SM, SourceLoc Loc); /// Retrieve the string used to indent the line that contains the given diff --git a/include/swift/Parse/ParsedRawSyntaxNode.h b/include/swift/Parse/ParsedRawSyntaxNode.h index 916e3d816703b..81985d929fc46 100644 --- a/include/swift/Parse/ParsedRawSyntaxNode.h +++ b/include/swift/Parse/ParsedRawSyntaxNode.h @@ -98,8 +98,8 @@ class ParsedRawSyntaxNode { assert(DeferredToken.NumTrailingTrivia == numTrailingTrivia && "numLeadingTrivia is too large value!"); } - ParsedRawSyntaxNode(ParsedRawSyntaxNode &other) = delete; - ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &other) = delete; + ParsedRawSyntaxNode(const ParsedRawSyntaxNode &other) = delete; + ParsedRawSyntaxNode &operator=(const ParsedRawSyntaxNode &other) = delete; public: ParsedRawSyntaxNode() diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 625092e4a3ba3..18c69502936f9 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -125,9 +125,6 @@ class Parser { CodeCompletionCallbacks *CodeCompletion = nullptr; std::vector>> AnonClosureVars; - /// Tracks parsed decls that LLDB requires to be inserted at the top-level. - std::vector ContextSwitchedTopLevelDecls; - /// The current token hash, or \c None if the parser isn't computing a hash /// for the token stream. Optional CurrentTokenHash; @@ -146,7 +143,6 @@ class Parser { ArrayRef DisabledVars; Diag<> DisabledVarReason; - llvm::SmallPtrSet AlreadyHandledDecls; enum { /// InVarOrLetPattern has this value when not parsing a pattern. IVOLP_NotInVarOrLet, @@ -688,6 +684,14 @@ class Parser { Optional getStringLiteralIfNotInterpolated(SourceLoc Loc, StringRef DiagText); + /// Returns true to indicate that experimental concurrency syntax should be + /// parsed if the parser is generating only a syntax tree or if the user has + /// passed the `-enable-experimental-concurrency` flag to the frontend. + bool shouldParseExperimentalConcurrency() const { + return Context.LangOpts.EnableExperimentalConcurrency || + Context.LangOpts.ParseForSyntaxTreeOnly; + } + public: InFlightDiagnostic diagnose(SourceLoc Loc, Diagnostic Diag) { if (Diags.isDiagnosticPointsToFirstBadToken(Diag.getID()) && @@ -922,14 +926,8 @@ class Parser { void consumeDecl(ParserPosition BeginParserPosition, ParseDeclOptions Flags, bool IsTopLevel); - // When compiling for the Debugger, some Decl's need to be moved from the - // current scope. In which case although the Decl will be returned in the - // ParserResult, it should not be inserted into the Decl list for the current - // context. markWasHandled asserts that the Decl is already where it - // belongs, and declWasHandledAlready is used to check this assertion. - // To keep the handled decl array small, we remove the Decl when it is - // checked, so you can only call declWasAlreadyHandled once for a given - // decl. + /// FIXME: Remove this, it's vestigial. + llvm::SmallPtrSet AlreadyHandledDecls; void markWasHandled(Decl *D) { AlreadyHandledDecls.insert(D); @@ -1125,8 +1123,7 @@ class Parser { ParseDeclOptions Flags, DeclAttributes &Attributes, bool HasFuncKeyword = true); - ParserResult - parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD); + BraceStmt *parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD); void parseAbstractFunctionBody(AbstractFunctionDecl *AFD); BraceStmt *parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD); ParserResult parseDeclProtocol(ParseDeclOptions Flags, @@ -1572,6 +1569,7 @@ class Parser { SmallVectorImpl &captureList, VarDecl *&capturedSelfParamDecl, ParameterList *¶ms, + SourceLoc &asyncLoc, SourceLoc &throwsLoc, SourceLoc &arrowLoc, TypeExpr *&explicitResultType, diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index 08915aa090b73..9e26669aa8f38 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -22,8 +22,10 @@ #include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/Memory.h" #include "swift/ABI/Enum.h" +#include "swift/ABI/ObjectFile.h" #include "swift/Remote/MemoryReader.h" #include "swift/Remote/MetadataReader.h" #include "swift/Reflection/Records.h" @@ -210,12 +212,12 @@ class ReflectionContext auto SectBuf = this->getReader().readBytes(RemoteAddress(RangeStart), RangeEnd - RangeStart); - auto findMachOSectionByName = [&](std::string Name) + auto findMachOSectionByName = [&](llvm::StringRef Name) -> std::pair, uint64_t> { for (unsigned I = 0; I < NumSect; ++I) { auto S = reinterpret_cast( SectionsBuf + (I * sizeof(typename T::Section))); - if (strncmp(S->sectname, Name.c_str(), strlen(Name.c_str())) != 0) + if (strncmp(S->sectname, Name.data(), strlen(Name.data())) != 0) continue; auto RemoteSecStart = S->addr + Slide; auto SectBufData = reinterpret_cast(SectBuf.get()); @@ -228,12 +230,19 @@ class ReflectionContext return {nullptr, 0}; }; - auto FieldMdSec = findMachOSectionByName("__swift5_fieldmd"); - auto AssocTySec = findMachOSectionByName("__swift5_assocty"); - auto BuiltinTySec = findMachOSectionByName("__swift5_builtin"); - auto CaptureSec = findMachOSectionByName("__swift5_capture"); - auto TypeRefMdSec = findMachOSectionByName("__swift5_typeref"); - auto ReflStrMdSec = findMachOSectionByName("__swift5_reflstr"); + SwiftObjectFileFormatMachO ObjectFileFormat; + auto FieldMdSec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::fieldmd)); + auto AssocTySec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::assocty)); + auto BuiltinTySec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::builtin)); + auto CaptureSec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::capture)); + auto TypeRefMdSec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::typeref)); + auto ReflStrMdSec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr)); if (FieldMdSec.first == nullptr && AssocTySec.first == nullptr && @@ -330,12 +339,19 @@ class ReflectionContext return {nullptr, 0}; }; - auto CaptureSec = findCOFFSectionByName(".sw5cptr"); - auto TypeRefMdSec = findCOFFSectionByName(".sw5tyrf"); - auto FieldMdSec = findCOFFSectionByName(".sw5flmd"); - auto AssocTySec = findCOFFSectionByName(".sw5asty"); - auto BuiltinTySec = findCOFFSectionByName(".sw5bltn"); - auto ReflStrMdSec = findCOFFSectionByName(".sw5rfst"); + SwiftObjectFileFormatCOFF ObjectFileFormat; + auto FieldMdSec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::fieldmd)); + auto AssocTySec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::assocty)); + auto BuiltinTySec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::builtin)); + auto CaptureSec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::capture)); + auto TypeRefMdSec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::typeref)); + auto ReflStrMdSec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr)); if (FieldMdSec.first == nullptr && AssocTySec.first == nullptr && @@ -378,29 +394,60 @@ class ReflectionContext return readPECOFFSections(ImageStart); } - template bool readELFSections(RemoteAddress ImageStart) { - auto Buf = - this->getReader().readBytes(ImageStart, sizeof(typename T::Header)); + template + bool readELFSections(RemoteAddress ImageStart, + llvm::Optional FileBuffer) { + // When reading from the FileBuffer we can simply return a pointer to + // the underlying data. + // When reading from the process, we need to keep the memory around + // until the end of the function, so we store it inside ReadDataBuffer. + // We do this so in both cases we can return a simple pointer. + std::vector ReadDataBuffer; + auto readData = [&](uint64_t Offset, uint64_t Size) -> const void * { + if (FileBuffer.hasValue()) { + auto Buffer = FileBuffer.getValue(); + if (Offset + Size > Buffer.allocatedSize()) + return nullptr; + return (const void *)((uint64_t)Buffer.base() + Offset); + } else { + MemoryReader::ReadBytesResult Buf = + this->getReader().readBytes(ImageStart + Offset, Size); + if (!Buf) + return nullptr; + ReadDataBuffer.push_back(std::move(Buf)); + return ReadDataBuffer.back().get(); + } + }; - auto Hdr = reinterpret_cast(Buf.get()); + const void *Buf = readData(0, sizeof(typename T::Header)); + if (!Buf) + return false; + auto Hdr = reinterpret_cast(Buf); assert(Hdr->getFileClass() == T::ELFClass && "invalid ELF file class"); - // From the header, grab informations about the section header table. - auto SectionHdrAddress = ImageStart.getAddressData() + Hdr->e_shoff; - auto SectionHdrNumEntries = Hdr->e_shnum; - auto SectionEntrySize = Hdr->e_shentsize; + // From the header, grab information about the section header table. + uint64_t SectionHdrAddress = Hdr->e_shoff; + uint16_t SectionHdrNumEntries = Hdr->e_shnum; + uint16_t SectionEntrySize = Hdr->e_shentsize; + + if (sizeof(typename T::Section) > SectionEntrySize) + return false; + if (SectionHdrNumEntries == 0) + return false; // Collect all the section headers, we need them to look up the // reflection sections (by name) and the string table. + // We read the section headers from the FileBuffer, since they are + // not mapped in the child process. std::vector SecHdrVec; for (unsigned I = 0; I < SectionHdrNumEntries; ++I) { - auto SecBuf = this->getReader().readBytes( - RemoteAddress(SectionHdrAddress + (I * SectionEntrySize)), - SectionEntrySize); + uint64_t Offset = SectionHdrAddress + (I * SectionEntrySize); + auto SecBuf = readData(Offset, sizeof(typename T::Section)); if (!SecBuf) return false; - auto SecHdr = - reinterpret_cast(SecBuf.get()); + const typename T::Section *SecHdr = + reinterpret_cast(SecBuf); + SecHdrVec.push_back(SecHdr); } @@ -419,37 +466,72 @@ class ReflectionContext typename T::Offset StrTabOffset = SecHdrStrTab->sh_offset; typename T::Size StrTabSize = SecHdrStrTab->sh_size; - auto StrTabStart = - RemoteAddress(ImageStart.getAddressData() + StrTabOffset); - auto StrTabBuf = this->getReader().readBytes(StrTabStart, StrTabSize); - auto StrTab = reinterpret_cast(StrTabBuf.get()); - - auto findELFSectionByName = [&](std::string Name) - -> std::pair, uint64_t> { - // Now for all the sections, find their name. - for (const typename T::Section *Hdr : SecHdrVec) { - uint32_t Offset = Hdr->sh_name; - auto SecName = std::string(StrTab + Offset); - if (SecName != Name) - continue; - auto SecStart = - RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr); - auto SecSize = Hdr->sh_size; - auto SecBuf = this->getReader().readBytes(SecStart, SecSize); - auto SecContents = RemoteRef(SecStart.getAddressData(), - SecBuf.get()); - savedBuffers.push_back(std::move(SecBuf)); - return {SecContents, SecSize}; - } - return {nullptr, 0}; - }; + auto StrTabBuf = readData(StrTabOffset, StrTabSize); + if (!StrTabBuf) + return false; + auto StrTab = reinterpret_cast(StrTabBuf); + bool Error = false; + auto findELFSectionByName = + [&](llvm::StringRef Name) -> std::pair, uint64_t> { + if (Error) + return {nullptr, 0}; + // Now for all the sections, find their name. + for (const typename T::Section *Hdr : SecHdrVec) { + uint32_t Offset = Hdr->sh_name; + const char *Start = (const char *)StrTab + Offset; + uint64_t StringSize = strnlen(Start, StrTabSize - Offset); + if (StringSize > StrTabSize - Offset) { + Error = true; + break; + } + std::string SecName(Start, StringSize); + if (SecName != Name) + continue; + RemoteAddress SecStart = + RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr); + auto SecSize = Hdr->sh_size; + MemoryReader::ReadBytesResult SecBuf; + if (FileBuffer.hasValue()) { + // sh_offset gives us the offset to the section in the file, + // while sh_addr gives us the offset in the process. + auto Offset = Hdr->sh_offset; + if (FileBuffer->allocatedSize() < Offset + SecSize) { + Error = true; + break; + } + auto *Buf = malloc(SecSize); + SecBuf = MemoryReader::ReadBytesResult( + Buf, [](const void *ptr) { free(const_cast(ptr)); }); + memcpy((void *)Buf, + (const void *)((uint64_t)FileBuffer->base() + Offset), + SecSize); + } else { + SecBuf = this->getReader().readBytes(SecStart, SecSize); + } + auto SecContents = + RemoteRef(SecStart.getAddressData(), SecBuf.get()); + savedBuffers.push_back(std::move(SecBuf)); + return {SecContents, SecSize}; + } + return {nullptr, 0}; + }; - auto FieldMdSec = findELFSectionByName("swift5_fieldmd"); - auto AssocTySec = findELFSectionByName("swift5_assocty"); - auto BuiltinTySec = findELFSectionByName("swift5_builtin"); - auto CaptureSec = findELFSectionByName("swift5_capture"); - auto TypeRefMdSec = findELFSectionByName("swift5_typeref"); - auto ReflStrMdSec = findELFSectionByName("swift5_reflstr"); + SwiftObjectFileFormatELF ObjectFileFormat; + auto FieldMdSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::fieldmd)); + auto AssocTySec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::assocty)); + auto BuiltinTySec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::builtin)); + auto CaptureSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::capture)); + auto TypeRefMdSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::typeref)); + auto ReflStrMdSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr)); + + if (Error) + return false; // We succeed if at least one of the sections is present in the // ELF executable. @@ -470,12 +552,28 @@ class ReflectionContext {ReflStrMdSec.first, ReflStrMdSec.second}}; this->addReflectionInfo(info); - - savedBuffers.push_back(std::move(Buf)); return true; } - - bool readELF(RemoteAddress ImageStart) { + + /// Parses metadata information from an ELF image. Because the Section + /// Header Table maybe be missing (for example, when reading from a + /// process) this method optionally receives a buffer with the contents + /// of the image's file, from where it will the necessary information. + /// + /// + /// \param[in] ImageStart + /// A remote address pointing to the start of the image in the running + /// process. + /// + /// \param[in] FileBuffer + /// A buffer which contains the contents of the image's file + /// in disk. If missing, all the information will be read using the + /// instance's memory reader. + /// + /// \return + /// /b True if the metadata information was parsed successfully, + /// /b false otherwise. + bool readELF(RemoteAddress ImageStart, llvm::Optional FileBuffer) { auto Buf = this->getReader().readBytes(ImageStart, sizeof(llvm::ELF::Elf64_Ehdr)); @@ -488,9 +586,11 @@ class ReflectionContext // Check if we have a ELFCLASS32 or ELFCLASS64 unsigned char FileClass = Hdr->getFileClass(); if (FileClass == llvm::ELF::ELFCLASS64) { - return readELFSections>(ImageStart); + return readELFSections>( + ImageStart, FileBuffer); } else if (FileClass == llvm::ELF::ELFCLASS32) { - return readELFSections>(ImageStart); + return readELFSections>( + ImageStart, FileBuffer); } else { return false; } @@ -520,15 +620,16 @@ class ReflectionContext if (MagicBytes[0] == 'M' && MagicBytes[1] == 'Z') { return readPECOFF(ImageStart); } - + + // ELF. if (MagicBytes[0] == llvm::ELF::ElfMagic[0] && MagicBytes[1] == llvm::ELF::ElfMagic[1] && MagicBytes[2] == llvm::ELF::ElfMagic[2] && MagicBytes[3] == llvm::ELF::ElfMagic[3]) { - return readELF(ImageStart); + return readELF(ImageStart, llvm::Optional()); } - + // We don't recognize the format. return false; } @@ -579,7 +680,9 @@ class ReflectionContext /// Return a description of the layout of a class instance with the given /// metadata as its isa pointer. - const TypeInfo *getMetadataTypeInfo(StoredPointer MetadataAddress) { + const TypeInfo * + getMetadataTypeInfo(StoredPointer MetadataAddress, + remote::TypeInfoProvider *ExternalTypeInfo) { // See if we cached the layout already auto found = Cache.find(MetadataAddress); if (found != Cache.end()) @@ -601,7 +704,7 @@ class ReflectionContext // Perform layout if (start) - TI = TC.getClassInstanceTypeInfo(TR, *start); + TI = TC.getClassInstanceTypeInfo(TR, *start, ExternalTypeInfo); break; } @@ -617,7 +720,9 @@ class ReflectionContext /// Return a description of the layout of a class instance with the given /// metadata as its isa pointer. - const TypeInfo *getInstanceTypeInfo(StoredPointer ObjectAddress) { + const TypeInfo * + getInstanceTypeInfo(StoredPointer ObjectAddress, + remote::TypeInfoProvider *ExternalTypeInfo) { auto MetadataAddress = readMetadataFromInstance(ObjectAddress); if (!MetadataAddress) return nullptr; @@ -628,7 +733,7 @@ class ReflectionContext switch (*kind) { case MetadataKind::Class: - return getMetadataTypeInfo(*MetadataAddress); + return getMetadataTypeInfo(*MetadataAddress, ExternalTypeInfo); case MetadataKind::HeapLocalVariable: { auto CDAddr = this->readCaptureDescriptorFromMetadata(*MetadataAddress); @@ -650,7 +755,7 @@ class ReflectionContext auto Info = getBuilder().getClosureContextInfo(CD); - return getClosureContextInfo(ObjectAddress, Info); + return getClosureContextInfo(ObjectAddress, Info, ExternalTypeInfo); } case MetadataKind::HeapGenericLocalVariable: { @@ -659,7 +764,8 @@ class ReflectionContext if (auto Meta = readMetadata(*MetadataAddress)) { auto GenericHeapMeta = cast>(Meta.getLocalBuffer()); - return getMetadataTypeInfo(GenericHeapMeta->BoxedType); + return getMetadataTypeInfo(GenericHeapMeta->BoxedType, + ExternalTypeInfo); } return nullptr; } @@ -673,15 +779,15 @@ class ReflectionContext } } - bool - projectExistential(RemoteAddress ExistentialAddress, - const TypeRef *ExistentialTR, - const TypeRef **OutInstanceTR, - RemoteAddress *OutInstanceAddress) { + bool projectExistential(RemoteAddress ExistentialAddress, + const TypeRef *ExistentialTR, + const TypeRef **OutInstanceTR, + RemoteAddress *OutInstanceAddress, + remote::TypeInfoProvider *ExternalTypeInfo) { if (ExistentialTR == nullptr) return false; - auto ExistentialTI = getTypeInfo(ExistentialTR); + auto ExistentialTI = getTypeInfo(ExistentialTR, ExternalTypeInfo); if (ExistentialTI == nullptr) return false; @@ -745,14 +851,14 @@ class ReflectionContext /// Returns true if the enum case could be successfully determined. In /// particular, note that this code may return false for valid in-memory data /// if the compiler used a strategy we do not yet understand. - bool projectEnumValue(RemoteAddress EnumAddress, - const TypeRef *EnumTR, - int *CaseIndex) { + bool projectEnumValue(RemoteAddress EnumAddress, const TypeRef *EnumTR, + int *CaseIndex, + remote::TypeInfoProvider *ExternalTypeInfo) { // Get the TypeInfo and sanity-check it if (EnumTR == nullptr) { return false; } - auto TI = getTypeInfo(EnumTR); + auto TI = getTypeInfo(EnumTR, ExternalTypeInfo); if (TI == nullptr) { return false; } @@ -764,11 +870,12 @@ class ReflectionContext } /// Return a description of the layout of a value with the given type. - const TypeInfo *getTypeInfo(const TypeRef *TR) { + const TypeInfo *getTypeInfo(const TypeRef *TR, + remote::TypeInfoProvider *ExternalTypeInfo) { if (TR == nullptr) { return nullptr; } else { - return getBuilder().getTypeConverter().getTypeInfo(TR); + return getBuilder().getTypeConverter().getTypeInfo(TR, ExternalTypeInfo); } } @@ -778,7 +885,8 @@ class ReflectionContext std::function Call) { if (!NodePtr) return; - auto NodeBytes = getReader().readBytes(RemoteAddress(NodePtr), sizeof(Node)); + auto NodeBytes = getReader().readBytes(RemoteAddress(NodePtr), + sizeof(ConformanceNode)); auto NodeData = reinterpret_cast *>(NodeBytes.get()); if (!NodeData) @@ -788,6 +896,33 @@ class ReflectionContext iterateConformanceTree(NodeData->Right, Call); } + void IterateConformanceTable( + RemoteAddress ConformancesPtr, + std::function Call) { + auto MapBytes = getReader().readBytes(RemoteAddress(ConformancesPtr), + sizeof(ConcurrentHashMap)); + auto MapData = + reinterpret_cast *>(MapBytes.get()); + if (!MapData) + return; + + auto Count = MapData->ElementCount; + auto Size = Count * sizeof(ConformanceCacheEntry); + + auto ElementsBytes = + getReader().readBytes(RemoteAddress(MapData->Elements), Size); + auto ElementsData = + reinterpret_cast *>( + ElementsBytes.get()); + if (!ElementsData) + return; + + for (StoredSize i = 0; i < Count; i++) { + auto &Element = ElementsData[i]; + Call(Element.Type, Element.Proto); + } + } + /// Iterate the protocol conformance cache in the target process, calling Call /// with the type and protocol of each conformance. Returns None on success, /// and a string describing the error on failure. @@ -807,7 +942,26 @@ class ReflectionContext auto Root = getReader().readPointer(ConformancesAddr->getResolvedAddress(), sizeof(StoredPointer)); - iterateConformanceTree(Root->getResolvedAddress().getAddressData(), Call); + auto ReaderCount = Root->getResolvedAddress().getAddressData(); + + // ReaderCount will be the root pointer if the conformance cache is a + // ConcurrentMap. It's very unlikely that there would ever be more readers + // than the least valid pointer value, so compare with that to distinguish. + // TODO: once the old conformance cache is gone for good, remove that code. + uint64_t LeastValidPointerValue; + if (!getReader().queryDataLayout( + DataLayoutQueryType::DLQ_GetLeastValidPointerValue, nullptr, + &LeastValidPointerValue)) { + return std::string("unable to query least valid pointer value"); + } + + if (ReaderCount < LeastValidPointerValue) + IterateConformanceTable(ConformancesAddr->getResolvedAddress(), Call); + else { + // The old code has the root address at this location. + auto RootAddr = ReaderCount; + iterateConformanceTree(RootAddr, Call); + } return llvm::None; } @@ -1012,8 +1166,9 @@ class ReflectionContext } private: - const TypeInfo *getClosureContextInfo(StoredPointer Context, - const ClosureContextInfo &Info) { + const TypeInfo * + getClosureContextInfo(StoredPointer Context, const ClosureContextInfo &Info, + remote::TypeInfoProvider *ExternalTypeInfo) { RecordTypeInfoBuilder Builder(getBuilder().getTypeConverter(), RecordKind::ClosureContext); @@ -1071,7 +1226,7 @@ class ReflectionContext SubstCaptureTR = OrigCaptureTR; if (SubstCaptureTR != nullptr) { - Builder.addField("", SubstCaptureTR); + Builder.addField("", SubstCaptureTR, ExternalTypeInfo); if (Builder.isInvalid()) return nullptr; diff --git a/include/swift/Reflection/RuntimeInternals.h b/include/swift/Reflection/RuntimeInternals.h index 11b6027242aaf..30ec8827c8515 100644 --- a/include/swift/Reflection/RuntimeInternals.h +++ b/include/swift/Reflection/RuntimeInternals.h @@ -46,6 +46,20 @@ template struct MetadataCacheNode { typename Runtime::StoredPointer Right; }; +template struct ConcurrentHashMap { + typename Runtime::StoredSize ReaderCount; + typename Runtime::StoredSize ElementCount; + typename Runtime::StoredPointer Elements; + typename Runtime::StoredPointer Indices; + // We'll ignore the remaining fields for now.... +}; + +template struct ConformanceCacheEntry { + typename Runtime::StoredPointer Type; + typename Runtime::StoredPointer Proto; + typename Runtime::StoredPointer Witness; +}; + } // end namespace reflection } // end namespace swift diff --git a/include/swift/Reflection/TypeLowering.h b/include/swift/Reflection/TypeLowering.h index 13eda217e1510..9c278fa7ac3ac 100644 --- a/include/swift/Reflection/TypeLowering.h +++ b/include/swift/Reflection/TypeLowering.h @@ -22,6 +22,7 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/Support/Casting.h" #include "swift/Remote/MetadataReader.h" +#include "swift/Remote/TypeInfoProvider.h" #include @@ -181,7 +182,7 @@ class BuiltinTypeInfo : public TypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *extraInhabitantIndex) const; + int *extraInhabitantIndex) const override; static bool classof(const TypeInfo *TI) { return TI->getKind() == TypeInfoKind::Builtin; @@ -208,7 +209,7 @@ class RecordTypeInfo : public TypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *index) const; + int *index) const override; static bool classof(const TypeInfo *TI) { return TI->getKind() == TypeInfoKind::Record; @@ -299,7 +300,7 @@ class ReferenceTypeInfo : public TypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *extraInhabitantIndex) const { + int *extraInhabitantIndex) const override { if (getNumExtraInhabitants() == 0) { *extraInhabitantIndex = -1; return true; @@ -316,7 +317,8 @@ class ReferenceTypeInfo : public TypeInfo { class TypeConverter { TypeRefBuilder &Builder; std::vector> Pool; - llvm::DenseMap Cache; + llvm::DenseMap, + const TypeInfo *> Cache; llvm::DenseSet RecursionCheck; llvm::DenseMap, const ReferenceTypeInfo *> ReferenceCache; @@ -347,14 +349,16 @@ class TypeConverter { /// /// The type must either be concrete, or at least fixed-size, as /// determined by the isFixedSize() predicate. - const TypeInfo *getTypeInfo(const TypeRef *TR); + const TypeInfo *getTypeInfo(const TypeRef *TR, + remote::TypeInfoProvider *externalInfo); /// Returns layout information for an instance of the given /// class. /// /// Not cached. - const TypeInfo *getClassInstanceTypeInfo(const TypeRef *TR, - unsigned start); + const TypeInfo * + getClassInstanceTypeInfo(const TypeRef *TR, unsigned start, + remote::TypeInfoProvider *ExternalTypeInfo); private: friend class swift::reflection::LowerType; @@ -415,7 +419,8 @@ class RecordTypeInfoBuilder { bool bitwiseTakable); // Add a field of a record type, such as a struct. - void addField(const std::string &Name, const TypeRef *TR); + void addField(const std::string &Name, const TypeRef *TR, + remote::TypeInfoProvider *ExternalTypeInfo); const RecordTypeInfo *build(); diff --git a/include/swift/Reflection/TypeRef.h b/include/swift/Reflection/TypeRef.h index 2637f616ae007..fb03cbc9e2e82 100644 --- a/include/swift/Reflection/TypeRef.h +++ b/include/swift/Reflection/TypeRef.h @@ -156,8 +156,8 @@ class alignas(void *) TypeRef { bool isConcrete() const; bool isConcreteAfterSubstitutions(const GenericArgumentMap &Subs) const; - const TypeRef * - subst(TypeRefBuilder &Builder, const GenericArgumentMap &Subs) const; + const TypeRef *subst(TypeRefBuilder &Builder, + const GenericArgumentMap &Subs) const; llvm::Optional getSubstMap() const; @@ -301,27 +301,48 @@ class BoundGenericTypeRef final : public TypeRef, public NominalTypeTrait { }; class TupleTypeRef final : public TypeRef { +protected: std::vector Elements; + std::string Labels; - static TypeRefID Profile(const std::vector &Elements) { + static TypeRefID Profile(const std::vector &Elements, + const std::string &Labels) { TypeRefID ID; for (auto Element : Elements) ID.addPointer(Element); + ID.addString(Labels); return ID; } public: - TupleTypeRef(std::vector Elements) - : TypeRef(TypeRefKind::Tuple), Elements(std::move(Elements)) {} + TupleTypeRef(std::vector Elements, std::string &&Labels) + : TypeRef(TypeRefKind::Tuple), Elements(std::move(Elements)), + Labels(Labels) {} template static const TupleTypeRef *create(Allocator &A, - std::vector Elements) { - FIND_OR_CREATE_TYPEREF(A, TupleTypeRef, Elements); - } - - const std::vector &getElements() const { - return Elements; + std::vector Elements, + std::string &&Labels) { + FIND_OR_CREATE_TYPEREF(A, TupleTypeRef, Elements, Labels); + } + + const std::vector &getElements() const { return Elements; }; + const std::string &getLabelString() const { return Labels; }; + std::vector getLabels() const { + std::vector Vec; + std::string::size_type End, Start = 0; + while (true) { + End = Labels.find(' ', Start); + if (End == std::string::npos) + break; + Vec.push_back(llvm::StringRef(Labels.data() + Start, End - Start)); + Start = End + 1; + } + // A canonicalized TypeRef has an empty label string. + // Pad the vector with empty labels. + for (unsigned N = Vec.size(); N < Elements.size(); ++N) + Vec.push_back({}); + return Vec; }; static bool classof(const TypeRef *TR) { diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index f375918a5ff5d..982bcba2edb4c 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -405,9 +405,7 @@ class TypeRefBuilder { const TupleTypeRef *createTupleType(llvm::ArrayRef elements, std::string &&labels) { - // FIXME: Add uniqueness checks in TupleTypeRef::Profile and - // unittests/Reflection/TypeRef.cpp if using labels for identity. - return TupleTypeRef::create(*this, elements); + return TupleTypeRef::create(*this, elements, std::move(labels)); } const FunctionTypeRef *createFunctionType( @@ -618,8 +616,8 @@ class TypeRefBuilder { }), OpaqueUnderlyingTypeReader( [&reader](uint64_t descriptorAddr, unsigned ordinal) -> const TypeRef* { - return reader.readUnderlyingTypeForOpaqueTypeDescriptor(descriptorAddr, - ordinal); + return reader.readUnderlyingTypeForOpaqueTypeDescriptor( + descriptorAddr, ordinal).getType(); }) {} @@ -634,16 +632,14 @@ class TypeRefBuilder { const std::string &Member, StringRef Protocol); - const TypeRef * - lookupSuperclass(const TypeRef *TR); + const TypeRef *lookupSuperclass(const TypeRef *TR); /// Load unsubstituted field types for a nominal type. - RemoteRef - getFieldTypeInfo(const TypeRef *TR); + RemoteRef getFieldTypeInfo(const TypeRef *TR); /// Get the parsed and substituted field types for a nominal type. - bool getFieldTypeRefs(const TypeRef *TR, - RemoteRef FD, + bool getFieldTypeRefs(const TypeRef *TR, RemoteRef FD, + remote::TypeInfoProvider *ExternalTypeInfo, std::vector &Fields); /// Get the primitive type lowering for a builtin type. diff --git a/include/swift/Remote/MemoryReader.h b/include/swift/Remote/MemoryReader.h index 6575f83f3cf25..6dfd4c755a487 100644 --- a/include/swift/Remote/MemoryReader.h +++ b/include/swift/Remote/MemoryReader.h @@ -37,7 +37,8 @@ namespace remote { class MemoryReader { public: /// A convenient name for the return type from readBytes. - using ReadBytesResult = std::unique_ptr>; + using ReadBytesResult = + std::unique_ptr>; virtual bool queryDataLayout(DataLayoutQueryType type, void *inBuffer, void *outBuffer) = 0; @@ -152,9 +153,8 @@ class MemoryReader { return resolvePointer(address, pointerData); } - - // Parse extra inhabitants stored in a pointer. + // Parse extra inhabitants stored in a pointer. // Sets *extraInhabitant to -1 if the pointer at this address // is actually a valid pointer. // Otherwise, it sets *extraInhabitant to the inhabitant diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index 4450066283afc..0090ae0746ed6 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -463,7 +463,8 @@ class MetadataReader { } /// Given a demangle tree, attempt to turn it into a type. - BuiltType decodeMangledType(NodePointer Node) { + TypeLookupErrorOr + decodeMangledType(NodePointer Node) { return swift::Demangle::decodeMangledType(Builder, Node); } @@ -925,8 +926,8 @@ class MetadataReader { swift_runtime_unreachable("Unhandled MetadataKind in switch"); } - BuiltType readTypeFromMangledName(const char *MangledTypeName, - size_t Length) { + TypeLookupErrorOr + readTypeFromMangledName(const char *MangledTypeName, size_t Length) { Demangle::Demangler Dem; Demangle::NodePointer Demangled = Dem.demangleSymbol(StringRef(MangledTypeName, Length)); @@ -1183,14 +1184,14 @@ class MetadataReader { MangledNameKind::Type, Dem); } - BuiltType + TypeLookupErrorOr readUnderlyingTypeForOpaqueTypeDescriptor(StoredPointer contextAddr, unsigned ordinal) { Demangle::Demangler Dem; auto node = readUnderlyingTypeManglingForOpaqueTypeDescriptor(contextAddr, ordinal, Dem); if (!node) - return BuiltType(); + return TypeLookupError("Failed to read type mangling for descriptor."); return decodeMangledType(node); } diff --git a/include/swift/Remote/TypeInfoProvider.h b/include/swift/Remote/TypeInfoProvider.h new file mode 100644 index 0000000000000..73995ca069247 --- /dev/null +++ b/include/swift/Remote/TypeInfoProvider.h @@ -0,0 +1,39 @@ +//===--- TypeInfoProvider.h - Abstract access to type info ------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file declares an abstract interface for reading type layout info. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_REMOTE_TYPEINFOPROVIDER_H +#define SWIFT_REMOTE_TYPEINFOPROVIDER_H + +namespace swift { +namespace reflection { +class TypeInfo; +} +namespace remote { + +/// An abstract interface for providing external type layout information. +struct TypeInfoProvider { + virtual ~TypeInfoProvider() = default; + + /// Attempt to read type information about (Clang)imported types that are not + /// represented in the metadata. LLDB can read this information from debug + /// info, for example. + virtual const reflection::TypeInfo * + getTypeInfo(llvm::StringRef mangledName) = 0; +}; + +} // namespace remote +} // namespace swift +#endif diff --git a/include/swift/Runtime/Concurrent.h b/include/swift/Runtime/Concurrent.h index 7e4ed718b131b..e634fbc25660d 100644 --- a/include/swift/Runtime/Concurrent.h +++ b/include/swift/Runtime/Concurrent.h @@ -17,6 +17,7 @@ #include #include #include +#include "llvm/ADT/Hashing.h" #include "llvm/Support/Allocator.h" #include "Atomic.h" #include "Debug.h" @@ -26,6 +27,10 @@ #include #endif +#if defined(__APPLE__) && defined(__MACH__) +#include +#endif + namespace swift { /// This is a node in a concurrent linked list. @@ -488,8 +493,8 @@ template struct ConcurrentReadableArray { const ElemTy *end() { return Start + Count; } size_t count() { return Count; } }; - - // This type cannot be safely copied, moved, or deleted. + + // This type cannot be safely copied or moved. ConcurrentReadableArray(const ConcurrentReadableArray &) = delete; ConcurrentReadableArray(ConcurrentReadableArray &&) = delete; ConcurrentReadableArray &operator=(const ConcurrentReadableArray &) = delete; @@ -512,7 +517,7 @@ template struct ConcurrentReadableArray { auto *newStorage = Storage::allocate(newCapacity); if (storage) { std::copy(storage->data(), storage->data() + count, newStorage->data()); - newStorage->Count.store(count, std::memory_order_relaxed); + newStorage->Count.store(count, std::memory_order_release); FreeList.push_back(storage); } @@ -527,7 +532,7 @@ template struct ConcurrentReadableArray { if (ReaderCount.load(std::memory_order_acquire) == 0) deallocateFreeList(); } - + Snapshot snapshot() { incrementReaders(); auto *storage = Elements.load(SWIFT_MEMORY_ORDER_CONSUME); @@ -541,6 +546,416 @@ template struct ConcurrentReadableArray { } }; +using llvm::hash_value; + +/// A hash table that can be queried without taking any locks. Writes are still +/// locked and serialized, but only with respect to other locks. Writers can add +/// elements and clear the table, but they cannot remove individual elements. +/// Readers work by taking a snapshot of the table and then querying that +/// snapshot. +/// +/// The basic structure of the table consists of two arrays. Elements are stored +/// in a contiguous array, with new elements appended to the end. The second +/// array is the actual hash table, and it contains indices into the elements +/// array. This scheme cuts down on wasted space when the elements are larger +/// than a few bytes: instead of wasting `(1 - loadFactor) * sizeof(element)` +/// bytes on unused space in the hash table, we only waste `(1 - loadFactor) * +/// sizeof(index)`. This scheme also avoids readers seeing partially constructed +/// elements. +/// +/// Reader/writer synchronization for new elements is handled by keeping an +/// element count which is only incremented when the element has been fully +/// constructed. A reader which sees an index beyond its view of the current +/// count will ignore it and treat that as if there was no entry. +/// +/// Reader/writer synchronization for resizing the arrays is handled by tracking +/// the current number of active readers. When resizing, the new array is +/// allocated, the data copied, and then the old array is placed in a free list. +/// The free list is only deallocated if there are no readers, otherwise freeing +/// is deferred. +/// +/// Reader/writer synchronization for clearing the table is a combination of the +/// above. By keeping the old arrays around until all readers are finished, we +/// ensure that readers which started before the clear see valid (pre-clear) +/// data. Readers which see any array as empty will produce no results, thus +/// providing valid post-clear data. +template struct ConcurrentReadableHashMap { + // We use memcpy and don't call destructors. Make sure the elements will put + // up with this. + static_assert(std::is_trivially_copyable::value, + "Elements must be trivially copyable."); + static_assert(std::is_trivially_destructible::value, + "Elements must not have destructors (they won't be called)."); + +private: + /// The type of the elements of the indices array. TODO: use one or two byte + /// indices for smaller tables to save more memory. + using Index = unsigned; + + /// The reciprocal of the load factor at which we expand the table. A value of + /// 4 means that we resize at 1/4 = 75% load factor. + static const size_t ResizeProportion = 4; + + /// Get the "good size" for a given allocation size. When available, this + /// rounds up to the next allocation quantum by calling `malloc_good_size`. + /// Otherwise, just return the passed-in size, which is always valid even if + /// not necessarily optimal. + size_t goodSize(size_t size) { +#if defined(__APPLE__) && defined(__MACH__) + return malloc_good_size(size); +#else + return size; +#endif + } + + /// A private class representing the storage of the indices. In order to + /// ensure that readers can get a consistent view of the indices with a single + /// atomic read, we store the size of the indices array inline, as the first + /// element in the array. + /// + /// We want the number of indices to be a power of two so that we can use a + /// bitwise AND to convert a hash code to an index. We want the entire array + /// to be a power of two in size to be friendly to the allocator, but the size + /// is stored inline. We work around this contradiction by considering the + /// first index to always be occupied with a value that never matches any key. + struct IndexStorage { + std::atomic Mask; + + static IndexStorage *allocate(size_t capacity) { + assert((capacity & (capacity - 1)) == 0 && + "Capacity must be a power of 2"); + auto *ptr = + reinterpret_cast(calloc(capacity, sizeof(Mask))); + if (!ptr) + swift::crash("Could not allocate memory."); + ptr->Mask.store(capacity - 1, std::memory_order_relaxed); + return ptr; + } + + std::atomic &at(size_t i) { return (&Mask)[i]; } + }; + + /// A simple linked list representing pointers that need to be freed. + struct FreeListNode { + FreeListNode *Next; + void *Ptr; + + static void add(FreeListNode **head, void *ptr) { + auto *newNode = new FreeListNode{*head, ptr}; + *head = newNode; + } + + static void freeAll(FreeListNode **head) { + auto *node = *head; + while (node) { + auto *next = node->Next; + free(node->Ptr); + delete node; + node = next; + } + *head = nullptr; + } + }; + + /// The number of readers currently active, equal to the number of snapshot + /// objects currently alive. + std::atomic ReaderCount{0}; + + /// The number of elements in the elements array. + std::atomic ElementCount{0}; + + /// The array of elements. + std::atomic Elements{nullptr}; + + /// The array of indices. + std::atomic Indices{nullptr}; + + /// The writer lock, which must be taken before any mutation of the table. + Mutex WriterLock; + + /// The maximum number of elements that the current elements array can hold. + uint32_t ElementCapacity{0}; + + /// The list of pointers to be freed once no readers are active. + FreeListNode *FreeList{nullptr}; + + void incrementReaders() { + ReaderCount.fetch_add(1, std::memory_order_acquire); + } + + void decrementReaders() { + ReaderCount.fetch_sub(1, std::memory_order_release); + } + + /// Free all the arrays in the free lists if there are no active readers. If + /// there are active readers, do nothing. + void deallocateFreeListIfSafe() { + if (ReaderCount.load(std::memory_order_acquire) == 0) + FreeListNode::freeAll(&FreeList); + } + + /// Grow the elements array, adding the old array to the free list and + /// returning the new array with all existing elements copied into it. + ElemTy *resize(ElemTy *elements, size_t elementCount) { + // Grow capacity by 25%, making sure we grow by at least 1. + size_t newCapacity = + std::max(elementCount + (elementCount >> 2), elementCount + 1); + size_t newSize = newCapacity * sizeof(ElemTy); + + newSize = goodSize(newSize); + newCapacity = newSize / sizeof(ElemTy); + + ElemTy *newElements = static_cast(malloc(newSize)); + if (elements) { + memcpy(newElements, elements, elementCount * sizeof(ElemTy)); + FreeListNode::add(&FreeList, elements); + } + + ElementCapacity = newCapacity; + Elements.store(newElements, std::memory_order_release); + return newElements; + } + + /// Grow the indices array, adding the old array to the free list and + /// returning the new array with all existing indices copied into it. This + /// operation performs a rehash, so that the indices are in the correct + /// location in the new array. + IndexStorage *resize(IndexStorage *indices, Index indicesMask, + ElemTy *elements) { + // Mask is size - 1. Double the size. Start with 4 (fits into 16-byte malloc + // bucket). + size_t newCount = indices ? 2 * (indicesMask + 1) : 4; + size_t newMask = newCount - 1; + + IndexStorage *newIndices = IndexStorage::allocate(newCount); + + for (size_t i = 1; i <= indicesMask; i++) { + Index index = indices->at(i).load(std::memory_order_relaxed); + if (index == 0) + continue; + + auto *element = &elements[index - 1]; + auto hash = hash_value(*element); + + size_t newI = hash & newMask; + while (newIndices->at(newI) != 0) + newI = (newI + 1) & newMask; + newIndices->at(newI).store(index, std::memory_order_relaxed); + } + + Indices.store(newIndices, std::memory_order_release); + + FreeListNode::add(&FreeList, indices); + + return newIndices; + } + + /// Search for the given key within the given indices and elements arrays. If + /// an entry already exists for that key, return a pointer to the element. If + /// no entry exists, return a pointer to the location in the indices array + /// where the index of the new element would be stored. + template + static std::pair *> + find(const KeyTy &key, IndexStorage *indices, size_t elementCount, + ElemTy *elements) { + if (!indices) + return {nullptr, nullptr}; + auto hash = hash_value(key); + auto indicesMask = indices->Mask.load(std::memory_order_relaxed); + + auto i = hash & indicesMask; + while (true) { + // Index 0 is used for the mask and is not actually an index. + if (i == 0) + i++; + + auto *indexPtr = &indices->at(i); + auto index = indexPtr->load(std::memory_order_acquire); + // Element indices are 1-based, 0 means no entry. + if (index == 0) + return {nullptr, indexPtr}; + if (index - 1 < elementCount) { + auto *candidate = &elements[index - 1]; + if (candidate->matchesKey(key)) + return {candidate, nullptr}; + } + + i = (i + 1) & indicesMask; + } + } + +public: + // This type cannot be safely copied or moved. + ConcurrentReadableHashMap(const ConcurrentReadableHashMap &) = delete; + ConcurrentReadableHashMap(ConcurrentReadableHashMap &&) = delete; + ConcurrentReadableHashMap & + operator=(const ConcurrentReadableHashMap &) = delete; + + ConcurrentReadableHashMap() + : ReaderCount(0), ElementCount(0), Elements(nullptr), Indices(nullptr), + ElementCapacity(0) {} + + ~ConcurrentReadableHashMap() { + assert(ReaderCount.load(std::memory_order_acquire) == 0 && + "deallocating ConcurrentReadableHashMap with outstanding snapshots"); + FreeListNode::freeAll(&FreeList); + } + + /// Readers take a snapshot of the hash map, then work with the snapshot. + class Snapshot { + ConcurrentReadableHashMap *Map; + IndexStorage *Indices; + ElemTy *Elements; + size_t ElementCount; + + public: + Snapshot(ConcurrentReadableHashMap *map, IndexStorage *indices, + ElemTy *elements, size_t elementCount) + : Map(map), Indices(indices), Elements(elements), + ElementCount(elementCount) {} + + Snapshot(const Snapshot &other) + : Map(other.Map), Indices(other.Indices), Elements(other.Elements), + ElementCount(other.ElementCount) { + Map->incrementReaders(); + } + + ~Snapshot() { Map->decrementReaders(); } + + /// Search for an element matching the given key. Returns a pointer to the + /// found element, or nullptr if no matching element exists. + template const ElemTy *find(const KeyTy &key) { + if (!Indices || !ElementCount || !Elements) + return nullptr; + return ConcurrentReadableHashMap::find(key, Indices, ElementCount, + Elements) + .first; + } + }; + + /// Take a snapshot of the current state of the hash map. + Snapshot snapshot() { + incrementReaders(); + + // Carefully loading the indices, element count, and elements pointer in + // order ensures a consistent view of the table with respect to concurrent + // inserts. However, this is not sufficient to avoid an inconsistent view + // with respect to concurrent clears. The danger scenario is: + // + // 1. Read indices and elementCount from a table with N entries. + // 2. Another thread clears the table. + // 3. Another thread inserts M entries, where M < N. + // 4. The reader thread reads elements. + // 5. The reader thread performs a find. The key's hash leads us to an index + // I, where > M. + // 6. The reader thread reads from element I, which is off the end of the + // elements array. + // + // To avoid this, read the elements pointer twice, at the beginning and end. + // If the values are not the same then there may have been a clear in the + // middle, so we retry. This will have false positives: a new element + // pointer can just mean a concurrent insert that triggered a resize of the + // elements array. This is harmless aside from a small performance hit, and + // should not happen often. + IndexStorage *indices; + size_t elementCount; + ElemTy *elements; + ElemTy *elements2; + do { + elements = Elements.load(std::memory_order_acquire); + indices = Indices.load(std::memory_order_acquire); + elementCount = ElementCount.load(std::memory_order_acquire); + elements2 = Elements.load(std::memory_order_acquire); + } while (elements != elements2); + + return Snapshot(this, indices, elements, elementCount); + } + + /// Get an element by key, or insert a new element for that key if one is not + /// already present. Invoke `call` with the pointer to the element. BEWARE: + /// `call` is invoked with the internal writer lock held, keep work to a + /// minimum. + /// + /// `call` is passed the following parameters: + /// - `element`: the pointer to the element corresponding to `key` + /// - `created`: true if the element is newly created, false if it already + /// exists + /// `call` returns a `bool`. When `created` is `true`, the return values mean: + /// - `true` the new entry is to be kept + /// - `false` indicates that the new entry is discarded + /// If the new entry is kept, then the new element MUST be initialized, and + /// have a hash value that matches the hash value of `key`. + /// + /// The return value is ignored when `created` is `false`. + template + void getOrInsert(KeyTy key, const Call &call) { + ScopedLock guard(WriterLock); + + auto *indices = Indices.load(std::memory_order_relaxed); + if (!indices) + indices = resize(indices, 0, nullptr); + + auto indicesMask = indices->Mask.load(std::memory_order_relaxed); + auto elementCount = ElementCount.load(std::memory_order_relaxed); + auto *elements = Elements.load(std::memory_order_relaxed); + + auto found = find(key, indices, elementCount, elements); + if (found.first) { + call(found.first, false); + deallocateFreeListIfSafe(); + return; + } + + // The actual capacity is indicesMask + 1. The number of slots in use is + // elementCount + 1, since the mask also takes a slot. + auto emptyCount = (indicesMask + 1) - (elementCount + 1); + auto proportion = (indicesMask + 1) / emptyCount; + if (proportion >= ResizeProportion) { + indices = resize(indices, indicesMask, elements); + found = find(key, indices, elementCount, elements); + assert(!found.first && "Shouldn't suddenly find the key after rehashing"); + } + + if (elementCount >= ElementCapacity) { + elements = resize(elements, elementCount); + } + auto *element = &elements[elementCount]; + + // Order matters: fill out the element, then update the count, + // then update the index. + bool keep = call(element, true); + if (keep) { + assert(hash_value(key) == hash_value(*element) && + "Element must have the same hash code as its key."); + ElementCount.store(elementCount + 1, std::memory_order_release); + found.second->store(elementCount + 1, std::memory_order_release); + } + + deallocateFreeListIfSafe(); + } + + /// Clear the hash table, freeing (when safe) all memory currently used for + /// indices and elements. + void clear() { + ScopedLock guard(WriterLock); + + auto *indices = Indices.load(std::memory_order_relaxed); + auto *elements = Elements.load(std::memory_order_relaxed); + + // Order doesn't matter here, snapshots will gracefully handle any field + // being NULL/0 while the others are not. + Indices.store(nullptr, std::memory_order_relaxed); + ElementCount.store(0, std::memory_order_relaxed); + Elements.store(nullptr, std::memory_order_relaxed); + ElementCapacity = 0; + + FreeListNode::add(&FreeList, indices); + FreeListNode::add(&FreeList, elements); + + deallocateFreeListIfSafe(); + } +}; + } // end namespace swift #endif // SWIFT_RUNTIME_CONCURRENTUTILS_H diff --git a/include/swift/Runtime/Debug.h b/include/swift/Runtime/Debug.h index 86e19642e51a7..f14e8d16f1554 100644 --- a/include/swift/Runtime/Debug.h +++ b/include/swift/Runtime/Debug.h @@ -21,7 +21,6 @@ #include "swift/Runtime/Unreachable.h" #include #include -#include #include #include @@ -248,39 +247,6 @@ std::atomic _swift_debug_metadataAllocationBacktraceList; SWIFT_RUNTIME_STDLIB_SPI const void * const _swift_debug_protocolConformanceStatePointer; -SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE -inline static int swift_asprintf(char **strp, const char *fmt, ...) { - va_list args; - va_start(args, fmt); -#if defined(_WIN32) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuninitialized" - int len = _vscprintf(fmt, args); -#pragma GCC diagnostic pop - if (len < 0) { - va_end(args); - return -1; - } - char *buffer = static_cast(malloc(len + 1)); - if (!buffer) { - va_end(args); - return -1; - } - int result = vsprintf(buffer, fmt, args); - if (result < 0) { - va_end(args); - free(buffer); - return -1; - } - *strp = buffer; -#else - int result = vasprintf(strp, fmt, args); -#endif - va_end(args); - return result; -} - - // namespace swift } diff --git a/include/swift/Runtime/Mutex.h b/include/swift/Runtime/Mutex.h index 019bd5b3b913a..aff2005d87514 100644 --- a/include/swift/Runtime/Mutex.h +++ b/include/swift/Runtime/Mutex.h @@ -20,12 +20,18 @@ #include -#if (defined(__APPLE__) || defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)) +#if __has_include() +#include +#endif + +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#include "swift/Runtime/MutexSingleThreaded.h" +#elif defined(_POSIX_THREADS) #include "swift/Runtime/MutexPThread.h" #elif defined(_WIN32) #include "swift/Runtime/MutexWin32.h" #elif defined(__wasi__) -#include "swift/Runtime/MutexWASI.h" +#include "swift/Runtime/MutexSingleThreaded.h" #else #error "Implement equivalent of MutexPThread.h/cpp for your platform." #endif diff --git a/include/swift/Runtime/MutexWASI.h b/include/swift/Runtime/MutexSingleThreaded.h similarity index 82% rename from include/swift/Runtime/MutexWASI.h rename to include/swift/Runtime/MutexSingleThreaded.h index 153a5f87b11dd..b7323c4b67389 100644 --- a/include/swift/Runtime/MutexWASI.h +++ b/include/swift/Runtime/MutexSingleThreaded.h @@ -1,4 +1,4 @@ -//===--- MutexWASI.h - -----------------------------------------*- C++ -*-===// +//===--- MutexSingleThreaded.h - --------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // @@ -10,16 +10,14 @@ // //===----------------------------------------------------------------------===// // -// No-op implementation of locks for the WebAssembly System Interface. The -// implementation does not need to perform locking, because as of January 2020 -// WebAssembly does not support threads. -// See the current status at https://github.com/WebAssembly/proposals and -// https://github.com/webassembly/threads +// No-op implementation of locks for single-threaded environments. // //===----------------------------------------------------------------------===// -#ifndef SWIFT_RUNTIME_MUTEX_WASI_H -#define SWIFT_RUNTIME_MUTEX_WASI_H +#ifndef SWIFT_RUNTIME_MUTEX_SINGLE_THREADED_H +#define SWIFT_RUNTIME_MUTEX_SINGLE_THREADED_H + +#include "swift/Runtime/Debug.h" namespace swift { @@ -39,7 +37,9 @@ struct ConditionPlatformHelper { static void destroy(ConditionHandle &condition) {} static void notifyOne(ConditionHandle &condition) {} static void notifyAll(ConditionHandle &condition) {} - static void wait(ConditionHandle &condition, MutexHandle &mutex); + static void wait(ConditionHandle &condition, MutexHandle &mutex) { + fatalError(0, "single-threaded runtime cannot wait for condition"); + } }; struct MutexPlatformHelper { diff --git a/include/swift/Runtime/Once.h b/include/swift/Runtime/Once.h index 95265cfcda794..f9931edf5b9bf 100644 --- a/include/swift/Runtime/Once.h +++ b/include/swift/Runtime/Once.h @@ -22,7 +22,11 @@ namespace swift { -#ifdef __APPLE__ +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + +typedef bool swift_once_t; + +#elif defined(__APPLE__) // On OS X and iOS, swift_once_t matches dispatch_once_t. typedef long swift_once_t; @@ -44,10 +48,6 @@ typedef std::once_flag swift_once_t; /// extent of type swift_once_t. SWIFT_RUNTIME_EXPORT void swift_once(swift_once_t *predicate, void (*fn)(void *), void *context); -#ifdef __wasm__ -// WebAssembly: hack -void swift_once_real(swift_once_t *predicate, void (*fn)(void *), void *context); -#endif } diff --git a/include/swift/Runtime/Portability.h b/include/swift/Runtime/Portability.h index 9e4fc418e162f..cd19b2c4193ba 100644 --- a/include/swift/Runtime/Portability.h +++ b/include/swift/Runtime/Portability.h @@ -16,8 +16,47 @@ #ifndef SWIFT_RUNTIME_PORTABILITY_H #define SWIFT_RUNTIME_PORTABILITY_H + +#include #include +#include +#include size_t _swift_strlcpy(char *dst, const char *src, size_t maxlen); +// Skip the attribute when included by the compiler. +#ifdef SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE +SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE +#endif +inline static int swift_asprintf(char **strp, const char *fmt, ...) { + va_list args; + va_start(args, fmt); +#if defined(_WIN32) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" + int len = _vscprintf(fmt, args); +#pragma GCC diagnostic pop + if (len < 0) { + va_end(args); + return -1; + } + char *buffer = static_cast(malloc(len + 1)); + if (!buffer) { + va_end(args); + return -1; + } + int result = vsprintf(buffer, fmt, args); + if (result < 0) { + va_end(args); + free(buffer); + return -1; + } + *strp = buffer; +#else + int result = vasprintf(strp, fmt, args); +#endif + va_end(args); + return result; +} + #endif diff --git a/include/swift/SIL/LoopInfo.h b/include/swift/SIL/LoopInfo.h index 4bcdc47d253c6..200797c1a76d4 100644 --- a/include/swift/SIL/LoopInfo.h +++ b/include/swift/SIL/LoopInfo.h @@ -50,6 +50,16 @@ class SILLoop : public llvm::LoopBase { /// this loop by unrolling or versioning. bool canDuplicate(SILInstruction *Inst) const; + void getExitingAndLatchBlocks( + SmallVectorImpl &ExitingAndLatchBlocks) const { + this->getExitingBlocks(ExitingAndLatchBlocks); + SILBasicBlock *header = getHeader(); + for (auto *predBB : header->getPredecessorBlocks()) { + if (contains(predBB) && !this->isLoopExiting(predBB)) + ExitingAndLatchBlocks.push_back(predBB); + } + } + private: friend class llvm::LoopInfoBase; diff --git a/include/swift/SIL/OptimizationRemark.h b/include/swift/SIL/OptimizationRemark.h index 47318c4cc6765..3e3c05cb6463f 100644 --- a/include/swift/SIL/OptimizationRemark.h +++ b/include/swift/SIL/OptimizationRemark.h @@ -57,7 +57,6 @@ struct ArgumentKeyKind { InnerTy innerValue; ArgumentKeyKind(InnerTy value) : innerValue(value) {} - ArgumentKeyKind(const ArgumentKeyKind &kind) : innerValue(kind.innerValue) {} operator InnerTy() const { return innerValue; } @@ -120,6 +119,12 @@ struct Argument { : Argument(ArgumentKey(ArgumentKeyKind::Default, key), msg, decl) {} Argument(ArgumentKey key, StringRef msg, const ValueDecl *decl) : key(key), val(msg), loc(decl->getLoc()) {} + + Argument(StringRef key, llvm::Twine &&msg, SILLocation loc) + : Argument(ArgumentKey(ArgumentKeyKind::Default, key), std::move(msg), + loc) {} + Argument(ArgumentKey key, llvm::Twine &&msg, SILLocation loc) + : key(key), val(msg.str()), loc(loc.getSourceLoc()) {} }; /// Shorthand to insert named-value pairs. @@ -132,14 +137,26 @@ struct IndentDebug { unsigned width; }; -enum class SourceLocInferenceBehavior { - None, - ForwardScanOnly, - BackwardScanOnly, - ForwardThenBackward, - BackwardThenForward, +enum class SourceLocInferenceBehavior : unsigned { + None = 0, + ForwardScan = 0x1, + BackwardScan = 0x2, + ForwardScan2nd = 0x4, + AlwaysInfer = 0x8, + + ForwardThenBackwards = ForwardScan | BackwardScan, + BackwardsThenForwards = BackwardScan | ForwardScan2nd, + ForwardScanAlwaysInfer = ForwardScan | AlwaysInfer, + BackwardScanAlwaysInfer = BackwardScan | AlwaysInfer, }; +inline SourceLocInferenceBehavior operator&(SourceLocInferenceBehavior lhs, + SourceLocInferenceBehavior rhs) { + auto lhsVal = std::underlying_type::type(lhs); + auto rhsVal = std::underlying_type::type(rhs); + return SourceLocInferenceBehavior(lhsVal & rhsVal); +} + /// Infer the proper SourceLoc to use for the given SILInstruction. /// /// This means that if we have a valid location for the instruction, we just diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index 4f2a36d7282aa..5884a0ad2d700 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -196,6 +196,18 @@ struct BorrowingOperand { void visitConsumingUsesOfBorrowIntroducingUserResults( function_ref visitor) const; + /// Compute the implicit uses that this borrowing operand "injects" into the + /// set of its operands uses. + /// + /// E.x.: end_apply uses. + /// + /// \p errorFunction a callback that if non-null is passed an operand that + /// triggers a mal-formed SIL error. This is just needed for the ownership + /// verifier to emit good output. + bool getImplicitUses( + SmallVectorImpl &foundUses, + std::function *errorFunction = nullptr) const; + void print(llvm::raw_ostream &os) const; SWIFT_DEBUG_DUMP { print(llvm::dbgs()); } @@ -467,6 +479,16 @@ struct InteriorPointerOperand { llvm_unreachable("Covered switch isn't covered?!"); } + /// Compute the list of implicit uses that this interior pointer operand puts + /// on its parent guaranted value. + /// + /// Example: Uses of a ref_element_addr can not occur outside of the lifetime + /// of the instruction's operand. The uses of that address act as liveness + /// requirements to ensure that the underlying class is alive at all use + /// points. + bool getImplicitUses(SmallVectorImpl &foundUses, + std::function *onError = nullptr); + private: /// Internal constructor for failable static constructor. Please do not expand /// its usage since it assumes the code passed in is well formed. diff --git a/include/swift/SIL/PrettyStackTrace.h b/include/swift/SIL/PrettyStackTrace.h index 7b62b3d6ec8ac..1b35d3ebf3c7f 100644 --- a/include/swift/SIL/PrettyStackTrace.h +++ b/include/swift/SIL/PrettyStackTrace.h @@ -39,7 +39,7 @@ class PrettyStackTraceSILLocation : public llvm::PrettyStackTraceEntry { PrettyStackTraceSILLocation(const char *action, SILLocation loc, ASTContext &C) : Loc(loc), Action(action), Context(C) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; @@ -62,7 +62,7 @@ class PrettyStackTraceSILFunction : public llvm::PrettyStackTraceEntry { PrettyStackTraceSILFunction(llvm::Twine &&twine, const SILFunction *func) : func(func), data(), action(twine.toNullTerminatedStringRef(data)) {} - virtual void print(llvm::raw_ostream &os) const; + virtual void print(llvm::raw_ostream &os) const override; protected: void printFunctionInfo(llvm::raw_ostream &out) const; @@ -77,7 +77,7 @@ class PrettyStackTraceSILNode : public llvm::PrettyStackTraceEntry { PrettyStackTraceSILNode(const char *action, const SILNode *node) : Node(node), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; } // end namespace swift diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index e7c544992dddc..c27d345ee8ae2 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -2905,10 +2905,10 @@ template void SILCloner:: visitLinearFunctionExtractInst(LinearFunctionExtractInst *Inst) { getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - recordClonedInstruction( - Inst, getBuilder().createLinearFunctionExtract( - getOpLocation(Inst->getLoc()), Inst->getExtractee(), - getOpValue(Inst->getFunctionOperand()))); + recordClonedInstruction(Inst, getBuilder().createLinearFunctionExtract( + getOpLocation(Inst->getLoc()), + Inst->getExtractee(), + getOpValue(Inst->getOperand()))); } template diff --git a/include/swift/SIL/SILConstants.h b/include/swift/SIL/SILConstants.h index 4e04f3e8044e7..eb53bad64701f 100644 --- a/include/swift/SIL/SILConstants.h +++ b/include/swift/SIL/SILConstants.h @@ -73,7 +73,7 @@ class SymbolicValueBumpAllocator : public SymbolicValueAllocator { SymbolicValueBumpAllocator() {} ~SymbolicValueBumpAllocator() {} - void *allocate(unsigned long byteSize, unsigned alignment) { + void *allocate(unsigned long byteSize, unsigned alignment) override { return bumpAllocator.Allocate(byteSize, alignment); } }; diff --git a/include/swift/SIL/SILDebugScope.h b/include/swift/SIL/SILDebugScope.h index ce9ad200ac77e..0349ed6dbffc8 100644 --- a/include/swift/SIL/SILDebugScope.h +++ b/include/swift/SIL/SILDebugScope.h @@ -66,6 +66,28 @@ class SILDebugScope : public SILAllocated { /// into. SILFunction *getParentFunction() const; + /// If this is a debug scope associated with an inlined call site, return the + /// SILLocation associated with the call site resulting from the final + /// inlining. + /// + /// This allows one to emit diagnostics based off of inlined code's final + /// location in the function that was inlined into. + SILLocation getOutermostInlineLocation() const { + if (!InlinedCallSite) + return SILLocation::invalid(); + + auto *scope = this; + do { + scope = scope->InlinedCallSite; + } while (scope->InlinedCallSite); + + SILLocation callSite = scope->Loc; + if (callSite.isNull() || !callSite.isASTNode()) + return SILLocation::invalid(); + + return callSite; + } + void print(SourceManager &SM, llvm::raw_ostream &OS = llvm::errs(), unsigned Indent = 0) const; diff --git a/include/swift/SIL/SILDebuggerClient.h b/include/swift/SIL/SILDebuggerClient.h index e6c2bf7a2bd27..1f8af82d78fb1 100644 --- a/include/swift/SIL/SILDebuggerClient.h +++ b/include/swift/SIL/SILDebuggerClient.h @@ -38,11 +38,11 @@ class SILDebuggerClient : public DebuggerClient { virtual SILValue emitLValueForVariable(VarDecl *var, SILBuilder &builder) = 0; - inline SILDebuggerClient *getAsSILDebuggerClient() { + inline SILDebuggerClient *getAsSILDebuggerClient() override { return this; } private: - virtual void anchor(); + virtual void anchor() override; }; } // namespace swift diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index 8125736fc391f..ec81558ab3179 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -121,6 +121,7 @@ class SILFunction enum class Purpose : uint8_t { None, GlobalInit, + GlobalInitOnceFunction, LazyPropertyGetter }; @@ -274,9 +275,6 @@ class SILFunction /// that it may have unboxed capture (i.e. @inout_aliasable parameters). unsigned IsWithoutActuallyEscapingThunk : 1; - /// True if this function is an async function. - unsigned IsAsync : 1; - /// If != OptimizationMode::NotSet, the optimization mode specified with an /// function attribute. unsigned OptMode : NumOptimizationModeBits; @@ -504,9 +502,7 @@ class SILFunction IsWithoutActuallyEscapingThunk = val; } - bool isAsync() const { return IsAsync; } - - void setAsync(bool val = true) { IsAsync = val; } + bool isAsync() const { return LoweredType->isAsync(); } /// Returns the calling convention used by this entry point. SILFunctionTypeRepresentation getRepresentation() const { @@ -837,6 +833,10 @@ class SILFunction /// function itself does not need this attribute. It is private and only /// called within the addressor. bool isGlobalInit() const { return specialPurpose == Purpose::GlobalInit; } + + bool isGlobalInitOnceFunction() const { + return specialPurpose == Purpose::GlobalInitOnceFunction; + } bool isLazyPropertyGetter() const { return specialPurpose == Purpose::LazyPropertyGetter; diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index d504f37085831..36ebd2ef858da 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -8364,14 +8364,11 @@ class DifferentiableFunctionExtractInst /// representing a bundle of the original function and the transpose function, /// extract the specified function. class LinearFunctionExtractInst - : public InstructionBase< - SILInstructionKind::LinearFunctionExtractInst, - SingleValueInstruction> { + : public UnaryInstructionBase { private: /// The extractee. LinearDifferentiableFunctionTypeComponent extractee; - /// The list containing the `@differentiable(linear)` function operand. - FixedOperandList<1> operands; static SILType getExtracteeType(SILValue function, @@ -8387,10 +8384,6 @@ class LinearFunctionExtractInst LinearDifferentiableFunctionTypeComponent getExtractee() const { return extractee; } - - SILValue getFunctionOperand() const { return operands[0].get(); } - ArrayRef getAllOperands() const { return operands.asArray(); } - MutableArrayRef getAllOperands() { return operands.asArray(); } }; /// DifferentiabilityWitnessFunctionInst - Looks up a differentiability witness diff --git a/include/swift/SIL/SILInstructionWorklist.h b/include/swift/SIL/SILInstructionWorklist.h index 9f4b399b60f4a..6df8e06cc0d5b 100644 --- a/include/swift/SIL/SILInstructionWorklist.h +++ b/include/swift/SIL/SILInstructionWorklist.h @@ -30,6 +30,9 @@ /// //===----------------------------------------------------------------------===// +#ifndef SWIFT_SIL_SILINSTRUCTIONWORKLIST_H +#define SWIFT_SIL_SILINSTRUCTIONWORKLIST_H + #include "swift/Basic/BlotSetVector.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" @@ -342,3 +345,5 @@ class SmallSILInstructionWorklist final }; } // end namespace swift + +#endif // SWIFT_SIL_SILINSTRUCTIONWORKLIST_H diff --git a/include/swift/SIL/SILLocation.h b/include/swift/SIL/SILLocation.h index d847221805743..9e0d07a74695a 100644 --- a/include/swift/SIL/SILLocation.h +++ b/include/swift/SIL/SILLocation.h @@ -65,7 +65,7 @@ class SILLocation { using type = Pattern; }; - using ASTNodeTy = llvm::PointerUnion4; + using ASTNodeTy = llvm::PointerUnion; public: enum LocationKind : unsigned { diff --git a/include/swift/SIL/SILNode.h b/include/swift/SIL/SILNode.h index 6f1f50a2dc453..829ac3536c2b7 100644 --- a/include/swift/SIL/SILNode.h +++ b/include/swift/SIL/SILNode.h @@ -19,6 +19,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/PointerLikeTypeTraits.h" #include "swift/Basic/InlineBitfield.h" #include "swift/Basic/LLVM.h" #include diff --git a/include/swift/SIL/SILOpenedArchetypesTracker.h b/include/swift/SIL/SILOpenedArchetypesTracker.h index 508eb366cdcf9..6c89487ceb4b9 100644 --- a/include/swift/SIL/SILOpenedArchetypesTracker.h +++ b/include/swift/SIL/SILOpenedArchetypesTracker.h @@ -99,10 +99,10 @@ class SILOpenedArchetypesTracker : public DeleteNotificationHandler { bool hasUnresolvedOpenedArchetypeDefinitions(); // Handling of instruction removal notifications. - bool needsNotifications() { return true; } + bool needsNotifications() override { return true; } // Handle notifications about removals of instructions. - void handleDeleteNotification(SILNode *node); + void handleDeleteNotification(SILNode *node) override; // Dump the contents. void dump() const; diff --git a/include/swift/SIL/SILVTableVisitor.h b/include/swift/SIL/SILVTableVisitor.h index de8419b238601..2aeb6755cdecf 100644 --- a/include/swift/SIL/SILVTableVisitor.h +++ b/include/swift/SIL/SILVTableVisitor.h @@ -148,7 +148,7 @@ template class SILVTableVisitor { if (!theClass->hasKnownSwiftImplementation()) return; - for (auto member : theClass->getEmittedMembers()) + for (auto member : theClass->getSemanticMembers()) maybeAddMember(member); } }; diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index aba919ee0090c..344087f0a1aaf 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -992,7 +992,6 @@ class TypeConverter { /// Given a function type, yield its bridged formal type. CanAnyFunctionType getBridgedFunctionType(AbstractionPattern fnPattern, CanAnyFunctionType fnType, - AnyFunctionType::ExtInfo extInfo, Bridgeability bridging); /// Given a referenced value and the substituted formal type of a diff --git a/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h b/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h index 2b3b5d121756b..6afbc0ad36eaf 100644 --- a/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h @@ -24,7 +24,7 @@ class SILInstruction; class DominanceAnalysis : public FunctionAnalysisBase { protected: virtual void verify(DominanceInfo *DI) const override { - if (DI->getRoots().empty()) + if (DI->roots().empty()) return; DI->verify(); } @@ -52,7 +52,7 @@ class DominanceAnalysis : public FunctionAnalysisBase { class PostDominanceAnalysis : public FunctionAnalysisBase { protected: virtual void verify(PostDominanceInfo *PDI) const override { - if (PDI->getRoots().empty()) + if (PDI->roots().empty()) return; PDI->verify(); } diff --git a/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h b/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h index 285e694723617..4975c4bf09787 100644 --- a/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h @@ -726,8 +726,9 @@ class LoopRegion { return getSubregionData().RPONumOfHeaderBlock; } - void dump() const; - void print(llvm::raw_ostream &os, bool insertSpaces = false) const; + void dump(bool isVerbose = false) const; + void print(llvm::raw_ostream &os, bool isShort = false, + bool isVerbose = false) const; void dumpName() const; void printName(llvm::raw_ostream &os) const; diff --git a/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h b/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h index f4ddc2ee77673..3064fc889abb2 100644 --- a/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h @@ -55,7 +55,7 @@ class RCIdentityFunctionInfo { /// *NOTE* This ignores obvious ARC escapes where the a potential /// user of the RC is not managed by ARC. For instance /// unchecked_trivial_bit_cast. - void getRCUses(SILValue V, llvm::SmallVectorImpl &Uses); + void getRCUses(SILValue V, SmallVectorImpl &Uses); /// A helper method that calls getRCUses and then maps each operand to the /// operands user and then uniques the list. @@ -63,7 +63,11 @@ class RCIdentityFunctionInfo { /// *NOTE* The routine asserts that the passed in Users array is empty for /// simplicity. If needed this can be changed, but it is not necessary given /// current uses. - void getRCUsers(SILValue V, llvm::SmallVectorImpl &Users); + void getRCUsers(SILValue V, SmallVectorImpl &Users); + + /// Like getRCUses except uses a callback to prevent the need for an + /// intermediate array. + void visitRCUses(SILValue V, function_ref Visitor); void handleDeleteNotification(SILNode *node) { auto value = dyn_cast(node); diff --git a/include/swift/SILOptimizer/Differentiation/ADContext.h b/include/swift/SILOptimizer/Differentiation/ADContext.h index 368d7fc8d4aec..4e8fd61a9f143 100644 --- a/include/swift/SILOptimizer/Differentiation/ADContext.h +++ b/include/swift/SILOptimizer/Differentiation/ADContext.h @@ -273,7 +273,8 @@ ADContext::emitNondifferentiabilityError(SILValue value, Diag diag, U &&... args) { LLVM_DEBUG({ getADDebugStream() << "Diagnosing non-differentiability.\n"; - getADDebugStream() << "For value:\n" << value; + auto &s = getADDebugStream() << "For value:\n"; + value->printInContext(s); getADDebugStream() << "With invoker:\n" << invoker << '\n'; }); // If instruction does not have a valid location, use the function location @@ -290,7 +291,8 @@ ADContext::emitNondifferentiabilityError(SILInstruction *inst, Diag diag, U &&... args) { LLVM_DEBUG({ getADDebugStream() << "Diagnosing non-differentiability.\n"; - getADDebugStream() << "For instruction:\n" << *inst; + auto &s = getADDebugStream() << "For instruction:\n"; + inst->printInContext(s); getADDebugStream() << "With invoker:\n" << invoker << '\n'; }); // If instruction does not have a valid location, use the function location diff --git a/include/swift/SILOptimizer/Differentiation/Common.h b/include/swift/SILOptimizer/Differentiation/Common.h index 2f996740b08b6..90e3c26690928 100644 --- a/include/swift/SILOptimizer/Differentiation/Common.h +++ b/include/swift/SILOptimizer/Differentiation/Common.h @@ -271,59 +271,6 @@ inline void createEntryArguments(SILFunction *f) { } } -/// Helper class for visiting basic blocks in post-order post-dominance order, -/// based on a worklist algorithm. -class PostOrderPostDominanceOrder { - SmallVector buffer; - PostOrderFunctionInfo *postOrderInfo; - size_t srcIdx = 0; - -public: - /// Constructor. - /// \p root The root of the post-dominator tree. - /// \p postOrderInfo The post-order info of the function. - /// \p capacity Should be the number of basic blocks in the dominator tree to - /// reduce memory allocation. - PostOrderPostDominanceOrder(DominanceInfoNode *root, - PostOrderFunctionInfo *postOrderInfo, - int capacity = 0) - : postOrderInfo(postOrderInfo) { - buffer.reserve(capacity); - buffer.push_back(root); - } - - /// Get the next block from the worklist. - DominanceInfoNode *getNext() { - if (srcIdx == buffer.size()) - return nullptr; - return buffer[srcIdx++]; - } - - /// Pushes the dominator children of a block onto the worklist in post-order. - void pushChildren(DominanceInfoNode *node) { - pushChildrenIf(node, [](SILBasicBlock *) { return true; }); - } - - /// Conditionally pushes the dominator children of a block onto the worklist - /// in post-order. - template - void pushChildrenIf(DominanceInfoNode *node, Pred pred) { - SmallVector children; - for (auto *child : *node) - children.push_back(child); - llvm::sort(children.begin(), children.end(), - [&](DominanceInfoNode *n1, DominanceInfoNode *n2) { - return postOrderInfo->getPONumber(n1->getBlock()) < - postOrderInfo->getPONumber(n2->getBlock()); - }); - for (auto *child : children) { - SILBasicBlock *childBB = child->getBlock(); - if (pred(childBB)) - buffer.push_back(child); - } - } -}; - /// Cloner that remaps types using the target function's generic environment. class BasicTypeSubstCloner final : public TypeSubstCloner { diff --git a/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h b/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h index f00bba619e533..1ebae9671d7da 100644 --- a/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h +++ b/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h @@ -30,7 +30,7 @@ class PrettyStackTraceSILFunctionTransform PrettyStackTraceSILFunctionTransform(SILFunctionTransform *SFT, unsigned PassNumber); - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; class PrettyStackTraceSILModuleTransform : public llvm::PrettyStackTraceEntry { @@ -41,7 +41,7 @@ class PrettyStackTraceSILModuleTransform : public llvm::PrettyStackTraceEntry { PrettyStackTraceSILModuleTransform(SILModuleTransform *SMT, unsigned PassNumber) : SMT(SMT), PassNumber(PassNumber) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; } // end namespace swift diff --git a/include/swift/SILOptimizer/Utils/Existential.h b/include/swift/SILOptimizer/Utils/Existential.h index 75c88cf388f0a..5436654f71a2c 100644 --- a/include/swift/SILOptimizer/Utils/Existential.h +++ b/include/swift/SILOptimizer/Utils/Existential.h @@ -49,6 +49,8 @@ struct OpenedArchetypeInfo { assert(!OpenedArchetype || (OpenedArchetypeValue && ExistentialValue)); return OpenedArchetype; } + + void dump() const; }; /// Record conformance and concrete type info derived from an init_existential @@ -102,6 +104,8 @@ struct ConcreteExistentialInfo { CanType selfTy = P->getSelfInterfaceType()->getCanonicalType(); return ExistentialSubs.lookupConformance(selfTy, P); } + + void dump() const; private: void initializeSubstitutionMap( @@ -131,6 +135,8 @@ struct ConcreteOpenedExistentialInfo { assert(CEI->isValid()); return true; } + + void dump() const; }; } // end namespace swift diff --git a/include/swift/SILOptimizer/Utils/InstOptUtils.h b/include/swift/SILOptimizer/Utils/InstOptUtils.h index 522abb0f5a68c..86c1ab802541f 100644 --- a/include/swift/SILOptimizer/Utils/InstOptUtils.h +++ b/include/swift/SILOptimizer/Utils/InstOptUtils.h @@ -308,21 +308,22 @@ bool tryCheckedCastBrJumpThreading( /// A structure containing callbacks that are called when an instruction is /// removed or added. struct InstModCallbacks { - std::function deleteInst = [](SILInstruction *inst) { - inst->eraseFromParent(); - }; - std::function createdNewInst = [](SILInstruction *) { - }; - std::function replaceValueUsesWith = - [](SILValue oldValue, SILValue newValue) { - oldValue->replaceAllUsesWith(newValue); - }; + static const std::function defaultDeleteInst; + static const std::function defaultCreatedNewInst; + static const std::function defaultReplaceValueUsesWith; + static const std::function + defaultEraseAndRAUWSingleValueInst; + + std::function deleteInst = + InstModCallbacks::defaultDeleteInst; + std::function createdNewInst = + InstModCallbacks::defaultCreatedNewInst; + std::function + replaceValueUsesWith = + InstModCallbacks::defaultReplaceValueUsesWith; std::function eraseAndRAUWSingleValueInst = - [](SingleValueInstruction *i, SILValue newValue) { - i->replaceAllUsesWith(newValue); - i->eraseFromParent(); - }; + InstModCallbacks::defaultEraseAndRAUWSingleValueInst; InstModCallbacks(decltype(deleteInst) deleteInst, decltype(createdNewInst) createdNewInst, @@ -330,10 +331,7 @@ struct InstModCallbacks { : deleteInst(deleteInst), createdNewInst(createdNewInst), replaceValueUsesWith(replaceValueUsesWith), eraseAndRAUWSingleValueInst( - [](SingleValueInstruction *i, SILValue newValue) { - i->replaceAllUsesWith(newValue); - i->eraseFromParent(); - }) {} + InstModCallbacks::defaultEraseAndRAUWSingleValueInst) {} InstModCallbacks( decltype(deleteInst) deleteInst, decltype(createdNewInst) createdNewInst, diff --git a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h index 39b3c6ffa9ad1..cee8fd7ed8bc1 100644 --- a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h +++ b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h @@ -236,7 +236,7 @@ class LSValue : public LSBase { } /// Returns whether the LSValue has been initialized properly. - bool isValid() const { + bool isValid() const override { if (CoveringValue) return true; return LSBase::isValid(); @@ -261,7 +261,7 @@ class LSValue : public LSBase { return Path.getValue().createExtract(Base, Inst, true); } - void print(llvm::raw_ostream &os) { + void print(llvm::raw_ostream &os) override { if (CoveringValue) { os << "Covering Value"; return; diff --git a/include/swift/SILOptimizer/Utils/ValueLifetime.h b/include/swift/SILOptimizer/Utils/ValueLifetime.h index d4e5bb5b1ba53..92af2083ef62f 100644 --- a/include/swift/SILOptimizer/Utils/ValueLifetime.h +++ b/include/swift/SILOptimizer/Utils/ValueLifetime.h @@ -28,6 +28,24 @@ namespace swift { /// of the analysis and can be a super set of the uses of the SILValue /// e.g. it can be the set of transitive uses of the SILValue. class ValueLifetimeAnalysis { + /// The instruction or argument that define the value. + PointerUnion defValue; + + /// The set of blocks where the value is live. + llvm::SmallSetVector liveBlocks; + + /// The set of instructions where the value is used, or the users-list + /// provided with the constructor. + llvm::SmallPtrSet userSet; + + /// Indicates whether the basic block containing def has users of def that + /// precede def. This field is initialized by propagateLiveness. + bool hasUsersBeforeDef; + + /// Critical edges that couldn't be split to compute the frontier. This could + /// be non-empty when the analysis is invoked with DontModifyCFG mode. + llvm::SmallVector, 16> criticalEdges; + public: /// The lifetime frontier for the value. It is the list of instructions @@ -35,13 +53,13 @@ class ValueLifetimeAnalysis { /// end the value's lifetime. using Frontier = SmallVector; - /// Constructor for the value \p Def with a specific range of users. + /// Constructor for the value \p def with a specific range of users. /// /// We templatize over the RangeTy so that we can initialize /// ValueLifetimeAnalysis with misc iterators including transform /// iterators. template - ValueLifetimeAnalysis(SILInstruction *def, const RangeTy &userRange) + ValueLifetimeAnalysis(decltype(defValue) def, const RangeTy &userRange) : defValue(def), userSet(userRange.begin(), userRange.end()) { propagateLiveness(); } @@ -102,7 +120,7 @@ class ValueLifetimeAnalysis { /// Returns true if the value is alive at the begin of block \p bb. bool isAliveAtBeginOfBlock(SILBasicBlock *bb) { return liveBlocks.count(bb) && - (bb != defValue->getParent() || hasUsersBeforeDef); + (hasUsersBeforeDef || bb != getDefValueParentBlock()); } /// Checks if there is a dealloc_ref inside the value's live range. @@ -112,24 +130,19 @@ class ValueLifetimeAnalysis { void dump() const; private: + SILFunction *getFunction() const { + if (auto *inst = defValue.dyn_cast()) { + return inst->getFunction(); + } + return defValue.get()->getFunction(); + } - /// The value. - SILInstruction *defValue; - - /// The set of blocks where the value is live. - llvm::SmallSetVector liveBlocks; - - /// The set of instructions where the value is used, or the users-list - /// provided with the constructor. - llvm::SmallPtrSet userSet; - - /// Indicates whether the basic block containing def has users of def that - /// precede def. This field is initialized by propagateLiveness. - bool hasUsersBeforeDef; - - /// Critical edges that couldn't be split to compute the frontier. This could - /// be non-empty when the analysis is invoked with DontModifyCFG mode. - llvm::SmallVector, 16> criticalEdges; + SILBasicBlock *getDefValueParentBlock() const { + if (auto *inst = defValue.dyn_cast()) { + return inst->getParent(); + } + return defValue.get()->getParent(); + } /// Propagates the liveness information up the control flow graph. void propagateLiveness(); diff --git a/include/swift/Serialization/ModuleDependencyScanner.h b/include/swift/Serialization/ModuleDependencyScanner.h new file mode 100644 index 0000000000000..dd12f8ee98008 --- /dev/null +++ b/include/swift/Serialization/ModuleDependencyScanner.h @@ -0,0 +1,131 @@ +//===--- ModuleDependencyScanner.h - Import Swift modules --------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/ASTContext.h" +#include "swift/Frontend/ModuleInterfaceLoader.h" +#include "swift/Serialization/SerializedModuleLoader.h" + +namespace swift { + /// A module "loader" that looks for .swiftinterface and .swiftmodule files + /// for the purpose of determining dependencies, but does not attempt to + /// load the module files. + class ModuleDependencyScanner : public SerializedModuleLoaderBase { + public: + enum ScannerKind { + MDS_plain, + MDS_placeholder + }; + + private: + /// The kind of scanner this is (LLVM-style RTTI) + const ScannerKind kind; + + /// The module we're scanning dependencies of. + Identifier moduleName; + + /// Scan the given interface file to determine dependencies. + llvm::ErrorOr scanInterfaceFile( + Twine moduleInterfacePath, bool isFramework); + + InterfaceSubContextDelegate &astDelegate; + public: + Optional dependencies; + + /// Describes the kind of dependencies this scanner is able to identify + ModuleDependenciesKind dependencyKind; + + ModuleDependencyScanner( + ASTContext &ctx, ModuleLoadingMode LoadMode, Identifier moduleName, + InterfaceSubContextDelegate &astDelegate, + ModuleDependenciesKind dependencyKind = ModuleDependenciesKind::Swift, + ScannerKind kind = MDS_plain) + : SerializedModuleLoaderBase(ctx, nullptr, LoadMode, + /*IgnoreSwiftSourceInfoFile=*/true), + kind(kind), moduleName(moduleName), astDelegate(astDelegate), + dependencyKind(dependencyKind) {} + + std::error_code findModuleFilesInDirectory( + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; + + virtual void collectVisibleTopLevelModuleNames( + SmallVectorImpl &names) const override { + llvm_unreachable("Not used"); + } + + ScannerKind getKind() const { return kind; } + static bool classof(const ModuleDependencyScanner *MDS) { + return MDS->getKind() == MDS_plain; + } + }; + + /// A ModuleLoader that loads placeholder dependency module stubs specified in + /// -placeholder-dependency-module-map-file + /// This loader is used only in dependency scanning to inform the scanner that a + /// set of modules constitute placeholder dependencies that are not visible to the + /// scanner but will nevertheless be provided by the scanner's clients. + /// This "loader" will not attempt to load any module files. + class PlaceholderSwiftModuleScanner : public ModuleDependencyScanner { + /// Scan the given placeholder module map + void parsePlaceholderModuleMap(StringRef fileName) { + ExplicitModuleMapParser parser(Allocator); + auto result = + parser.parseSwiftExplicitModuleMap(fileName, PlaceholderDependencyModuleMap); + if (result == std::errc::invalid_argument) { + Ctx.Diags.diagnose(SourceLoc(), + diag::placeholder_dependency_module_map_corrupted, + fileName); + } + else if (result == std::errc::no_such_file_or_directory) { + Ctx.Diags.diagnose(SourceLoc(), + diag::placeholder_dependency_module_map_missing, + fileName); + } + } + + llvm::StringMap PlaceholderDependencyModuleMap; + llvm::BumpPtrAllocator Allocator; + + public: + PlaceholderSwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode, + Identifier moduleName, + StringRef PlaceholderDependencyModuleMap, + InterfaceSubContextDelegate &astDelegate) + : ModuleDependencyScanner(ctx, LoadMode, moduleName, astDelegate, + ModuleDependenciesKind::SwiftPlaceholder, + MDS_placeholder) { + + // FIXME: Find a better place for this map to live, to avoid + // doing the parsing on every module. + if (!PlaceholderDependencyModuleMap.empty()) { + parsePlaceholderModuleMap(PlaceholderDependencyModuleMap); + } + } + + std::error_code findModuleFilesInDirectory( + AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; + + static bool classof(const ModuleDependencyScanner *MDS) { + return MDS->getKind() == MDS_placeholder; + } + }; +} diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index ec2ad4a8a29ab..1cda5272cbb7a 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -73,12 +73,12 @@ class SerializedModuleLoaderBase : public ModuleLoader { StringRef extension) const; using AccessPathElem = Located; - bool findModule(AccessPathElem moduleID, - SmallVectorImpl *moduleInterfacePath, - std::unique_ptr *moduleBuffer, - std::unique_ptr *moduleDocBuffer, - std::unique_ptr *moduleSourceInfoBuffer, - bool &isFramework, bool &isSystemModule); + virtual bool findModule(AccessPathElem moduleID, + SmallVectorImpl *moduleInterfacePath, + std::unique_ptr *moduleBuffer, + std::unique_ptr *moduleDocBuffer, + std::unique_ptr *moduleSourceInfoBuffer, + bool &isFramework, bool &isSystemModule); /// Attempts to search the provided directory for a loadable serialized /// .swiftmodule with the provided `ModuleFilename`. Subclasses must @@ -98,7 +98,8 @@ class SerializedModuleLoaderBase : public ModuleLoader { SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) = 0; + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) = 0; std::error_code openModuleFile( @@ -229,7 +230,8 @@ class ImplicitSerializedModuleLoader : public SerializedModuleLoaderBase { SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override; + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; bool maybeDiagnoseTargetMismatch( SourceLoc sourceLocation, @@ -274,7 +276,8 @@ class MemoryBufferSerializedModuleLoader : public SerializedModuleLoaderBase { SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override; + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; bool maybeDiagnoseTargetMismatch( SourceLoc sourceLocation, diff --git a/include/swift/Serialization/Validation.h b/include/swift/Serialization/Validation.h index f0e84e7d7676e..ab2aed06d0079 100644 --- a/include/swift/Serialization/Validation.h +++ b/include/swift/Serialization/Validation.h @@ -177,9 +177,8 @@ ValidationInfo validateSerializedAST( /// - \p ModuleName is the name used to refer to the module in diagnostics. void diagnoseSerializedASTLoadFailure( ASTContext &Ctx, SourceLoc diagLoc, const ValidationInfo &loadInfo, - const ExtendedValidationInfo &extendedInfo, StringRef moduleBufferID, - StringRef moduleDocBufferID, ModuleFile *loadedModuleFile, - Identifier ModuleName); + StringRef moduleBufferID, StringRef moduleDocBufferID, + ModuleFile *loadedModuleFile, Identifier ModuleName); } // end namespace serialization } // end namespace swift diff --git a/include/swift/Strings.h b/include/swift/Strings.h index 32a7bb2d0072c..69b29ff4a52b9 100644 --- a/include/swift/Strings.h +++ b/include/swift/Strings.h @@ -38,6 +38,10 @@ constexpr static const StringLiteral MANGLING_MODULE_OBJC = "__C"; constexpr static const StringLiteral MANGLING_MODULE_CLANG_IMPORTER = "__C_Synthesized"; +/// The name prefix for C++ template instantiation imported as a Swift struct. +constexpr static const StringLiteral CXX_TEMPLATE_INST_PREFIX = + "__CxxTemplateInst"; + constexpr static const StringLiteral SEMANTICS_PROGRAMTERMINATION_POINT = "programtermination_point"; diff --git a/include/swift/Subsystems.h b/include/swift/Subsystems.h index 0a99b5f92175a..a4e545e52cb84 100644 --- a/include/swift/Subsystems.h +++ b/include/swift/Subsystems.h @@ -29,6 +29,7 @@ #include namespace llvm { + class raw_pwrite_stream; class GlobalVariable; class MemoryBuffer; class Module; diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h index 72229a63707cc..b3d798f2c7d38 100644 --- a/include/swift/TBDGen/TBDGen.h +++ b/include/swift/TBDGen/TBDGen.h @@ -14,7 +14,6 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringSet.h" -#include "swift/AST/TBDGenRequests.h" #include "swift/Basic/Version.h" #include @@ -25,6 +24,7 @@ class raw_ostream; namespace swift { class FileUnit; class ModuleDecl; +class TBDGenDescriptor; /// Options for controlling the exact set of symbols included in the TBD /// output. @@ -38,6 +38,9 @@ struct TBDGenOptions { /// Only collect linker directive symbols. bool LinkerDirectivesOnly = false; + /// Whether to include only symbols with public linkage. + bool PublicSymbolsOnly = true; + /// The install_name to use in the TBD file. std::string InstallName; @@ -66,6 +69,7 @@ struct TBDGenOptions { return lhs.HasMultipleIGMs == rhs.HasMultipleIGMs && lhs.IsInstallAPI == rhs.IsInstallAPI && lhs.LinkerDirectivesOnly == rhs.LinkerDirectivesOnly && + lhs.PublicSymbolsOnly == rhs.PublicSymbolsOnly && lhs.InstallName == rhs.InstallName && lhs.ModuleLinkName == rhs.ModuleLinkName && lhs.CurrentVersion == rhs.CurrentVersion && @@ -82,8 +86,9 @@ struct TBDGenOptions { using namespace llvm; return hash_combine( opts.HasMultipleIGMs, opts.IsInstallAPI, opts.LinkerDirectivesOnly, - opts.InstallName, opts.ModuleLinkName, opts.CurrentVersion, - opts.CompatibilityVersion, opts.ModuleInstallNameMapPath, + opts.PublicSymbolsOnly, opts.InstallName, opts.ModuleLinkName, + opts.CurrentVersion, opts.CompatibilityVersion, + opts.ModuleInstallNameMapPath, hash_combine_range(opts.embedSymbolsFromModules.begin(), opts.embedSymbolsFromModules.end())); } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index f95561eb4befd..21703f4929ce9 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -18,6 +18,7 @@ #include "ClangTypeConverter.h" #include "ForeignRepresentationInfo.h" #include "SubstitutionMapStorage.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/ConcreteDeclRef.h" #include "swift/AST/DiagnosticEngine.h" @@ -281,6 +282,10 @@ struct ASTContext::Implementation { llvm::DenseMap ForeignErrorConventions; + /// Map from declarations to foreign async conventions. + llvm::DenseMap ForeignAsyncConventions; + /// Cache of previously looked-up precedence queries. AssociativityCacheType AssociativityCache; @@ -339,6 +344,10 @@ struct ASTContext::Implementation { /// LiteralExprs in fully-checked AST. llvm::DenseMap BuiltinInitWitness; + /// Mapping from the function decl to its original body's source range. This + /// is populated if the body is reparsed from other source buffers. + llvm::DenseMap OriginalBodySourceRanges; + /// Structure that captures data that is segregated into different /// arenas. struct Arena { @@ -539,6 +548,7 @@ void ASTContext::operator delete(void *Data) throw() { ASTContext *ASTContext::get(LangOptions &langOpts, TypeCheckerOptions &typeckOpts, SearchPathOptions &SearchPathOpts, + ClangImporterOptions &ClangImporterOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags) { // If more than two data structures are concatentated, then the aggregate @@ -552,15 +562,19 @@ ASTContext *ASTContext::get(LangOptions &langOpts, llvm::alignAddr(impl, llvm::Align(alignof(Implementation)))); new (impl) Implementation(); return new (mem) - ASTContext(langOpts, typeckOpts, SearchPathOpts, SourceMgr, Diags); + ASTContext(langOpts, typeckOpts, SearchPathOpts, ClangImporterOpts, + SourceMgr, Diags); } ASTContext::ASTContext(LangOptions &langOpts, TypeCheckerOptions &typeckOpts, SearchPathOptions &SearchPathOpts, + ClangImporterOptions &ClangImporterOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags) : LangOpts(langOpts), TypeCheckerOpts(typeckOpts), - SearchPathOpts(SearchPathOpts), SourceMgr(SourceMgr), Diags(Diags), + SearchPathOpts(SearchPathOpts), + ClangImporterOpts(ClangImporterOpts), + SourceMgr(SourceMgr), Diags(Diags), evaluator(Diags, langOpts), TheBuiltinModule(createBuiltinModule(*this)), StdlibModuleName(getIdentifier(STDLIB_NAME)), @@ -1462,8 +1476,9 @@ bool ASTContext::hadError() const { /// Retrieve the arena from which we should allocate storage for a type. static AllocationArena getArena(RecursiveTypeProperties properties) { bool hasTypeVariable = properties.hasTypeVariable(); - return hasTypeVariable? AllocationArena::ConstraintSolver - : AllocationArena::Permanent; + bool hasHole = properties.hasTypeHole(); + return hasTypeVariable || hasHole ? AllocationArena::ConstraintSolver + : AllocationArena::Permanent; } void ASTContext::addSearchPath(StringRef searchPath, bool isFramework, @@ -1512,6 +1527,21 @@ Optional ASTContext::getModuleDependencies( return None; } +Optional +ASTContext::getSwiftModuleDependencies(StringRef moduleName, + ModuleDependenciesCache &cache, + InterfaceSubContextDelegate &delegate) { + for (auto &loader : getImpl().ModuleLoaders) { + if (loader.get() == getImpl().TheClangModuleLoader) + continue; + + if (auto dependencies = loader->getModuleDependencies(moduleName, cache, + delegate)) + return dependencies; + } + return None; +} + void ASTContext::loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration) { PrettyStackTraceDecl stackTrace("loading extensions for", nominal); @@ -2219,6 +2249,24 @@ AbstractFunctionDecl::getForeignErrorConvention() const { return it->second; } +void AbstractFunctionDecl::setForeignAsyncConvention( + const ForeignAsyncConvention &conv) { + assert(hasAsync() && "setting error convention on non-throwing decl"); + auto &conventionsMap = getASTContext().getImpl().ForeignAsyncConventions; + assert(!conventionsMap.count(this) && "error convention already set"); + conventionsMap.insert({this, conv}); +} + +Optional +AbstractFunctionDecl::getForeignAsyncConvention() const { + if (!hasAsync()) + return None; + auto &conventionsMap = getASTContext().getImpl().ForeignAsyncConventions; + auto it = conventionsMap.find(this); + if (it == conventionsMap.end()) return None; + return it->second; +} + Optional swift::getKnownFoundationEntity(StringRef name){ return llvm::StringSwitch>(name) #define FOUNDATION_ENTITY(Name) .Case(#Name, KnownFoundationEntity::Name) @@ -2339,6 +2387,17 @@ Type ErrorType::get(Type originalType) { return entry = new (mem) ErrorType(ctx, originalType, properties); } +Type HoleType::get(ASTContext &ctx, OriginatorType originator) { + assert(originator); + auto properties = reinterpret_cast(originator.getOpaqueValue()) + ->getRecursiveProperties(); + properties |= RecursiveTypeProperties::HasTypeHole; + + auto arena = getArena(properties); + return new (ctx, arena) + HoleType(ctx, originator, RecursiveTypeProperties::HasTypeHole); +} + BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth, const ASTContext &C) { assert(!BitWidth.isArbitraryWidth()); @@ -2780,6 +2839,7 @@ ReferenceStorageType *ReferenceStorageType::get(Type T, ReferenceOwnership ownership, const ASTContext &C) { assert(!T->hasTypeVariable()); // not meaningful in type-checker + assert(!T->hasHole()); switch (optionalityOf(ownership)) { case ReferenceOwnershipOptionality::Disallowed: assert(!T->getOptionalObjectType() && "optional type is disallowed"); @@ -2938,7 +2998,7 @@ isFunctionTypeCanonical(ArrayRef params, static RecursiveTypeProperties getGenericFunctionRecursiveProperties(ArrayRef params, Type result) { - static_assert(RecursiveTypeProperties::BitWidth == 11, + static_assert(RecursiveTypeProperties::BitWidth == 12, "revisit this if you add new recursive type properties"); RecursiveTypeProperties properties; @@ -3112,16 +3172,16 @@ FunctionType *FunctionType::get(ArrayRef params, return funcTy; } - Optional clangTypeInfo = info.getClangTypeInfo(); + auto clangTypeInfo = info.getClangTypeInfo(); size_t allocSize = totalSizeToAlloc( - params.size(), clangTypeInfo.hasValue() ? 1 : 0); + params.size(), clangTypeInfo.empty() ? 0 : 1); void *mem = ctx.Allocate(allocSize, alignof(FunctionType), arena); bool isCanonical = isFunctionTypeCanonical(params, result); - if (clangTypeInfo.hasValue()) { + if (!clangTypeInfo.empty()) { if (ctx.LangOpts.UseClangFunctionTypes) - isCanonical &= clangTypeInfo->type->isCanonicalUnqualified(); + isCanonical &= clangTypeInfo.getType()->isCanonicalUnqualified(); else isCanonical = false; } @@ -3143,8 +3203,8 @@ FunctionType::FunctionType(ArrayRef params, std::uninitialized_copy(params.begin(), params.end(), getTrailingObjects()); auto clangTypeInfo = info.getClangTypeInfo(); - if (clangTypeInfo.hasValue()) - *getTrailingObjects() = clangTypeInfo.getValue(); + if (!clangTypeInfo.empty()) + *getTrailingObjects() = clangTypeInfo; } void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID, @@ -3166,6 +3226,7 @@ GenericFunctionType *GenericFunctionType::get(GenericSignature sig, ExtInfo info) { assert(sig && "no generic signature for generic function type?!"); assert(!result->hasTypeVariable()); + assert(!result->hasHole()); llvm::FoldingSetNodeID id; GenericFunctionType::Profile(id, sig, params, result, info); @@ -3490,7 +3551,7 @@ CanSILFunctionType SILFunctionType::get( void *mem = ctx.Allocate(bytes, alignof(SILFunctionType)); RecursiveTypeProperties properties; - static_assert(RecursiveTypeProperties::BitWidth == 11, + static_assert(RecursiveTypeProperties::BitWidth == 12, "revisit this if you add new recursive type properties"); for (auto ¶m : params) properties |= param.getInterfaceType()->getRecursiveProperties(); @@ -3831,6 +3892,11 @@ CanOpenedArchetypeType OpenedArchetypeType::get(Type existential, protos.push_back(proto->getDecl()); auto layoutConstraint = layout.getLayoutConstraint(); + if (!layoutConstraint && layout.requiresClass()) { + layoutConstraint = LayoutConstraint::getLayoutConstraint( + LayoutConstraintKind::Class); + } + auto layoutSuperclass = layout.getSuperclass(); auto arena = AllocationArena::Permanent; @@ -3877,10 +3943,6 @@ CanType OpenedArchetypeType::getAny(Type existential) { return OpenedArchetypeType::get(existential); } -void TypeLoc::setInvalidType(ASTContext &C) { - Ty = ErrorType::get(C); -} - void SubstitutionMap::Storage::Profile( llvm::FoldingSetNodeID &id, GenericSignature genericSig, @@ -4437,16 +4499,29 @@ Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type, return Type(); } -const clang::Type * -ASTContext::getClangFunctionType(ArrayRef params, - Type resultTy, - FunctionTypeRepresentation trueRep) { +ClangTypeConverter &ASTContext::getClangTypeConverter() { auto &impl = getImpl(); if (!impl.Converter) { auto *cml = getClangModuleLoader(); impl.Converter.emplace(*this, cml->getClangASTContext(), LangOpts.Target); } - return impl.Converter.getValue().getFunctionType(params, resultTy, trueRep); + return impl.Converter.getValue(); +} + +const clang::Type * +ASTContext::getClangFunctionType(ArrayRef params, + Type resultTy, + FunctionTypeRepresentation trueRep) { + return getClangTypeConverter().getFunctionType(params, resultTy, trueRep); +} + +const clang::Type * +ASTContext::getCanonicalClangFunctionType( + ArrayRef params, + Optional result, + SILFunctionType::Representation trueRep) { + auto *ty = getClangTypeConverter().getFunctionType(params, result, trueRep); + return ty ? ty->getCanonicalTypeInternal().getTypePtr() : nullptr; } const Decl * @@ -4765,8 +4840,8 @@ VarDecl *VarDecl::getOriginalWrappedProperty( case PropertyWrapperSynthesizedPropertyKind::Backing: return this == wrapperInfo.backingVar ? original : nullptr; - case PropertyWrapperSynthesizedPropertyKind::StorageWrapper: - return this == wrapperInfo.storageWrapperVar ? original : nullptr; + case PropertyWrapperSynthesizedPropertyKind::Projection: + return this == wrapperInfo.projectionVar ? original : nullptr; } llvm_unreachable("covered switch"); } @@ -4778,6 +4853,36 @@ void VarDecl::setOriginalWrappedProperty(VarDecl *originalProperty) { ctx.getImpl().OriginalWrappedProperties[this] = originalProperty; } +#ifndef NDEBUG +static bool isSourceLocInOrignalBuffer(const Decl *D, SourceLoc Loc) { + assert(Loc.isValid()); + auto bufferID = D->getDeclContext()->getParentSourceFile()->getBufferID(); + assert(bufferID.hasValue() && "Source buffer ID must be set"); + auto &SM = D->getASTContext().SourceMgr; + return SM.getRangeForBuffer(*bufferID).contains(Loc); +} +#endif + +void AbstractFunctionDecl::keepOriginalBodySourceRange() { + auto &impl = getASTContext().getImpl(); + auto result = + impl.OriginalBodySourceRanges.insert({this, getBodySourceRange()}); + assert((!result.second || + isSourceLocInOrignalBuffer(this, result.first->getSecond().Start)) && + "This function must be called before setting new body range"); + (void)result; +} + +SourceRange AbstractFunctionDecl::getOriginalBodySourceRange() const { + auto &impl = getASTContext().getImpl(); + auto found = impl.OriginalBodySourceRanges.find(this); + if (found != impl.OriginalBodySourceRanges.end()) { + return found->getSecond(); + } else { + return getBodySourceRange(); + } +} + IndexSubset * IndexSubset::get(ASTContext &ctx, const SmallBitVector &indices) { auto &foldingSet = ctx.getImpl().IndexSubsets; diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 44d32c84a7a7d..6174ca0f6145b 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -44,7 +44,7 @@ Type swift::Demangle::getTypeForMangling(ASTContext &ctx, return Type(); ASTBuilder builder(ctx); - return swift::Demangle::decodeMangledType(builder, node); + return swift::Demangle::decodeMangledType(builder, node).getType(); } TypeDecl *swift::Demangle::getTypeDeclForMangling(ASTContext &ctx, @@ -144,7 +144,7 @@ Type ASTBuilder::createNominalType(GenericTypeDecl *decl, Type parent) { return Type(); // If the declaration is generic, fail. - if (nominalDecl->getGenericParams()) + if (auto list = nominalDecl->getGenericParams()) return Type(); // Imported types can be renamed to be members of other (non-generic) @@ -200,21 +200,16 @@ createSubstitutionMapFromGenericArgs(GenericSignature genericSig, if (!genericSig) return SubstitutionMap(); - SmallVector genericParams; - genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) { - if (canonical) - genericParams.push_back(gp); - }); - if (genericParams.size() != args.size()) + if (genericSig->getGenericParams().size() != args.size()) return SubstitutionMap(); return SubstitutionMap::get( genericSig, [&](SubstitutableType *t) -> Type { - for (unsigned i = 0, e = genericParams.size(); i < e; ++i) { - if (t->isEqual(genericParams[i])) - return args[i]; - } + auto *gp = cast(t); + unsigned ordinal = genericSig->getGenericParamOrdinal(gp); + if (ordinal < args.size()) + return args[ordinal]; return Type(); }, LookUpConformanceInModule(moduleDecl)); @@ -530,7 +525,7 @@ Type ASTBuilder::createImplFunctionType( // [TODO: Store-SIL-Clang-type] auto einfo = SILExtInfoBuilder(representation, flags.isPseudogeneric(), - !flags.isEscaping(), diffKind, + !flags.isEscaping(), flags.isAsync(), diffKind, /*clangFunctionType*/ nullptr) .build(); @@ -846,8 +841,8 @@ CanGenericSignature ASTBuilder::demangleGenericSignature( if (child->getNumChildren() != 2) return CanGenericSignature(); - auto subjectType = swift::Demangle::decodeMangledType( - *this, child->getChild(0)); + auto subjectType = + swift::Demangle::decodeMangledType(*this, child->getChild(0)).getType(); if (!subjectType) return CanGenericSignature(); @@ -856,8 +851,9 @@ CanGenericSignature ASTBuilder::demangleGenericSignature( Demangle::Node::Kind::DependentGenericConformanceRequirement || child->getKind() == Demangle::Node::Kind::DependentGenericSameTypeRequirement) { - constraintType = swift::Demangle::decodeMangledType( - *this, child->getChild(1)); + constraintType = + swift::Demangle::decodeMangledType(*this, child->getChild(1)) + .getType(); if (!constraintType) return CanGenericSignature(); } diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 532790cc94f3b..f1544695fc82e 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ClangModuleLoader.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" @@ -585,6 +586,9 @@ namespace { if (D->isImplicit()) PrintWithColorRAII(OS, DeclModifierColor) << " implicit"; + if (D->isHoisted()) + PrintWithColorRAII(OS, DeclModifierColor) << " hoisted"; + auto R = D->getSourceRange(); if (R.isValid()) { PrintWithColorRAII(OS, RangeColor) << " range="; @@ -952,6 +956,16 @@ namespace { D->getCaptureInfo().print(OS); } + if (auto fac = D->getForeignAsyncConvention()) { + OS << " foreign_async="; + if (auto type = fac->completionHandlerType()) + type.print(OS); + OS << ",completion_handler_param=" + << fac->completionHandlerParamIndex(); + if (auto errorParamIndex = fac->completionHandlerErrorParamIndex()) + OS << ",error_param=" << *errorParamIndex; + } + if (auto fec = D->getForeignErrorConvention()) { OS << " foreign_error="; OS << getForeignErrorConventionKindString(fec->getKind()); @@ -1074,13 +1088,13 @@ namespace { Indent -= 2; if (auto FD = dyn_cast(D)) { - if (FD->getBodyResultTypeLoc().getTypeRepr()) { + if (FD->getResultTypeRepr()) { OS << '\n'; Indent += 2; OS.indent(Indent); PrintWithColorRAII(OS, ParenthesisColor) << '('; OS << "result\n"; - printRec(FD->getBodyResultTypeLoc().getTypeRepr()); + printRec(FD->getResultTypeRepr()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; if (auto opaque = FD->getOpaqueResultTypeDecl()) { OS << '\n'; @@ -2108,11 +2122,8 @@ class PrintExpr : public ExprVisitor { void visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { printCommon(E, "unresolved_member_expr") << " name='" << E->getName() << "'"; - printArgumentLabels(E->getArgumentLabels()); - if (E->getArgument()) { - OS << '\n'; - printRec(E->getArgument()); - } + PrintWithColorRAII(OS, ExprModifierColor) + << " function_ref=" << getFunctionRefKindStr(E->getFunctionRefKind()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDotSelfExpr(DotSelfExpr *E) { @@ -2135,7 +2146,12 @@ class PrintExpr : public ExprVisitor { printRec(E->getSubExpr()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitUnresolvedMemberChainResultExpr(UnresolvedMemberChainResultExpr *E){ + printCommon(E, "unresolved_member_chain_expr"); + OS << '\n'; + printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } void visitTupleExpr(TupleExpr *E) { printCommon(E, "tuple_expr"); if (E->hasTrailingClosure()) @@ -3496,6 +3512,18 @@ namespace { TRIVIAL_TYPE_PRINTER(Unresolved, unresolved) + void visitHoleType(HoleType *T, StringRef label) { + printCommon(label, "hole_type"); + auto originatorTy = T->getOriginatorType(); + if (auto *typeVar = originatorTy.dyn_cast()) { + printRec("type_variable", typeVar); + } else { + printRec("dependent_member_type", + originatorTy.get()); + } + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitBuiltinIntegerType(BuiltinIntegerType *T, StringRef label) { printCommon(label, "builtin_integer_type"); if (T->isFixedWidth()) @@ -3767,7 +3795,9 @@ namespace { if (!T->getClangTypeInfo().empty()) { std::string s; llvm::raw_string_ostream os(s); - T->getClangTypeInfo().dump(os); + auto &ctx = T->getASTContext().getClangModuleLoader() + ->getClangASTContext(); + T->getClangTypeInfo().dump(os, ctx); printField("clang_type", os.str()); } printAnyFunctionParams(T->getParams(), "input"); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index e013ad5db8b3c..8da9843183986 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -39,6 +39,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" @@ -335,21 +336,29 @@ std::string ASTMangler::mangleKeyPathHashHelper(ArrayRef indices, return finalize(); } -std::string ASTMangler::mangleGlobalInit(const VarDecl *decl, int counter, +std::string ASTMangler::mangleGlobalInit(const PatternBindingDecl *pd, + unsigned pbdEntry, bool isInitFunc) { - auto topLevelContext = decl->getDeclContext()->getModuleScopeContext(); - auto fileUnit = cast(topLevelContext); - Identifier discriminator = fileUnit->getDiscriminatorForPrivateValue(decl); - assert(!discriminator.empty()); - assert(!isNonAscii(discriminator.str()) && - "discriminator contains non-ASCII characters"); - assert(!clang::isDigit(discriminator.str().front()) && - "not a valid identifier"); - - Buffer << "globalinit_"; - appendIdentifier(discriminator.str()); - Buffer << (isInitFunc ? "_func" : "_token"); - Buffer << counter; + beginMangling(); + + Pattern *pattern = pd->getPattern(pbdEntry); + bool first = true; + pattern->forEachVariable([&](VarDecl *D) { + if (first) { + appendContextOf(D); + first = false; + } + appendDeclName(D); + appendListSeparator(); + }); + assert(!first && "no variables in pattern binding?!"); + + if (isInitFunc) { + appendOperator("WZ"); + } else { + appendOperator("Wz"); + } + return finalize(); } @@ -914,6 +923,7 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) { TypeBase *tybase = type.getPointer(); switch (type->getKind()) { case TypeKind::TypeVariable: + case TypeKind::Hole: llvm_unreachable("mangling type variable"); case TypeKind::Module: @@ -2114,6 +2124,7 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) { // Always use Clang names for imported Clang declarations, unless they don't // have one. auto tryAppendClangName = [this, decl]() -> bool { + auto *nominal = dyn_cast(decl); auto namedDecl = getClangDeclForMangling(decl); if (!namedDecl) return false; @@ -2126,6 +2137,13 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) { appendIdentifier(interface->getObjCRuntimeNameAsString()); } else if (UseObjCRuntimeNames && protocol) { appendIdentifier(protocol->getObjCRuntimeNameAsString()); + } else if (auto ctsd = dyn_cast(namedDecl)) { + // If this is a `ClassTemplateSpecializationDecl`, it was + // imported as a Swift decl with `__CxxTemplateInst...` name. + // `ClassTemplateSpecializationDecl`'s name does not include information about + // template arguments, and in order to prevent name clashes we use the + // name of the Swift decl which does include template arguments. + appendIdentifier(nominal->getName().str()); } else { appendIdentifier(namedDecl->getName()); } diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 49305518234fc..65b3ea8af59a9 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -24,7 +24,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/FileUnit.h" -#include "swift/AST/GenericEnvironment.h" +#include "swift/AST/GenericSignature.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" @@ -48,6 +48,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/Module.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ConvertUTF.h" @@ -58,6 +59,11 @@ using namespace swift; +// Defined here to avoid repeatedly paying the price of template instantiation. +const std::function + PrintOptions::defaultPrintExtensionContentAsMembers + = [] (const ExtensionDecl *) { return false; }; + void PrintOptions::setBaseType(Type T) { if (T->is()) return; @@ -169,6 +175,24 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr, if (auto *ED = dyn_cast(D)) { if (!shouldPrint(ED->getExtendedNominal(), options)) return false; + + // Skip extensions to implementation-only imported types that have + // no public members. + auto localModule = ED->getParentModule(); + auto nominalModule = ED->getExtendedNominal()->getParentModule(); + if (localModule != nominalModule && + localModule->isImportedImplementationOnly(nominalModule)) { + + bool shouldPrintMembers = llvm::any_of( + ED->getMembers(), + [&](const Decl *member) -> bool { + return shouldPrint(member, options); + }); + + if (!shouldPrintMembers) + return false; + } + for (const Requirement &req : ED->getGenericRequirements()) { if (!isPublicOrUsableFromInline(req.getFirstType())) return false; @@ -1297,9 +1321,9 @@ bestRequirementPrintLocation(ProtocolDecl *proto, const Requirement &req) { bool inWhereClause; switch (req.getKind()) { + case RequirementKind::Layout: case RequirementKind::Conformance: - case RequirementKind::Superclass: - case RequirementKind::Layout: { + case RequirementKind::Superclass: { auto subject = req.getFirstType(); auto result = findRelevantDeclAndDirectUse(subject); @@ -1351,6 +1375,15 @@ void PrintAST::printInheritedFromRequirementSignature(ProtocolDecl *proto, proto->getRequirementSignature()), PrintInherited, [&](const Requirement &req) { + // Skip the inferred 'Self : AnyObject' constraint if this is an + // @objc protocol. + if (req.getKind() == RequirementKind::Layout && + req.getFirstType()->isEqual(proto->getProtocolSelfType()) && + req.getLayoutConstraint()->getKind() == LayoutConstraintKind::Class && + proto->isObjC()) { + return false; + } + auto location = bestRequirementPrintLocation(proto, req); return location.AttachedTo == attachingTo && !location.InWhereClause; }); @@ -2461,14 +2494,14 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { Printer << " = "; // FIXME: An inferred associated type witness type alias may reference // an opaque type, but OpaqueTypeArchetypes are always canonicalized - // so lose type sugar for generic params. Bind the generic environment so - // we can map params back into the generic environment and print them + // so lose type sugar for generic params. Bind the generic signature so + // we can map params back into the generic signature and print them // correctly. // // Remove this when we have a way to represent non-canonical archetypes // preserving sugar. - llvm::SaveAndRestore setGenericEnv(Options.GenericEnv, - decl->getGenericEnvironment()); + llvm::SaveAndRestore setGenericSig( + Options.GenericSig, decl->getGenericSignature().getPointer()); printTypeLoc(TypeLoc(decl->getUnderlyingTypeRepr(), Ty)); printDeclGenericRequirements(decl); } @@ -2939,8 +2972,8 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) { if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) { SourceLoc StartLoc = decl->getStartLoc(); SourceLoc EndLoc; - if (!decl->getBodyResultTypeLoc().isNull()) { - EndLoc = decl->getBodyResultTypeLoc().getSourceRange().End; + if (decl->getResultTypeRepr()) { + EndLoc = decl->getResultTypeSourceRange().End; } else { EndLoc = decl->getSignatureSourceRange().End; } @@ -2977,7 +3010,7 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) { Type ResultTy = decl->getResultInterfaceType(); if (ResultTy && !ResultTy->isVoid()) { - TypeLoc ResultTyLoc = decl->getBodyResultTypeLoc(); + TypeLoc ResultTyLoc(decl->getResultTypeRepr(), ResultTy); // When printing a protocol requirement with types substituted for a // conforming class, replace occurrences of the 'Self' generic parameter @@ -3157,9 +3190,8 @@ void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) { }); Printer << " -> "; - TypeLoc elementTy = decl->getElementTypeLoc(); - if (!elementTy.getTypeRepr()) - elementTy = TypeLoc::withoutLoc(decl->getElementInterfaceType()); + TypeLoc elementTy(decl->getElementTypeRepr(), + decl->getElementInterfaceType()); Printer.printDeclResultTypePre(decl, elementTy); Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); @@ -3603,7 +3635,7 @@ void printCType(ASTContext &Ctx, ASTPrinter &Printer, ExtInfo &info) { auto *cml = Ctx.getClangModuleLoader(); SmallString<64> buf; llvm::raw_svector_ostream os(buf); - info.getClangTypeInfo().getValue().printType(cml, os); + info.getClangTypeInfo().printType(cml, os); Printer << ", cType: " << QuotedString(os.str()); } @@ -3771,8 +3803,11 @@ class TypePrinter : public TypeVisitor { } void visitErrorType(ErrorType *T) { - if (auto originalType = T->getOriginalType()) + if (auto originalType = T->getOriginalType()) { + if (Options.PrintInSILBody) + Printer << "@error_type "; visit(originalType); + } else Printer << "<>"; } @@ -3784,6 +3819,17 @@ class TypePrinter : public TypeVisitor { Printer << "_"; } + void visitHoleType(HoleType *T) { + if (Options.PrintTypesForDebugging) { + Printer << "<getOriginatorType(); + visit(Type(reinterpret_cast(originatorTy.getOpaqueValue()))); + Printer << ">>"; + } else { + Printer << "<>"; + } + } + #ifdef ASTPRINTER_HANDLE_BUILTINTYPE #error "ASTPRINTER_HANDLE_BUILTINTYPE should not be defined?!" #endif @@ -4025,7 +4071,7 @@ class TypePrinter : public TypeVisitor { case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; // [TODO: Clang-type-plumbing] Remove the second check. - if (printNameOnly || !info.getClangTypeInfo().hasValue()) + if (printNameOnly || info.getClangTypeInfo().empty()) break; printCType(Ctx, Printer, info); break; @@ -4091,7 +4137,7 @@ class TypePrinter : public TypeVisitor { case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; // [TODO: Clang-type-plumbing] Remove the second check. - if (printNameOnly || !info.getClangTypeInfo().hasValue()) + if (printNameOnly || info.getClangTypeInfo().empty()) break; printCType(Ctx, Printer, info); break; @@ -4122,6 +4168,9 @@ class TypePrinter : public TypeVisitor { if (info.isNoEscape()) { Printer.printSimpleAttr("@noescape") << " "; } + if (info.isAsync()) { + Printer.printSimpleAttr("@async") << " "; + } } void visitAnyFunctionTypeParams(ArrayRef Params, @@ -4238,6 +4287,12 @@ class TypePrinter : public TypeVisitor { llvm_unreachable("bad convention"); } + void printSILAsyncAttr(bool isAsync) { + if (isAsync) { + Printer << "@async "; + } + } + void printCalleeConvention(ParameterConvention conv) { switch (conv) { case ParameterConvention::Direct_Unowned: @@ -4283,7 +4338,7 @@ class TypePrinter : public TypeVisitor { Optional subBuffer; PrintOptions subOptions = Options; if (auto substitutions = T->getPatternSubstitutions()) { - subOptions.GenericEnv = nullptr; + subOptions.GenericSig = nullptr; subBuffer.emplace(Printer, subOptions); sub = &*subBuffer; @@ -4375,7 +4430,7 @@ class TypePrinter : public TypeVisitor { // A box layout has its own independent generic environment. Don't try // to print it with the environment's generic params. PrintOptions subOptions = Options; - subOptions.GenericEnv = nullptr; + subOptions.GenericSig = nullptr; TypePrinter sub(Printer, subOptions); // Capture list used here to ensure we don't print anything using `this` @@ -4558,10 +4613,10 @@ class TypePrinter : public TypeVisitor { } } - // When printing SIL types, use a generic environment to map them from + // When printing SIL types, use a generic signature to map them from // canonical types to sugared types. - if (Options.GenericEnv) - T = Options.GenericEnv->getSugaredType(T); + if (Options.GenericSig) + T = Options.GenericSig->getSugaredType(T); } auto Name = T->getName(); diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index e2b30ed302bb6..d2818027ef2b2 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -354,10 +354,10 @@ class ScopeCreator final { ASTScopeImpl *constructExpandAndInsert(ASTScopeImpl *parent, Args... args) { auto *child = new (ctx) Scope(args...); parent->addChild(child, ctx); - if (shouldBeLazy()) { - if (auto *ip = child->insertionPointForDeferredExpansion().getPtrOrNull()) - return ip; - } + + if (auto *ip = child->insertionPointForDeferredExpansion().getPtrOrNull()) + return ip; + ASTScopeImpl *insertionPoint = child->expandAndBeCurrentDetectingRecursion(*this); ASTScopeAssert(child->verifyThatThisNodeComeAfterItsPriorSibling(), @@ -479,23 +479,6 @@ class ScopeCreator final { } public: - /// When ASTScopes are enabled for code completion, - /// IfConfigs will pose a challenge because we may need to field lookups into - /// the inactive clauses, but the AST contains redundancy: the active clause's - /// elements are present in the members or elements of an IterableTypeDecl or - /// BraceStmt alongside of the IfConfigDecl. In addition there are two more - /// complications: - /// - /// 1. The active clause's elements may be nested inside an init self - /// rebinding decl (as in StringObject.self). - /// - /// 2. The active clause may be before or after the inactive ones - /// - /// So, when encountering an IfConfigDecl, we will expand the inactive - /// elements. Also, always sort members or elements so that the child scopes - /// are in source order (Just one of several reasons we need to sort.) - /// - static const bool includeInactiveIfConfigClauses = false; private: static std::vector expandIfConfigClauses(ArrayRef input) { @@ -526,9 +509,6 @@ class ScopeCreator final { if (isa(d)) expandIfConfigClausesInto(expansion, {d}, true); } - } else if (includeInactiveIfConfigClauses) { - expandIfConfigClausesInto(expansion, clause.Elements, - /*isInAnActiveNode=*/false); } } } @@ -666,8 +646,6 @@ class ScopeCreator final { return !n.isDecl(DeclKind::Var); } - bool shouldBeLazy() const { return ctx.LangOpts.LazyASTScopes; } - public: /// For debugging. Return true if scope tree contains all the decl contexts in /// the AST May modify the scope tree in order to update obsolete scopes. @@ -762,10 +740,6 @@ void ASTScope:: impl->buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); } -bool ASTScope::areInactiveIfConfigClausesSupported() { - return ScopeCreator::includeInactiveIfConfigClauses; -} - void ASTScope::expandFunctionBody(AbstractFunctionDecl *AFD) { auto *const SF = AFD->getParentSourceFile(); SF->getScope().expandFunctionBodyImpl(AFD); @@ -795,7 +769,7 @@ void ASTSourceFileScope:: void ASTSourceFileScope::expandFunctionBody(AbstractFunctionDecl *AFD) { if (!AFD) return; - auto sr = AFD->getBodySourceRange(); + auto sr = AFD->getOriginalBodySourceRange(); if (sr.isInvalid()) return; ASTScopeImpl *bodyScope = findInnermostEnclosingScope(sr.Start, nullptr); @@ -1110,8 +1084,6 @@ void ASTScopeImpl::disownDescendants(ScopeCreator &scopeCreator) { ASTScopeImpl * ASTScopeImpl::expandAndBeCurrentDetectingRecursion(ScopeCreator &scopeCreator) { - assert(scopeCreator.getASTContext().LangOpts.EnableASTScopeLookup && - "Should not be getting here if ASTScopes are disabled"); return evaluateOrDefault(scopeCreator.getASTContext().evaluator, ExpandASTScopeRequest{this, &scopeCreator}, nullptr); } @@ -1147,14 +1119,13 @@ ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) { disownDescendants(scopeCreator); auto *insertionPoint = expandSpecifically(scopeCreator); - if (scopeCreator.shouldBeLazy()) { - ASTScopeAssert(!insertionPointForDeferredExpansion() || - insertionPointForDeferredExpansion().get() == - insertionPoint, - "In order for lookups into lazily-expanded scopes to be " - "accurate before expansion, the insertion point before " - "expansion must be the same as after expansion."); - } + ASTScopeAssert(!insertionPointForDeferredExpansion() || + insertionPointForDeferredExpansion().get() == + insertionPoint, + "In order for lookups into lazily-expanded scopes to be " + "accurate before expansion, the insertion point before " + "expansion must be the same as after expansion."); + replaceASTAncestorScopes(astAncestorScopes); setWasExpanded(); beCurrent(); @@ -1596,11 +1567,6 @@ ASTScopeImpl *GenericTypeOrExtensionWholePortion::expandScope( // Get now in case recursion emancipates scope auto *const ip = scope->getParent().get(); - // Prevent circular request bugs caused by illegal input and - // doing lookups that getExtendedNominal in the midst of getExtendedNominal. - if (scope->shouldHaveABody() && !scope->doesDeclHaveABody()) - return ip; - auto *context = scope->getGenericContext(); auto *genericParams = (isa(context) ? context->getParsedGenericParams() @@ -1609,6 +1575,12 @@ ASTScopeImpl *GenericTypeOrExtensionWholePortion::expandScope( scope->getDecl(), genericParams, scope); if (context->getTrailingWhereClause()) scope->createTrailingWhereClauseScope(deepestScope, scopeCreator); + + // Prevent circular request bugs caused by illegal input and + // doing lookups that getExtendedNominal in the midst of getExtendedNominal. + if (scope->shouldHaveABody() && !scope->doesDeclHaveABody()) + return ip; + scope->createBodyScope(deepestScope, scopeCreator); return ip; } @@ -2082,10 +2054,8 @@ class LocalizableDeclContextCollector : public ASTWalker { // catchForDebugging(D, "DictionaryBridging.swift", 694); if (const auto *dc = dyn_cast(D)) record(dc); - if (auto *icd = dyn_cast(D)) { - walkToClauses(icd); + if (isa(D)) return false; - } if (auto *pd = dyn_cast(D)) record(pd->getDefaultArgumentInitContext()); else if (auto *pbd = dyn_cast(D)) @@ -2103,18 +2073,6 @@ class LocalizableDeclContextCollector : public ASTWalker { } private: - void walkToClauses(IfConfigDecl *icd) { - for (auto &clause : icd->getClauses()) { - // Generate scopes for any closures in the condition - if (ScopeCreator::includeInactiveIfConfigClauses && clause.isActive) { - if (clause.Cond) - clause.Cond->walk(*this); - for (auto n : clause.Elements) - n.walk(*this); - } - } - } - void recordInitializers(PatternBindingDecl *pbd) { for (auto idx : range(pbd->getNumPatternEntries())) record(pbd->getInitContext(idx)); diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 13ab5b86a3177..7896e009534a2 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -30,7 +30,6 @@ #include "swift/AST/TypeRepr.h" #include "swift/Basic/STLExtras.h" #include "llvm/Support/Compiler.h" -#include using namespace swift; using namespace namelookup; @@ -82,6 +81,15 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( // Someday, just use the assertion below. For now, print out lots of info for // debugging. if (!startingScope) { + + // Be lenient in code completion mode. There are cases where the decl + // context doesn't match with the ASTScope. e.g. dangling attributes. + // FIXME: Create ASTScope tree even for invalid code. + if (innermost && + startingContext->getASTContext().SourceMgr.hasCodeCompletionBuffer()) { + return innermost; + } + llvm::errs() << "ASTScopeImpl: resorting to startingScope hack, file: " << sourceFile->getFilename() << "\n"; // The check is costly, and inactive lookups will end up here, so don't @@ -143,33 +151,40 @@ bool ASTScopeImpl::checkSourceRangeOfThisASTNode() const { return true; } +/// If the \p loc is in a new buffer but \p range is not, consider the location +/// is at the start of replaced range. Otherwise, returns \p loc as is. +static SourceLoc translateLocForReplacedRange(SourceManager &sourceMgr, + SourceRange range, + SourceLoc loc) { + if (const auto &replacedRange = sourceMgr.getReplacedRange()) { + if (sourceMgr.rangeContainsTokenLoc(replacedRange.New, loc) && + !sourceMgr.rangeContains(replacedRange.New, range)) { + return replacedRange.Original.Start; + } + } + return loc; +} + NullablePtr ASTScopeImpl::findChildContaining(SourceLoc loc, SourceManager &sourceMgr) const { // Use binary search to find the child that contains this location. - struct CompareLocs { - SourceManager &sourceMgr; - - bool operator()(const ASTScopeImpl *scope, SourceLoc loc) { - ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); - return -1 == ASTScopeImpl::compare(scope->getSourceRangeOfScope(), loc, - sourceMgr, - /*ensureDisjoint=*/false); - } - bool operator()(SourceLoc loc, const ASTScopeImpl *scope) { - ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); - // Alternatively, we could check that loc < start-of-scope - return 0 >= ASTScopeImpl::compare(loc, scope->getSourceRangeOfScope(), - sourceMgr, - /*ensureDisjoint=*/false); - } - }; - auto *const *child = std::lower_bound( - getChildren().begin(), getChildren().end(), loc, CompareLocs{sourceMgr}); - - if (child != getChildren().end() && - sourceMgr.rangeContainsTokenLoc((*child)->getSourceRangeOfScope(), loc)) - return *child; + auto *const *child = llvm::lower_bound( + getChildren(), loc, + [&sourceMgr](const ASTScopeImpl *scope, SourceLoc loc) { + ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); + auto rangeOfScope = scope->getSourceRangeOfScope(); + loc = translateLocForReplacedRange(sourceMgr, rangeOfScope, loc); + return -1 == ASTScopeImpl::compare(rangeOfScope, loc, sourceMgr, + /*ensureDisjoint=*/false); + }); + + if (child != getChildren().end()) { + auto rangeOfScope = (*child)->getSourceRangeOfScope(); + loc = translateLocForReplacedRange(sourceMgr, rangeOfScope, loc); + if (sourceMgr.rangeContainsTokenLoc(rangeOfScope, loc)) + return *child; + } return nullptr; } @@ -504,7 +519,7 @@ bool BraceStmtScope::lookupLocalsOrMembers(ArrayRef, bool PatternEntryInitializerScope::lookupLocalsOrMembers( ArrayRef, DeclConsumer consumer) const { // 'self' is available within the pattern initializer of a 'lazy' variable. - auto *initContext = cast_or_null( + auto *initContext = dyn_cast_or_null( decl->getInitContext(0)); if (initContext) { if (auto *selfParam = initContext->getImplicitSelfDecl()) { @@ -801,7 +816,7 @@ Optional ClosureBodyScope::resolveIsCascadingUseForThisScope( Optional PatternEntryInitializerScope::resolveIsCascadingUseForThisScope( Optional isCascadingUse) const { auto *const initContext = getPatternEntry().getInitContext(); - auto *PBI = cast_or_null(initContext); + auto *PBI = dyn_cast_or_null(initContext); auto *isd = PBI ? PBI->getImplicitSelfDecl() : nullptr; // 'self' is available within the pattern initializer of a 'lazy' variable. diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index 731826ad5f6a3..87713befcfcb2 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -67,6 +67,14 @@ ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range, if (range.isInvalid()) return childRange; auto r = range; + + // HACK: For code completion. If the range of the child is from another + // source buffer, don't widen using that range. + if (const auto &replacedRange = getSourceManager().getReplacedRange()) { + if (getSourceManager().rangeContains(replacedRange.Original, range) && + getSourceManager().rangeContains(replacedRange.New, childRange)) + return r; + } r.widen(childRange); return r; } @@ -114,6 +122,14 @@ bool ASTScopeImpl::verifyThatChildrenAreContainedWithin( getChildren().back()->getSourceRangeOfScope().End); if (getSourceManager().rangeContains(range, rangeOfChildren)) return true; + + // HACK: For code completion. Handle replaced range. + if (const auto &replacedRange = getSourceManager().getReplacedRange()) { + if (getSourceManager().rangeContains(replacedRange.Original, range) && + getSourceManager().rangeContains(replacedRange.New, rangeOfChildren)) + return true; + } + auto &out = verificationError() << "children not contained in its parent\n"; if (getChildren().size() == 1) { out << "\n***Only Child node***\n"; @@ -200,7 +216,7 @@ SourceRange DifferentiableAttributeScope::getSourceRangeOfThisASTNode( SourceRange AbstractFunctionBodyScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { - return decl->getBodySourceRange(); + return decl->getOriginalBodySourceRange(); } SourceRange TopLevelCodeScope::getSourceRangeOfThisASTNode( @@ -357,7 +373,7 @@ SourceRange AbstractFunctionDeclScope::getSourceRangeOfThisASTNode( ASTScopeAssert(r.End.isValid(), "Start valid imples end valid."); return r; } - return decl->getBodySourceRange(); + return decl->getOriginalBodySourceRange(); } SourceRange ParameterListScope::getSourceRangeOfThisASTNode( @@ -510,8 +526,6 @@ void ASTScopeImpl::computeAndCacheSourceRangeOfScope( } bool ASTScopeImpl::checkLazySourceRange(const ASTContext &ctx) const { - if (!ctx.LangOpts.LazyASTScopes) - return true; const auto unexpandedRange = sourceRangeForDeferredExpansion(); const auto expandedRange = computeSourceRangeOfScopeWithChildASTNodes(); if (unexpandedRange.isInvalid() || expandedRange.isInvalid()) @@ -609,7 +623,7 @@ SourceRange IterableTypeScope::sourceRangeForDeferredExpansion() const { return portion->sourceRangeForDeferredExpansion(this); } SourceRange AbstractFunctionBodyScope::sourceRangeForDeferredExpansion() const { - const auto bsr = decl->getBodySourceRange(); + const auto bsr = decl->getOriginalBodySourceRange(); const SourceLoc endEvenIfNoCloseBraceAndEndsWithInterpolatedStringLiteral = getLocEncompassingPotentialLookups(getSourceManager(), bsr.End); return SourceRange(bsr.Start, diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index aebc89a1c267a..78ce70008c8ea 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -20,6 +20,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" @@ -2994,8 +2995,23 @@ class Verifier : public ASTWalker { } } - // Throwing @objc methods must have a foreign error convention. + // Asynchronous @objc methods must have a foreign async convention. if (AFD->isObjC() && + static_cast(AFD->getForeignAsyncConvention()) + != AFD->hasAsync()) { + if (AFD->hasAsync()) + Out << "@objc method async but does not have a foreign async " + << "convention"; + else + Out << "@objc method has a foreign async convention but is not " + << "async"; + abort(); + } + + // Synchronous throwing @objc methods must have a foreign error + // convention. + if (AFD->isObjC() && + !AFD->hasAsync() && static_cast(AFD->getForeignErrorConvention()) != AFD->hasThrows()) { if (AFD->hasThrows()) diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 3641f7c807627..ef2ba5afb7cbf 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -358,7 +358,7 @@ class Traversal : public ASTVisitorgetIndices()); - if (auto *const TyR = SD->getElementTypeLoc().getTypeRepr()) + if (auto *const TyR = SD->getElementTypeRepr()) if (doIt(TyR)) return true; @@ -394,7 +394,7 @@ class Traversal : public ASTVisitor(AFD)) { if (!isa(FD)) - if (auto *const TyR = FD->getBodyResultTypeLoc().getTypeRepr()) + if (auto *const TyR = FD->getResultTypeRepr()) if (doIt(TyR)) return true; } @@ -504,17 +504,7 @@ class Traversal : public ASTVisitorgetArgument()) { - if (auto arg = doIt(E->getArgument())) { - E->setArgument(arg); - return E; - } - - return nullptr; - } - return E; - } + Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { return E; } Expr *visitOpaqueValueExpr(OpaqueValueExpr *E) { return E; } diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 69719bfb62ce6..70a1ec3429409 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -589,32 +589,11 @@ static void printDifferentiableAttrArguments( if (!isLeadingClause) stream << ' '; stream << "where "; - std::function getInterfaceType; - if (!original || !original->getGenericEnvironment()) { - getInterfaceType = [](Type Ty) -> Type { return Ty; }; - } else { - // Use GenericEnvironment to produce user-friendly - // names instead of something like 't_0_0'. - auto *genericEnv = original->getGenericEnvironment(); - assert(genericEnv); - getInterfaceType = [=](Type Ty) -> Type { - return genericEnv->getSugaredType(Ty); - }; - } interleave(requirementsToPrint, [&](Requirement req) { if (const auto &originalGenSig = original->getGenericSignature()) if (originalGenSig->isRequirementSatisfied(req)) return; - auto FirstTy = getInterfaceType(req.getFirstType()); - if (req.getKind() != RequirementKind::Layout) { - auto SecondTy = getInterfaceType(req.getSecondType()); - Requirement ReqWithDecls(req.getKind(), FirstTy, SecondTy); - ReqWithDecls.print(stream, Options); - } else { - Requirement ReqWithDecls(req.getKind(), FirstTy, - req.getLayoutConstraint()); - ReqWithDecls.print(stream, Options); - } + req.print(stream, Options); }, [&] { stream << ", "; }); @@ -928,25 +907,16 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, Printer << "kind: " << kind << ", "; SmallVector requirementsScratch; ArrayRef requirements; - if (auto sig = attr->getSpecializedSgnature()) + if (auto sig = attr->getSpecializedSignature()) requirements = sig->getRequirements(); - std::function GetInterfaceType; auto *FnDecl = dyn_cast_or_null(D); - if (!FnDecl || !FnDecl->getGenericEnvironment()) - GetInterfaceType = [](Type Ty) -> Type { return Ty; }; - else { - // Use GenericEnvironment to produce user-friendly - // names instead of something like t_0_0. - auto *GenericEnv = FnDecl->getGenericEnvironment(); - assert(GenericEnv); - GetInterfaceType = [=](Type Ty) -> Type { - return GenericEnv->getSugaredType(Ty); - }; - - if (auto sig = attr->getSpecializedSgnature()) { + if (FnDecl && FnDecl->getGenericSignature()) { + auto genericSig = FnDecl->getGenericSignature(); + + if (auto sig = attr->getSpecializedSignature()) { requirementsScratch = sig->requirementsNotSatisfiedBy( - GenericEnv->getGenericSignature()); + genericSig); requirements = requirementsScratch; } } @@ -957,16 +927,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, interleave(requirements, [&](Requirement req) { - auto FirstTy = GetInterfaceType(req.getFirstType()); - if (req.getKind() != RequirementKind::Layout) { - auto SecondTy = GetInterfaceType(req.getSecondType()); - Requirement ReqWithDecls(req.getKind(), FirstTy, SecondTy); - ReqWithDecls.print(Printer, Options); - } else { - Requirement ReqWithDecls(req.getKind(), FirstTy, - req.getLayoutConstraint()); - ReqWithDecls.print(Printer, Options); - } + req.print(Printer, Options); }, [&] { Printer << ", "; }); diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index a28946dc49bc4..743d3f80c69fb 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -306,21 +306,21 @@ AvailabilityContext ASTContext::getTypesInAbstractMetadataStateAvailability() { } AvailabilityContext ASTContext::getPrespecializedGenericMetadataAvailability() { - return getSwift53Availability(); + return getSwift54Availability(); } AvailabilityContext ASTContext::getCompareTypeContextDescriptorsAvailability() { - return getSwiftFutureAvailability(); + return getSwift54Availability(); } AvailabilityContext ASTContext::getCompareProtocolConformanceDescriptorsAvailability() { - return getSwiftFutureAvailability(); + return getSwift54Availability(); } AvailabilityContext ASTContext::getIntermodulePrespecializedGenericMetadataAvailability() { - return getSwiftFutureAvailability(); + return getSwift54Availability(); } AvailabilityContext ASTContext::getSwift52Availability() { @@ -384,6 +384,10 @@ AvailabilityContext ASTContext::getSwift53Availability() { } } +AvailabilityContext ASTContext::getSwift54Availability() { + return getSwiftFutureAvailability(); +} + AvailabilityContext ASTContext::getSwiftFutureAvailability() { auto target = LangOpts.Target; diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index dde68fa9c1ea8..f49276266cfce 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -168,16 +168,10 @@ getBuiltinFunction(Identifier Id, ArrayRef argTypes, Type ResType) { auto *paramList = ParameterList::create(Context, params); DeclName Name(Context, Id, paramList); - auto FD = FuncDecl::create(Context, /*StaticLoc=*/SourceLoc(), - StaticSpellingKind::None, - /*FuncLoc=*/SourceLoc(), - Name, /*NameLoc=*/SourceLoc(), - /*Async-*/false, /*AsyncLoc=*/SourceLoc(), - /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - /*GenericParams=*/nullptr, - paramList, - TypeLoc::withoutLoc(ResType), DC); - FD->setImplicit(); + auto *const FD = FuncDecl::createImplicit( + Context, StaticSpellingKind::None, Name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, /*Throws=*/false, + /*GenericParams=*/nullptr, paramList, ResType, DC); FD->setAccess(AccessLevel::Public); return FD; } @@ -214,17 +208,11 @@ getBuiltinGenericFunction(Identifier Id, auto *paramList = ParameterList::create(Context, params); DeclName Name(Context, Id, paramList); - auto func = FuncDecl::create(Context, /*StaticLoc=*/SourceLoc(), - StaticSpellingKind::None, - /*FuncLoc=*/SourceLoc(), - Name, /*NameLoc=*/SourceLoc(), - /*Async-*/false, /*AsyncLoc=*/SourceLoc(), - /*Throws=*/ Rethrows, /*ThrowsLoc=*/SourceLoc(), - GenericParams, - paramList, - TypeLoc::withoutLoc(ResType), DC); - - func->setImplicit(); + auto *const func = FuncDecl::createImplicit( + Context, StaticSpellingKind::None, Name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/Rethrows, GenericParams, paramList, ResType, DC); + func->setAccess(AccessLevel::Public); func->setGenericSignature(Sig); if (Rethrows) @@ -1759,12 +1747,12 @@ Type IntrinsicTypeDecoder::decodeImmediate() { IITDescriptor D = Table.front(); Table = Table.slice(1); switch (D.Kind) { + case IITDescriptor::BFloat: case IITDescriptor::MMX: case IITDescriptor::Metadata: case IITDescriptor::ExtendArgument: case IITDescriptor::TruncArgument: case IITDescriptor::HalfVecArgument: - case IITDescriptor::ScalableVecArgument: case IITDescriptor::VarArg: case IITDescriptor::Token: case IITDescriptor::VecElementArgument: @@ -1793,7 +1781,7 @@ Type IntrinsicTypeDecoder::decodeImmediate() { case IITDescriptor::Vector: { Type eltType = decodeImmediate(); if (!eltType) return Type(); - return makeVector(eltType, D.Vector_Width); + return makeVector(eltType, D.Vector_Width.Min); } // A pointer to an immediate type. diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 71a1cfa05c1ea..62993edae03ea 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -57,7 +57,6 @@ add_swift_host_library(swiftAST STATIC IndexSubset.cpp InlinableText.cpp LayoutConstraint.cpp - LocalizationFormat.cpp Module.cpp ModuleDependencies.cpp ModuleLoader.cpp diff --git a/lib/AST/ClangTypeConverter.cpp b/lib/AST/ClangTypeConverter.cpp index d4ccea512f069..9fd13f797798d 100644 --- a/lib/AST/ClangTypeConverter.cpp +++ b/lib/AST/ClangTypeConverter.cpp @@ -158,6 +158,57 @@ const clang::Type *ClangTypeConverter::getFunctionType( llvm_unreachable("invalid representation"); } +const clang::Type *ClangTypeConverter::getFunctionType( + ArrayRef params, Optional result, + SILFunctionType::Representation repr) { + + // Using the interface type is sufficient as type parameters get mapped to + // `id`, since ObjC lightweight generics use type erasure. (See also: SE-0057) + auto resultClangTy = result.hasValue() + ? convert(result.getValue().getInterfaceType()) + : ClangASTContext.VoidTy; + + if (resultClangTy.isNull()) + return nullptr; + + SmallVector extParamInfos; + SmallVector paramsClangTy; + bool someParamIsConsumed = false; + for (auto &p : params) { + auto pc = convert(p.getInterfaceType()); + if (pc.isNull()) + return nullptr; + clang::FunctionProtoType::ExtParameterInfo extParamInfo; + if (p.isConsumed()) { + someParamIsConsumed = true; + extParamInfo = extParamInfo.withIsConsumed(true); + } + extParamInfos.push_back(extParamInfo); + paramsClangTy.push_back(pc); + } + + clang::FunctionProtoType::ExtProtoInfo info(clang::CallingConv::CC_C); + if (someParamIsConsumed) + info.ExtParameterInfos = extParamInfos.begin(); + auto fn = ClangASTContext.getFunctionType(resultClangTy, paramsClangTy, info); + if (fn.isNull()) + return nullptr; + + switch (repr) { + case SILFunctionType::Representation::CFunctionPointer: + return ClangASTContext.getPointerType(fn).getTypePtr(); + case SILFunctionType::Representation::Block: + return ClangASTContext.getBlockPointerType(fn).getTypePtr(); + case SILFunctionType::Representation::Thick: + case SILFunctionType::Representation::Thin: + case SILFunctionType::Representation::Method: + case SILFunctionType::Representation::ObjCMethod: + case SILFunctionType::Representation::WitnessMethod: + case SILFunctionType::Representation::Closure: + llvm_unreachable("Expected a C-compatible representation."); + } +} + clang::QualType ClangTypeConverter::convertMemberType(NominalTypeDecl *DC, StringRef memberName) { auto memberTypeDecl = cast( @@ -576,12 +627,19 @@ clang::QualType ClangTypeConverter::visitFunctionType(FunctionType *type) { } clang::QualType ClangTypeConverter::visitSILFunctionType(SILFunctionType *type) { - llvm::report_fatal_error("Expected only AST types but found a SIL function."); + // We must've already computed it before if applicable. + return clang::QualType(type->getClangTypeInfo().getType(), 0); } clang::QualType ClangTypeConverter::visitSILBlockStorageType(SILBlockStorageType *type) { - llvm::report_fatal_error("Expected only AST types but found a SIL block."); + // We'll select (void)(^)(). This isn't correct for all blocks, but block + // storage type should only be converted for function signature lowering, + // where the parameter types do not matter. + auto &clangCtx = ClangASTContext; + auto fnTy = clangCtx.getFunctionNoProtoType(clangCtx.VoidTy); + auto blockTy = clangCtx.getBlockPointerType(fnTy); + return clangCtx.getCanonicalType(blockTy); } clang::QualType diff --git a/lib/AST/ClangTypeConverter.h b/lib/AST/ClangTypeConverter.h index 450b9e30cf19a..e41a824163312 100644 --- a/lib/AST/ClangTypeConverter.h +++ b/lib/AST/ClangTypeConverter.h @@ -74,6 +74,11 @@ class ClangTypeConverter : ArrayRef params, Type resultTy, AnyFunctionType::Representation repr); + /// Compute the C function type for a SIL function type. + const clang::Type *getFunctionType( + ArrayRef params, Optional result, + SILFunctionType::Representation repr); + /// Check whether the given Clang declaration is an export of a Swift /// declaration introduced by this converter, and if so, return the original /// Swift declaration. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 0b0816acd18b0..60f13ba3d9fd9 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -24,6 +24,7 @@ #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" @@ -59,6 +60,7 @@ #include "swift/Demangling/ManglingMacros.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/Module.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" @@ -116,6 +118,17 @@ const clang::Module *ClangNode::getClangModule() const { return nullptr; } +void ClangNode::dump() const { + if (auto D = getAsDecl()) + D->dump(); + else if (auto M = getAsMacro()) + M->dump(); + else if (auto M = getAsModule()) + M->dump(); + else + llvm::errs() << "ClangNode contains nullptr\n"; +} + // Only allow allocation of Decls using the allocator in ASTContext. void *Decl::operator new(size_t Bytes, const ASTContext &C, unsigned Alignment) { @@ -2759,9 +2772,9 @@ OpaqueReturnTypeRepr *ValueDecl::getOpaqueResultTypeRepr() const { returnRepr = VD->getTypeReprOrParentPatternTypeRepr(); } } else if (auto *FD = dyn_cast(this)) { - returnRepr = FD->getBodyResultTypeLoc().getTypeRepr(); + returnRepr = FD->getResultTypeRepr(); } else if (auto *SD = dyn_cast(this)) { - returnRepr = SD->getElementTypeLoc().getTypeRepr(); + returnRepr = SD->getElementTypeRepr(); } return dyn_cast_or_null(returnRepr); @@ -4170,13 +4183,6 @@ DestructorDecl *ClassDecl::getDestructor() const { nullptr); } -ArrayRef ClassDecl::getEmittedMembers() const { - ASTContext &ctx = getASTContext(); - return evaluateOrDefault(ctx.evaluator, - EmittedMembersRequest{const_cast(this)}, - ArrayRef()); -} - /// Synthesizer callback for an empty implicit function body. static std::pair synthesizeEmptyFunctionBody(AbstractFunctionDecl *afd, void *context) { @@ -5904,8 +5910,8 @@ VarDecl::getPropertyWrapperSynthesizedPropertyKind() const { PropertyWrapperSynthesizedPropertyKind::Backing)) return PropertyWrapperSynthesizedPropertyKind::Backing; if (getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) - return PropertyWrapperSynthesizedPropertyKind::StorageWrapper; + PropertyWrapperSynthesizedPropertyKind::Projection)) + return PropertyWrapperSynthesizedPropertyKind::Projection; return None; } @@ -5913,8 +5919,8 @@ VarDecl *VarDecl::getPropertyWrapperBackingProperty() const { return getPropertyWrapperBackingPropertyInfo().backingVar; } -VarDecl *VarDecl::getPropertyWrapperStorageWrapper() const { - return getPropertyWrapperBackingPropertyInfo().storageWrapperVar; +VarDecl *VarDecl::getPropertyWrapperProjectionVar() const { + return getPropertyWrapperBackingPropertyInfo().projectionVar; } VarDecl *VarDecl::getLazyStorageProperty() const { @@ -6584,6 +6590,57 @@ ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind() const { return ObjCSubscriptKind::Keyed; } +void SubscriptDecl::setElementInterfaceType(Type type) { + getASTContext().evaluator.cacheOutput(ResultTypeRequest{this}, + std::move(type)); +} + +SubscriptDecl * +SubscriptDecl::createDeserialized(ASTContext &Context, DeclName Name, + StaticSpellingKind StaticSpelling, + Type ElementTy, DeclContext *Parent, + GenericParamList *GenericParams) { + assert(ElementTy && "Deserialized element type must not be null"); + auto *const SD = new (Context) + SubscriptDecl(Name, SourceLoc(), StaticSpelling, SourceLoc(), nullptr, + SourceLoc(), /*ElementTyR=*/nullptr, Parent, GenericParams); + SD->setElementInterfaceType(ElementTy); + return SD; +} + +SubscriptDecl *SubscriptDecl::create(ASTContext &Context, DeclName Name, + SourceLoc StaticLoc, + StaticSpellingKind StaticSpelling, + SourceLoc SubscriptLoc, + ParameterList *Indices, SourceLoc ArrowLoc, + TypeRepr *ElementTyR, DeclContext *Parent, + GenericParamList *GenericParams) { + assert(ElementTyR); + auto *const SD = new (Context) + SubscriptDecl(Name, StaticLoc, StaticSpelling, SubscriptLoc, Indices, + ArrowLoc, ElementTyR, Parent, GenericParams); + return SD; +} + +SubscriptDecl *SubscriptDecl::createImported(ASTContext &Context, DeclName Name, + SourceLoc SubscriptLoc, + ParameterList *Indices, + SourceLoc ArrowLoc, Type ElementTy, + DeclContext *Parent, + ClangNode ClangN) { + assert(ClangN && ElementTy); + auto *DeclPtr = allocateMemoryForDecl( + Context, sizeof(SubscriptDecl), /*includeSpaceForClangNode=*/true); + + auto *const SD = ::new (DeclPtr) + SubscriptDecl(Name, SourceLoc(), StaticSpellingKind::None, SubscriptLoc, + Indices, ArrowLoc, /*ElementTyR=*/nullptr, Parent, + /*GenericParams=*/nullptr); + SD->setElementInterfaceType(ElementTy); + SD->setClangNode(ClangN); + return SD; +} + SourceRange SubscriptDecl::getSourceRange() const { return {getSubscriptLoc(), getEndLoc()}; } @@ -6691,6 +6748,17 @@ bool AbstractFunctionDecl::argumentNameIsAPIByDefault() const { return false; } +bool AbstractFunctionDecl::isAsyncHandler() const { + auto func = dyn_cast(this); + if (!func) + return false; + + auto mutableFunc = const_cast(func); + return evaluateOrDefault(getASTContext().evaluator, + IsAsyncHandlerRequest{mutableFunc}, + false); +} + BraceStmt *AbstractFunctionDecl::getBody(bool canSynthesize) const { if ((getBodyKind() == BodyKind::Synthesize || getBodyKind() == BodyKind::Unparsed) && @@ -6726,6 +6794,20 @@ void AbstractFunctionDecl::setBody(BraceStmt *S, BodyKind NewBodyKind) { } } +void AbstractFunctionDecl::setBodyToBeReparsed(SourceRange bodyRange) { + assert(bodyRange.isValid()); + assert(getBodyKind() == BodyKind::Unparsed || + getBodyKind() == BodyKind::Parsed || + getBodyKind() == BodyKind::TypeChecked); + assert(getASTContext().SourceMgr.rangeContainsTokenLoc( + bodyRange, getASTContext().SourceMgr.getCodeCompletionLoc()) && + "This function is only intended to be used for code completion"); + + keepOriginalBodySourceRange(); + BodyRange = bodyRange; + setBodyKind(BodyKind::Unparsed); +} + SourceRange AbstractFunctionDecl::getBodySourceRange() const { switch (getBodyKind()) { case BodyKind::None: @@ -6829,10 +6911,13 @@ AbstractFunctionDecl::getObjCSelector(DeclName preferredName, } // The number of selector pieces we'll have. + Optional asyncConvention + = getForeignAsyncConvention(); Optional errorConvention = getForeignErrorConvention(); unsigned numSelectorPieces - = argNames.size() + (errorConvention.hasValue() ? 1 : 0); + = argNames.size() + (asyncConvention.hasValue() ? 1 : 0) + + (errorConvention.hasValue() ? 1 : 0); // If we have no arguments, it's a nullary selector. if (numSelectorPieces == 0) { @@ -6851,6 +6936,14 @@ AbstractFunctionDecl::getObjCSelector(DeclName preferredName, unsigned argIndex = 0; for (unsigned piece = 0; piece != numSelectorPieces; ++piece) { if (piece > 0) { + // If we have an async convention that inserts a completion handler + // parameter here, add "completionHandler". + if (asyncConvention && + piece == asyncConvention->completionHandlerParamIndex()) { + selectorPieces.push_back(ctx.getIdentifier("completionHandler")); + continue; + } + // If we have an error convention that inserts an error parameter // here, add "error". if (errorConvention && @@ -6864,12 +6957,21 @@ AbstractFunctionDecl::getObjCSelector(DeclName preferredName, continue; } - // For the first selector piece, attach either the first parameter - // or "AndReturnError" to the base name, if appropriate. + // For the first selector piece, attach either the first parameter, + // "withCompletionHandker", or "AndReturnError" to the base name, + // if appropriate. auto firstPiece = baseName; llvm::SmallString<32> scratch; scratch += firstPiece.str(); - if (errorConvention && piece == errorConvention->getErrorParameterIndex()) { + if (asyncConvention && + piece == asyncConvention->completionHandlerParamIndex()) { + // The completion handler is first; append "WithCompletionHandler". + camel_case::appendSentenceCase(scratch, "WithCompletionHandler"); + + firstPiece = ctx.getIdentifier(scratch); + didStringManipulation = true; + } else if (errorConvention && + piece == errorConvention->getErrorParameterIndex()) { // The error is first; append "AndReturnError". camel_case::appendSentenceCase(scratch, "AndReturnError"); @@ -7088,6 +7190,11 @@ void AbstractFunctionDecl::addDerivativeFunctionConfiguration( DerivativeFunctionConfigs->insert(config); } +void FuncDecl::setResultInterfaceType(Type type) { + getASTContext().evaluator.cacheOutput(ResultTypeRequest{this}, + std::move(type)); +} + FuncDecl *FuncDecl::createImpl(ASTContext &Context, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, @@ -7117,39 +7224,66 @@ FuncDecl *FuncDecl::createImpl(ASTContext &Context, } FuncDecl *FuncDecl::createDeserialized(ASTContext &Context, - SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, - SourceLoc FuncLoc, - DeclName Name, SourceLoc NameLoc, - bool Async, SourceLoc AsyncLoc, - bool Throws, SourceLoc ThrowsLoc, + DeclName Name, bool Async, bool Throws, GenericParamList *GenericParams, - DeclContext *Parent) { - return createImpl(Context, StaticLoc, StaticSpelling, FuncLoc, - Name, NameLoc, Async, AsyncLoc, Throws, ThrowsLoc, - GenericParams, Parent, - ClangNode()); + Type FnRetType, DeclContext *Parent) { + assert(FnRetType && "Deserialized result type must not be null"); + auto *const FD = + FuncDecl::createImpl(Context, SourceLoc(), StaticSpelling, SourceLoc(), + Name, SourceLoc(), Async, SourceLoc(), Throws, + SourceLoc(), GenericParams, Parent, ClangNode()); + FD->setResultInterfaceType(FnRetType); + return FD; } FuncDecl *FuncDecl::create(ASTContext &Context, SourceLoc StaticLoc, - StaticSpellingKind StaticSpelling, - SourceLoc FuncLoc, - DeclName Name, SourceLoc NameLoc, - bool Async, SourceLoc AsyncLoc, - bool Throws, SourceLoc ThrowsLoc, + StaticSpellingKind StaticSpelling, SourceLoc FuncLoc, + DeclName Name, SourceLoc NameLoc, bool Async, + SourceLoc AsyncLoc, bool Throws, SourceLoc ThrowsLoc, GenericParamList *GenericParams, - ParameterList *BodyParams, - TypeLoc FnRetType, DeclContext *Parent, - ClangNode ClangN) { - auto *FD = FuncDecl::createImpl( - Context, StaticLoc, StaticSpelling, FuncLoc, - Name, NameLoc, Async, AsyncLoc, Throws, ThrowsLoc, - GenericParams, Parent, ClangN); + ParameterList *BodyParams, TypeRepr *ResultTyR, + DeclContext *Parent) { + auto *const FD = FuncDecl::createImpl( + Context, StaticLoc, StaticSpelling, FuncLoc, Name, NameLoc, Async, + AsyncLoc, Throws, ThrowsLoc, GenericParams, Parent, ClangNode()); FD->setParameters(BodyParams); - FD->getBodyResultTypeLoc() = FnRetType; + FD->FnRetType = TypeLoc(ResultTyR); return FD; } - + +FuncDecl *FuncDecl::createImplicit(ASTContext &Context, + StaticSpellingKind StaticSpelling, + DeclName Name, SourceLoc NameLoc, bool Async, + bool Throws, GenericParamList *GenericParams, + ParameterList *BodyParams, Type FnRetType, + DeclContext *Parent) { + assert(FnRetType); + auto *const FD = FuncDecl::createImpl( + Context, SourceLoc(), StaticSpelling, SourceLoc(), Name, NameLoc, Async, + SourceLoc(), Throws, SourceLoc(), GenericParams, Parent, ClangNode()); + FD->setImplicit(); + FD->setParameters(BodyParams); + FD->setResultInterfaceType(FnRetType); + return FD; +} + +FuncDecl *FuncDecl::createImported(ASTContext &Context, SourceLoc FuncLoc, + DeclName Name, SourceLoc NameLoc, + bool Async, bool Throws, + ParameterList *BodyParams, + Type FnRetType, DeclContext *Parent, + ClangNode ClangN) { + assert(ClangN && FnRetType); + auto *const FD = FuncDecl::createImpl( + Context, SourceLoc(), StaticSpellingKind::None, FuncLoc, Name, NameLoc, + Async, SourceLoc(), Throws, SourceLoc(), + /*GenericParams=*/nullptr, Parent, ClangN); + FD->setParameters(BodyParams); + FD->setResultInterfaceType(FnRetType); + return FD; +} + OperatorDecl *FuncDecl::getOperatorDecl() const { // Fast-path: Most functions are not operators. if (!isOperator()) { @@ -7198,20 +7332,18 @@ AccessorDecl *AccessorDecl::createImpl(ASTContext &ctx, return D; } -AccessorDecl *AccessorDecl::createDeserialized(ASTContext &ctx, - SourceLoc declLoc, - SourceLoc accessorKeywordLoc, - AccessorKind accessorKind, - AbstractStorageDecl *storage, - SourceLoc staticLoc, - StaticSpellingKind staticSpelling, - bool throws, SourceLoc throwsLoc, - GenericParamList *genericParams, - DeclContext *parent) { - return createImpl(ctx, declLoc, accessorKeywordLoc, accessorKind, - storage, staticLoc, staticSpelling, - throws, throwsLoc, genericParams, parent, - ClangNode()); +AccessorDecl * +AccessorDecl::createDeserialized(ASTContext &ctx, AccessorKind accessorKind, + AbstractStorageDecl *storage, + StaticSpellingKind staticSpelling, + bool throws, GenericParamList *genericParams, + Type fnRetType, DeclContext *parent) { + assert(fnRetType && "Deserialized result type must not be null"); + auto *const D = AccessorDecl::createImpl( + ctx, SourceLoc(), SourceLoc(), accessorKind, storage, SourceLoc(), + staticSpelling, throws, SourceLoc(), genericParams, parent, ClangNode()); + D->setResultInterfaceType(fnRetType); + return D; } AccessorDecl *AccessorDecl::create(ASTContext &ctx, @@ -7224,7 +7356,7 @@ AccessorDecl *AccessorDecl::create(ASTContext &ctx, bool throws, SourceLoc throwsLoc, GenericParamList *genericParams, ParameterList * bodyParams, - TypeLoc fnRetType, + Type fnRetType, DeclContext *parent, ClangNode clangNode) { auto *D = AccessorDecl::createImpl( @@ -7232,7 +7364,7 @@ AccessorDecl *AccessorDecl::create(ASTContext &ctx, staticLoc, staticSpelling, throws, throwsLoc, genericParams, parent, clangNode); D->setParameters(bodyParams); - D->getBodyResultTypeLoc() = fnRetType; + D->setResultInterfaceType(fnRetType); return D; } @@ -7386,7 +7518,7 @@ SourceRange FuncDecl::getSourceRange() const { getBodyKind() == BodyKind::Skipped) return { StartLoc, BodyRange.End }; - SourceLoc RBraceLoc = getBodySourceRange().End; + SourceLoc RBraceLoc = getOriginalBodySourceRange().End; if (RBraceLoc.isValid()) { return { StartLoc, RBraceLoc }; } @@ -7401,9 +7533,9 @@ SourceRange FuncDecl::getSourceRange() const { if (TrailingWhereClauseSourceRange.isValid()) return { StartLoc, TrailingWhereClauseSourceRange.End }; - if (getBodyResultTypeLoc().hasLocation() && - getBodyResultTypeLoc().getSourceRange().End.isValid()) - return { StartLoc, getBodyResultTypeLoc().getSourceRange().End }; + const auto ResultTyEndLoc = getResultTypeSourceRange().End; + if (ResultTyEndLoc.isValid()) + return { StartLoc, ResultTyEndLoc }; if (hasThrows()) return { StartLoc, getThrowsLoc() }; @@ -7507,7 +7639,7 @@ SourceRange ConstructorDecl::getSourceRange() const { if (isImplicit()) return getConstructorLoc(); - SourceLoc End = getBodySourceRange().End; + SourceLoc End = getOriginalBodySourceRange().End; if (End.isInvalid()) End = getGenericTrailingWhereClauseSourceRange().End; if (End.isInvalid()) @@ -7733,7 +7865,7 @@ ConstructorDecl::getDelegatingOrChainedInitKind(DiagnosticEngine *diags, } SourceRange DestructorDecl::getSourceRange() const { - SourceLoc End = getBodySourceRange().End; + SourceLoc End = getOriginalBodySourceRange().End; if (End.isInvalid()) { End = getDestructorLoc(); } @@ -7909,7 +8041,7 @@ void Decl::setClangNode(ClangNode Node) { // dependency. struct DeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const Decl *D = static_cast(Entity); @@ -7922,7 +8054,7 @@ struct DeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter { } } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const Decl *D = static_cast(Entity); diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 5f7733df66c2b..f1cc0b4722107 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -793,6 +793,23 @@ DeclRange IterableDeclContext::getMembers() const { return getCurrentMembersWithoutLoading(); } +ArrayRef IterableDeclContext::getParsedMembers() const { + ASTContext &ctx = getASTContext(); + auto mutableThis = const_cast(this); + return evaluateOrDefault( + ctx.evaluator, ParseMembersRequest{mutableThis}, + FingerprintAndMembers()) + .members; +} + +ArrayRef IterableDeclContext::getSemanticMembers() const { + ASTContext &ctx = getASTContext(); + return evaluateOrDefault( + ctx.evaluator, + SemanticMembersRequest{const_cast(this)}, + ArrayRef()); +} + /// Add a member to this context. void IterableDeclContext::addMember(Decl *member, Decl *Hint) { // Add the member to the list of declarations without notification. @@ -891,10 +908,7 @@ void IterableDeclContext::loadAllMembers() const { // members to this context, this call is important for recording the // dependency edge. auto mutableThis = const_cast(this); - auto members = - evaluateOrDefault(ctx.evaluator, ParseMembersRequest{mutableThis}, - FingerprintAndMembers()) - .members; + auto members = getParsedMembers(); // If we haven't already done so, add these members to this context. if (!AddedParsedMembers) { diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 9e0094d02b279..f7b9368589bfa 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -20,7 +20,6 @@ #include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticSuppression.h" -#include "swift/AST/LocalizationFormat.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" #include "swift/AST/PrintOptions.h" @@ -28,6 +27,7 @@ #include "swift/AST/TypeRepr.h" #include "swift/Basic/SourceManager.h" #include "swift/Config.h" +#include "swift/Localization/LocalizationFormat.h" #include "swift/Parse/Lexer.h" // bad dependency #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" @@ -1010,8 +1010,9 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { emitDiagnostic(childNote); } -const char *DiagnosticEngine::diagnosticStringFor(const DiagID id, - bool printDiagnosticName) { +llvm::StringRef +DiagnosticEngine::diagnosticStringFor(const DiagID id, + bool printDiagnosticName) { // TODO: Print diagnostic names from `localization`. if (printDiagnosticName) { return debugDiagnosticStrings[(unsigned)id]; @@ -1020,7 +1021,7 @@ const char *DiagnosticEngine::diagnosticStringFor(const DiagID id, if (localization) { auto localizedMessage = localization.get()->getMessageOr(id, defaultMessage); - return localizedMessage.data(); + return localizedMessage; } return defaultMessage; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 59cdfa8ab7cb7..bcbd89fc32497 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -126,7 +126,7 @@ namespace { } // end anonymous namespace void Expr::setType(Type T) { - assert(!T || !T->hasTypeVariable()); + assert(!T || !T->hasTypeVariable() || !T->hasHole()); Ty = T; } @@ -288,6 +288,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const { return cast(this) ->getSubExpr()->getReferencedDecl(stopAtParenExpr); + PASS_THROUGH_REFERENCE(UnresolvedMemberChainResult, getSubExpr); PASS_THROUGH_REFERENCE(DotSelf, getSubExpr); PASS_THROUGH_REFERENCE(Await, getSubExpr); PASS_THROUGH_REFERENCE(Try, getSubExpr); @@ -606,6 +607,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const { case ExprKind::Paren: case ExprKind::DotSelf: + case ExprKind::UnresolvedMemberChainResult: case ExprKind::Tuple: case ExprKind::Array: case ExprKind::Dictionary: @@ -831,16 +833,15 @@ APInt BuiltinIntegerWidth::parse(StringRef text, unsigned radix, bool negate, static APFloat getFloatLiteralValue(bool IsNegative, StringRef Text, const llvm::fltSemantics &Semantics) { APFloat Val(Semantics); - llvm::Expected MaybeRes = - Val.convertFromString(Text, llvm::APFloat::rmNearestTiesToEven); - assert(MaybeRes && *MaybeRes != APFloat::opInvalidOp && - "Sema didn't reject invalid number"); - (void)MaybeRes; + auto Res = + Val.convertFromString(Text, llvm::APFloat::rmNearestTiesToEven); + assert(Res && "Sema didn't reject invalid number"); + consumeError(Res.takeError()); if (IsNegative) { auto NegVal = APFloat::getZero(Semantics, /*negative*/ true); - auto Res = NegVal.subtract(Val, llvm::APFloat::rmNearestTiesToEven); - assert(Res != APFloat::opInvalidOp && "Sema didn't reject invalid number"); - (void)Res; + Res = NegVal.subtract(Val, llvm::APFloat::rmNearestTiesToEven); + assert(Res && "Sema didn't reject invalid number"); + consumeError(Res.takeError()); return NegVal; } return Val; @@ -1606,61 +1607,6 @@ DynamicSubscriptExpr::create(ASTContext &ctx, Expr *base, Expr *index, hasTrailingClosure, decl, implicit); } -UnresolvedMemberExpr::UnresolvedMemberExpr(SourceLoc dotLoc, - DeclNameLoc nameLoc, - DeclNameRef name, Expr *argument, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, - bool implicit) - : Expr(ExprKind::UnresolvedMember, implicit), - DotLoc(dotLoc), NameLoc(nameLoc), Name(name), Argument(argument) { - Bits.UnresolvedMemberExpr.HasArguments = (argument != nullptr); - Bits.UnresolvedMemberExpr.NumArgLabels = argLabels.size(); - Bits.UnresolvedMemberExpr.HasArgLabelLocs = !argLabelLocs.empty(); - Bits.UnresolvedMemberExpr.HasTrailingClosure = hasTrailingClosure; - initializeCallArguments(argLabels, argLabelLocs); -} - -UnresolvedMemberExpr *UnresolvedMemberExpr::create(ASTContext &ctx, - SourceLoc dotLoc, - DeclNameLoc nameLoc, - DeclNameRef name, - bool implicit) { - size_t size = totalSizeToAlloc({ }, { }); - - void *memory = ctx.Allocate(size, alignof(UnresolvedMemberExpr)); - return new (memory) UnresolvedMemberExpr(dotLoc, nameLoc, name, nullptr, - { }, { }, - /*hasTrailingClosure=*/false, - implicit); -} - -UnresolvedMemberExpr * -UnresolvedMemberExpr::create(ASTContext &ctx, SourceLoc dotLoc, - DeclNameLoc nameLoc, DeclNameRef name, - SourceLoc lParenLoc, - ArrayRef args, - ArrayRef argLabels, - ArrayRef argLabelLocs, - SourceLoc rParenLoc, - ArrayRef trailingClosures, - bool implicit) { - SmallVector argLabelsScratch; - SmallVector argLabelLocsScratch; - Expr *arg = packSingleArgument(ctx, lParenLoc, args, argLabels, argLabelLocs, - rParenLoc, trailingClosures, implicit, - argLabelsScratch, argLabelLocsScratch); - - size_t size = totalSizeToAlloc(argLabels, argLabelLocs); - - void *memory = ctx.Allocate(size, alignof(UnresolvedMemberExpr)); - return new (memory) UnresolvedMemberExpr(dotLoc, nameLoc, name, arg, - argLabels, argLabelLocs, - trailingClosures.size() == 1, - implicit); -} - ArrayRef ApplyExpr::getArgumentLabels( SmallVectorImpl &scratch) const { // Unary operators and 'self' applications have a single, unlabeled argument. @@ -2001,7 +1947,7 @@ bool ClosureExpr::capturesSelfEnablingImplictSelf() const { } void ClosureExpr::setExplicitResultType(Type ty) { - assert(ty && !ty->hasTypeVariable()); + assert(ty && !ty->hasTypeVariable() && !ty->hasHole()); ExplicitResultTypeAndBodyState.getPointer() ->setType(MetatypeType::get(ty)); } @@ -2470,14 +2416,14 @@ SourceLoc swift::extractNearestSourceLoc(const DefaultArgumentExpr *expr) { // dependency. struct ExprTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const Expr *E = static_cast(Entity); OS << Expr::getKindName(E->getKind()); } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const Expr *E = static_cast(Entity); diff --git a/lib/AST/ExtInfo.cpp b/lib/AST/ExtInfo.cpp index a75a3ff1d9f5e..aba9bb2577ce0 100644 --- a/lib/AST/ExtInfo.cpp +++ b/lib/AST/ExtInfo.cpp @@ -19,6 +19,18 @@ #include "clang/AST/Type.h" +static void assertIsFunctionType(const clang::Type *type) { +#ifndef NDEBUG + if (!(type->isFunctionPointerType() || type->isBlockPointerType() || + type->isFunctionReferenceType())) { + llvm::errs() << "Expected a Clang function type wrapped in a pointer type " + << "or a block pointer type but found:\n"; + type->dump(); + llvm_unreachable("\nUnexpected Clang type when creating ExtInfo!"); + } +#endif +} + namespace swift { // MARK: - ClangTypeInfo @@ -43,9 +55,10 @@ void ClangTypeInfo::printType(ClangModuleLoader *cml, cml->printClangType(type, os); } -void ClangTypeInfo::dump(llvm::raw_ostream &os) const { +void ClangTypeInfo::dump(llvm::raw_ostream &os, + const clang::ASTContext &ctx) const { if (type) { - type->dump(os); + type->dump(os, ctx); } else { os << ""; } @@ -53,23 +66,12 @@ void ClangTypeInfo::dump(llvm::raw_ostream &os) const { // MARK: - ASTExtInfoBuilder -void ASTExtInfoBuilder::assertIsFunctionType(const clang::Type *type) { -#ifndef NDEBUG - if (!(type->isFunctionPointerType() || type->isBlockPointerType() || - type->isFunctionReferenceType())) { - SmallString<256> buf; - llvm::raw_svector_ostream os(buf); - os << "Expected a Clang function type wrapped in a pointer type or " - << "a block pointer type but found:\n"; - type->dump(os); - llvm_unreachable(os.str().data()); - } -#endif - return; -} - void ASTExtInfoBuilder::checkInvariants() const { - // TODO: Add validation checks here while making sure things don't blow up. + // TODO: [clang-function-type-serialization] Once we start serializing + // the Clang type, we should also assert that the pointer is non-null. + auto Rep = Representation(bits & RepresentationMask); + if ((Rep == Representation::CFunctionPointer) && clangTypeInfo.type) + assertIsFunctionType(clangTypeInfo.type); } // MARK: - ASTExtInfo diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp index a5033e16c4c29..8b29c9c85d1ef 100644 --- a/lib/AST/GenericEnvironment.cpp +++ b/lib/AST/GenericEnvironment.cpp @@ -171,27 +171,6 @@ Type GenericEnvironment::mapTypeIntoContext(GenericTypeParamType *type) const { return result; } -GenericTypeParamType *GenericEnvironment::getSugaredType( - GenericTypeParamType *type) const { - for (auto *sugaredType : getGenericParams()) - if (sugaredType->isEqual(type)) - return sugaredType; - - llvm_unreachable("missing generic parameter"); -} - -Type GenericEnvironment::getSugaredType(Type type) const { - if (!type->hasTypeParameter()) - return type; - - return type.transform([this](Type Ty) -> Type { - if (auto GP = dyn_cast(Ty.getPointer())) { - return Type(getSugaredType(GP)); - } - return Ty; - }); -} - SubstitutionMap GenericEnvironment::getForwardingSubstitutionMap() const { auto genericSig = getGenericSignature(); return SubstitutionMap::get(genericSig, diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 9b6befde6a9ea..1f9731635b49f 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -404,16 +404,6 @@ bool GenericSignatureImpl::requiresClass(Type type) const { // If there is a layout constraint, it might be a class. if (equivClass->layout && equivClass->layout->isClass()) return true; - // If there is a superclass bound, then obviously it must be a class. - // FIXME: We shouldn't need this? - if (equivClass->superclass) return true; - - // If any of the protocols are class-bound, then it must be a class. - // FIXME: We shouldn't need this? - for (const auto &conforms : equivClass->conformsTo) { - if (conforms.first->requiresClass()) return true; - } - return false; } @@ -1047,10 +1037,27 @@ SubstitutionMap GenericSignatureImpl::getIdentitySubstitutionMap() const { MakeAbstractConformanceForGenericType()); } +GenericTypeParamType *GenericSignatureImpl::getSugaredType( + GenericTypeParamType *type) const { + unsigned ordinal = getGenericParamOrdinal(type); + return getGenericParams()[ordinal]; +} + +Type GenericSignatureImpl::getSugaredType(Type type) const { + if (!type->hasTypeParameter()) + return type; + + return type.transform([this](Type Ty) -> Type { + if (auto GP = dyn_cast(Ty.getPointer())) { + return Type(getSugaredType(GP)); + } + return Ty; + }); +} + unsigned GenericSignatureImpl::getGenericParamOrdinal( GenericTypeParamType *param) const { - return GenericParamKey(param->getDepth(), param->getIndex()) - .findIndexIn(getGenericParams()); + return GenericParamKey(param).findIndexIn(getGenericParams()); } bool GenericSignatureImpl::hasTypeVariable() const { diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index dc03dc5cc0c61..bff5a8688291d 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -3871,9 +3871,21 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement( return false; }); - // Remaining logic is not relevant in ObjC protocol cases. - if (proto->isObjC()) + if (proto->isObjC()) { + // @objc implies an inferred AnyObject constraint. + auto innerSource = + FloatingRequirementSource::viaProtocolRequirement(source, proto, + /*inferred=*/true); + addLayoutRequirementDirect(selfType, + LayoutConstraint::getLayoutConstraint( + LayoutConstraintKind::Class, + getASTContext()), + innerSource); + return ConstraintResult::Resolved; + } + + // Remaining logic is not relevant in ObjC protocol cases. // Collect all of the inherited associated types and typealiases in the // inherited protocols (recursively). @@ -7418,13 +7430,11 @@ AbstractGenericSignatureRequest::evaluate( if (baseSignature) canBaseSignature = baseSignature->getCanonicalSignature(); - llvm::SmallDenseMap mappedTypeParameters; SmallVector canAddedParameters; canAddedParameters.reserve(addedParameters.size()); for (auto gp : addedParameters) { auto canGP = gp->getCanonicalType()->castTo(); canAddedParameters.push_back(canGP); - mappedTypeParameters[canGP] = Type(gp); } SmallVector canAddedRequirements; @@ -7441,10 +7451,8 @@ AbstractGenericSignatureRequest::evaluate( if (!canSignatureResult || !*canSignatureResult) return GenericSignature(); - // Substitute in the original generic parameters to form a more-sugared - // result closer to what the original request wanted. Note that this - // loses sugar on concrete types, but for abstract signatures that - // shouldn't matter. + // Substitute in the original generic parameters to form the sugared + // result the original request wanted. auto canSignature = *canSignatureResult; SmallVector resugaredParameters; resugaredParameters.reserve(canSignature->getGenericParams().size()); @@ -7462,9 +7470,8 @@ AbstractGenericSignatureRequest::evaluate( auto resugaredReq = req.subst( [&](SubstitutableType *type) { if (auto gp = dyn_cast(type)) { - auto knownGP = mappedTypeParameters.find(gp); - if (knownGP != mappedTypeParameters.end()) - return knownGP->second; + unsigned ordinal = canSignature->getGenericParamOrdinal(gp); + return Type(resugaredParameters[ordinal]); } return Type(type); }, diff --git a/lib/AST/InlinableText.cpp b/lib/AST/InlinableText.cpp index 7a805d94add6d..c21a0b10e217c 100644 --- a/lib/AST/InlinableText.cpp +++ b/lib/AST/InlinableText.cpp @@ -78,7 +78,7 @@ struct ExtractInactiveRanges : public ASTWalker { ranges.push_back(charRange); } - bool walkToDeclPre(Decl *d) { + bool walkToDeclPre(Decl *d) override { auto icd = dyn_cast(d); if (!icd) return true; diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 6749fdc8b8802..69075ff7a08d9 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -312,6 +312,7 @@ SourceLookupCache::SourceLookupCache(const SourceFile &SF) { FrontendStatsTracer tracer(SF.getASTContext().Stats, "source-file-populate-cache"); addToUnqualifiedLookupCache(SF.getTopLevelDecls(), false); + addToUnqualifiedLookupCache(SF.getHoistedDecls(), false); } SourceLookupCache::SourceLookupCache(const ModuleDecl &M) { @@ -322,8 +323,9 @@ SourceLookupCache::SourceLookupCache(const ModuleDecl &M) { addToUnqualifiedLookupCache(SFU->getTopLevelDecls(), false); continue; } - auto &SF = *cast(file); - addToUnqualifiedLookupCache(SF.getTopLevelDecls(), false); + auto *SF = cast(file); + addToUnqualifiedLookupCache(SF->getTopLevelDecls(), false); + addToUnqualifiedLookupCache(SF->getHoistedDecls(), false); } } @@ -1994,6 +1996,27 @@ bool SourceFile::isImportedImplementationOnly(const ModuleDecl *module) const { return !imports.isImportedBy(module, getParentModule()); } +bool ModuleDecl::isImportedImplementationOnly(const ModuleDecl *module) const { + auto &imports = getASTContext().getImportCache(); + + // Look through non-implementation-only imports to see if module is imported + // in some other way. Otherwise we assume it's implementation-only imported. + ModuleDecl::ImportFilter filter = { + ModuleDecl::ImportFilterKind::Public, + ModuleDecl::ImportFilterKind::Private, + ModuleDecl::ImportFilterKind::SPIAccessControl, + ModuleDecl::ImportFilterKind::ShadowedBySeparateOverlay}; + SmallVector results; + getImportedModules(results, filter); + + for (auto &desc : results) { + if (imports.isImportedBy(module, desc.importedModule)) + return false; + } + + return true; +} + void SourceFile::lookupImportedSPIGroups( const ModuleDecl *importedModule, llvm::SmallSetVector &spiGroups) const { @@ -2314,6 +2337,12 @@ bool SourceFile::hasDelayedBodyParsing() const { return true; } +/// Add a hoisted declaration. See Decl::isHoisted(). +void SourceFile::addHoistedDecl(Decl *d) { + assert(d->isHoisted()); + Hoisted.push_back(d); +} + ArrayRef SourceFile::getTopLevelDecls() const { auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); @@ -2321,6 +2350,10 @@ ArrayRef SourceFile::getTopLevelDecls() const { {}).TopLevelDecls; } +ArrayRef SourceFile::getHoistedDecls() const { + return Hoisted; +} + bool FileUnit::walk(ASTWalker &walker) { SmallVector Decls; getTopLevelDecls(Decls); @@ -2387,7 +2420,7 @@ StringRef SourceFile::getFilename() const { ASTScope &SourceFile::getScope() { if (!Scope) - Scope = std::unique_ptr(new (getASTContext()) ASTScope(this)); + Scope = new (getASTContext()) ASTScope(this); return *Scope.get(); } @@ -2657,14 +2690,14 @@ const clang::Module* ModuleEntity::getAsClangModule() const { // dependency. struct SourceFileTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const SourceFile *SF = static_cast(Entity); OS << llvm::sys::path::filename(SF->getFilename()); } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { // SourceFiles don't have SourceLocs of their own; they contain them. } }; diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index fdbfb119ebddb..7ef21cadcb205 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -312,6 +312,19 @@ static void recordShadowedDeclsAfterTypeMatch( } } + // If one declaration is in a protocol or extension thereof and the + // other is not, prefer the one that is not. + if ((bool)firstDecl->getDeclContext()->getSelfProtocolDecl() != + (bool)secondDecl->getDeclContext()->getSelfProtocolDecl()) { + if (firstDecl->getDeclContext()->getSelfProtocolDecl()) { + shadowed.insert(firstDecl); + break; + } else { + shadowed.insert(secondDecl); + continue; + } + } + continue; } @@ -2421,6 +2434,53 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator, } } + // If we have more than one attribute declaration, we have an ambiguity. + // So, emit an ambiguity diagnostic. + if (auto typeRepr = attr->getTypeRepr()) { + if (nominals.size() > 1) { + SmallVector ambiguousCandidates; + // Filter out declarations that cannot be attributes. + for (auto decl : nominals) { + if (isa(decl)) { + continue; + } + ambiguousCandidates.push_back(decl); + } + if (ambiguousCandidates.size() > 1) { + auto attrName = nominals.front()->getName(); + ctx.Diags.diagnose(typeRepr->getLoc(), + diag::ambiguous_custom_attribute_ref, attrName); + for (auto candidate : ambiguousCandidates) { + ctx.Diags.diagnose(candidate->getLoc(), + diag::found_attribute_candidate); + // If the candidate is a top-level attribute, let's suggest + // adding module name to resolve the ambiguity. + if (candidate->getDeclContext()->isModuleScopeContext()) { + auto moduleName = candidate->getParentModule()->getName(); + ctx.Diags + .diagnose(typeRepr->getLoc(), + diag::ambiguous_custom_attribute_ref_fix, + moduleName.str(), attrName, moduleName) + .fixItInsert(typeRepr->getLoc(), moduleName.str().str() + "."); + } + } + return nullptr; + } + } + } + + // There is no nominal type with this name, so complain about this being + // an unknown attribute. + std::string typeName; + if (auto typeRepr = attr->getTypeRepr()) { + llvm::raw_string_ostream out(typeName); + typeRepr->print(out); + } else { + typeName = attr->getType().getString(); + } + + ctx.Diags.diagnose(attr->getLocation(), diag::unknown_attribute, typeName); + return nullptr; } diff --git a/lib/AST/Pattern.cpp b/lib/AST/Pattern.cpp index 2006c06e62e27..eed9e33c0341c 100644 --- a/lib/AST/Pattern.cpp +++ b/lib/AST/Pattern.cpp @@ -517,7 +517,7 @@ SourceRange ExprPattern::getSourceRange() const { // dependency. struct PatternTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const Pattern *P = static_cast(Entity); @@ -526,7 +526,7 @@ struct PatternTraceFormatter : public UnifiedStatsReporter::TraceFormatter { } } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const Pattern *P = static_cast(Entity); diff --git a/lib/AST/PrettyStackTrace.cpp b/lib/AST/PrettyStackTrace.cpp index a13caf0683dab..dc07100062991 100644 --- a/lib/AST/PrettyStackTrace.cpp +++ b/lib/AST/PrettyStackTrace.cpp @@ -217,7 +217,7 @@ void PrettyStackTraceClangType::print(llvm::raw_ostream &out) const { out << "NULL clang type!\n"; return; } - TheType->dump(out); + TheType->dump(out, Context); } void PrettyStackTraceTypeRepr::print(llvm::raw_ostream &out) const { diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index d612dff6a0574..5b2ff91752ca6 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -1489,7 +1489,7 @@ ProtocolConformanceRef::getCanonicalConformanceRef() const { struct ProtocolConformanceTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const ProtocolConformance *C = @@ -1497,7 +1497,7 @@ struct ProtocolConformanceTraceFormatter C->printName(OS); } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const ProtocolConformance *C = diff --git a/lib/AST/SILLayout.cpp b/lib/AST/SILLayout.cpp index da70ccd300917..ffbd35175d226 100644 --- a/lib/AST/SILLayout.cpp +++ b/lib/AST/SILLayout.cpp @@ -52,6 +52,8 @@ static void verifyFields(CanGenericSignature Sig, ArrayRef Fields) { && "SILLayout field cannot have an archetype type"); assert(!ty->hasTypeVariable() && "SILLayout cannot contain constraint system type variables"); + assert(!ty->hasHole() && + "SILLayout cannot contain constraint system type holes"); if (!ty->hasTypeParameter()) continue; field.getLoweredType().findIf([Sig](Type t) -> bool { diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 83d24aacaf94a..98541beee21a4 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -524,14 +524,14 @@ SwitchStmt *SwitchStmt::create(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc, // dependency. struct StmtTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const Stmt *S = static_cast(Entity); OS << Stmt::getKindName(S->getKind()); } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const Stmt *S = static_cast(Entity); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 62142eb9ccb27..402a33ab65356 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -76,7 +76,7 @@ Type QuerySubstitutionMap::operator()(SubstitutableType *type) const { } void TypeLoc::setType(Type Ty) { - assert(!Ty || !Ty->hasTypeVariable()); + assert(!Ty || !Ty->hasTypeVariable() || !Ty->hasHole()); this->Ty = Ty; } @@ -153,9 +153,7 @@ bool TypeBase::isAny() { return isEqual(getASTContext().TheAnyType); } -bool TypeBase::isHole() { - return isEqual(getASTContext().TheUnresolvedType); -} +bool TypeBase::isHole() { return getCanonicalType()->is(); } bool TypeBase::isAnyClassReferenceType() { return getCanonicalType().isAnyClassReferenceType(); @@ -221,6 +219,7 @@ bool CanType::isReferenceTypeImpl(CanType type, const GenericSignatureImpl *sig, case TypeKind::LValue: case TypeKind::InOut: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::BoundGenericEnum: case TypeKind::BoundGenericStruct: case TypeKind::SILToken: @@ -1149,6 +1148,7 @@ CanType TypeBase::computeCanonicalType() { case TypeKind::Error: case TypeKind::Unresolved: case TypeKind::TypeVariable: + case TypeKind::Hole: llvm_unreachable("these types are always canonical"); #define SUGARED_TYPE(id, parent) \ @@ -3206,14 +3206,8 @@ PrimaryArchetypeType::getNew(const ASTContext &Ctx, } bool ArchetypeType::requiresClass() const { - if (Bits.ArchetypeType.HasSuperclass) - return true; if (auto layout = getLayoutConstraint()) - if (layout->isClass()) - return true; - for (ProtocolDecl *conformed : getConformsTo()) - if (conformed->requiresClass()) - return true; + return layout->isClass(); return false; } @@ -4250,6 +4244,7 @@ case TypeKind::Id: case TypeKind::Error: case TypeKind::Unresolved: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::GenericTypeParam: case TypeKind::SILToken: case TypeKind::Module: @@ -4952,8 +4947,7 @@ ReferenceCounting TypeBase::getReferenceCounting() { auto archetype = cast(type); auto layout = archetype->getLayoutConstraint(); (void)layout; - assert(archetype->requiresClass() || - (layout && layout->isRefCounted())); + assert(layout && layout->isRefCounted()); if (auto supertype = archetype->getSuperclass()) return supertype->getReferenceCounting(); return ReferenceCounting::Unknown; @@ -4989,6 +4983,7 @@ ReferenceCounting TypeBase::getReferenceCounting() { case TypeKind::LValue: case TypeKind::InOut: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::BoundGenericEnum: case TypeKind::BoundGenericStruct: case TypeKind::SILToken: diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index ff2efbc44ce89..b6bf4130e16f3 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -935,23 +935,28 @@ void ParamSpecifierRequest::cacheResult(ParamSpecifier specifier) const { // ResultTypeRequest computation. //----------------------------------------------------------------------------// -TypeLoc &ResultTypeRequest::getResultTypeLoc() const { - auto *decl = std::get<0>(getStorage()); - if (auto *funcDecl = dyn_cast(decl)) - return funcDecl->getBodyResultTypeLoc(); - auto *subscriptDecl = cast(decl); - return subscriptDecl->getElementTypeLoc(); -} - Optional ResultTypeRequest::getCachedResult() const { - if (auto type = getResultTypeLoc().getType()) - return type; + Type type; + auto *const decl = std::get<0>(getStorage()); + if (const auto *const funcDecl = dyn_cast(decl)) { + type = funcDecl->FnRetType.getType(); + } else { + type = cast(decl)->ElementTy.getType(); + } - return None; + if (type.isNull()) + return None; + + return type; } void ResultTypeRequest::cacheResult(Type type) const { - getResultTypeLoc().setType(type); + auto *const decl = std::get<0>(getStorage()); + if (auto *const funcDecl = dyn_cast(decl)) { + funcDecl->FnRetType.setType(type); + } else { + cast(decl)->ElementTy.setType(type); + } } //----------------------------------------------------------------------------// @@ -1008,6 +1013,7 @@ void InterfaceTypeRequest::cacheResult(Type type) const { auto *decl = std::get<0>(getStorage()); if (type) { assert(!type->hasTypeVariable() && "Type variable in interface type"); + assert(!type->hasHole() && "Type hole in interface type"); assert(!type->is() && "Interface type must be materializable"); assert(!type->hasArchetype() && "Archetype in interface type"); } diff --git a/lib/AST/TypeJoinMeet.cpp b/lib/AST/TypeJoinMeet.cpp index a5609f8b669fb..468cb6810fc1a 100644 --- a/lib/AST/TypeJoinMeet.cpp +++ b/lib/AST/TypeJoinMeet.cpp @@ -87,6 +87,9 @@ struct TypeJoin : CanTypeVisitor { assert(!first->hasTypeVariable() && !second->hasTypeVariable() && "Cannot compute join of types involving type variables"); + assert(!first->hasHole() && !second->hasHole() && + "Cannot compute join of types involving type holes"); + assert(first->getWithoutSpecifierType()->isEqual(first) && "Expected simple type!"); assert(second->getWithoutSpecifierType()->isEqual(second) && diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index 0a28f865f8e88..6490258e3b922 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -171,6 +171,9 @@ void AttributedTypeRepr::printAttrs(ASTPrinter &Printer, Printer.printStructurePost(PrintStructureKind::BuiltinAttribute); Printer << " "; } + + if (hasAttr(TAK_async)) + Printer.printSimpleAttr("@async") << " "; } IdentTypeRepr *IdentTypeRepr::create(ASTContext &C, @@ -454,14 +457,14 @@ void SILBoxTypeRepr::printImpl(ASTPrinter &Printer, // linkage dependency. struct TypeReprTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const TypeRepr *TR = static_cast(Entity); TR->print(OS); } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const TypeRepr *TR = static_cast(Entity); diff --git a/lib/AST/TypeWalker.cpp b/lib/AST/TypeWalker.cpp index f5be4e10b5223..f95bdb01366f9 100644 --- a/lib/AST/TypeWalker.cpp +++ b/lib/AST/TypeWalker.cpp @@ -34,6 +34,7 @@ class Traversal : public TypeVisitor bool visitErrorType(ErrorType *ty) { return false; } bool visitUnresolvedType(UnresolvedType *ty) { return false; } + bool visitHoleType(HoleType *ty) { return false; } bool visitBuiltinType(BuiltinType *ty) { return false; } bool visitTypeAliasType(TypeAliasType *ty) { if (auto parent = ty->getParent()) diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index a138f4528039e..0581a70ca5284 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -17,17 +17,11 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTVisitor.h" -#include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DebuggerClient.h" -#include "swift/AST/ExistentialLayout.h" #include "swift/AST/ImportCache.h" -#include "swift/AST/Initializer.h" -#include "swift/AST/LazyResolver.h" #include "swift/AST/ModuleNameLookup.h" #include "swift/AST/NameLookup.h" #include "swift/AST/NameLookupRequests.h" -#include "swift/AST/ParameterList.h" -#include "swift/AST/SourceFile.h" #include "swift/Basic/Debug.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/SourceManager.h" @@ -42,58 +36,6 @@ using namespace swift; using namespace swift::namelookup; - -namespace { - - /// Determine whether unqualified lookup should look at the members of the - /// given nominal type or extension, vs. only looking at type parameters. - template bool shouldLookupMembers(D *decl, SourceLoc loc) { - // Only look at members of this type (or its inherited types) when - // inside the body or a protocol's top-level 'where' clause. (Why the - // 'where' clause? Because that's where you put constraints on - // inherited associated types.) - - // When we have no source-location information, we have to perform member - // lookup. - if (loc.isInvalid() || decl->getBraces().isInvalid()) - return true; - - SourceManager &SM = decl->getASTContext().SourceMgr; - - // If a code completion happens inside a function body, some lookups may - // happen from the 'loc' that is in a different buffer from the 'decl'. - // In such cases, look for members of the 'decl' because we know 'loc' is - // inside a function body in the 'decl'. - if (SM.hasCodeCompletionBuffer()) { - auto completionBufferID = SM.getCodeCompletionBufferID(); - if (SM.getRangeForBuffer(completionBufferID).contains(loc)) { - auto declBufferID = - decl->getDeclContext()->getParentSourceFile()->getBufferID(); - if (completionBufferID != declBufferID) - return true; - } - } - - // Within the braces, always look for members. - auto braces = decl->getBraces(); - if (braces.Start != braces.End && - SM.rangeContainsTokenLoc(braces, loc)) - return true; - - // Within 'where' clause, we can also look for members. - if (auto *whereClause = decl->getTrailingWhereClause()) { - SourceRange whereClauseRange = whereClause->getSourceRange(); - if (whereClauseRange.isValid() && - SM.rangeContainsTokenLoc(whereClauseRange, loc)) { - return true; - } - } - - // Don't look at the members. - return false; - } -} // end anonymous namespace - namespace { class UnqualifiedLookupFactory { @@ -105,11 +47,6 @@ namespace { using ResultsVector = SmallVector; private: - struct ContextAndResolvedIsCascadingUse { - DeclContext *const DC; - const bool isCascadingUse; - }; - /// Finds lookup results based on the types that self conforms to. /// For instance, self always conforms to a struct, enum or class. /// But in addition, self could conform to any number of protocols. @@ -207,8 +144,6 @@ namespace { #endif public: // for exp debugging - SourceFile const *recordedSF = nullptr; - bool recordedIsCascadingUse = false; unsigned resultsSizeBeforeLocalsPass = ~0; public: @@ -224,20 +159,6 @@ namespace { void performUnqualifiedLookup(); private: - struct ContextAndUnresolvedIsCascadingUse { - DeclContext *whereToLook; - Optional isCascadingUse; - ContextAndResolvedIsCascadingUse resolve(const bool resolution) const { - return ContextAndResolvedIsCascadingUse{ - whereToLook, isCascadingUse.getValueOr(resolution)}; - } - }; - - bool useASTScopesForLookup() const; - - /// For testing, assume this lookup is enabled: - bool wouldUseASTScopesForLookupIfItWereEnabled() const; - void lookUpTopLevelNamesInModuleScopeContext(DeclContext *); void lookInASTScopes(); @@ -250,110 +171,16 @@ namespace { /// to record the dividing line between results from first fruitful scope and /// the result. void recordCompletionOfAScope(); - - template void ifNotDoneYet(Fn fn) { - recordCompletionOfAScope(); - if (!isFirstResultEnough()) - fn(); - } - - template void ifNotDoneYet(Fn1 fn1, Fn2 fn2) { - ifNotDoneYet(fn1); - ifNotDoneYet(fn2); - } - + #pragma mark context-based lookup declarations - - void lookupOperatorInDeclContexts(ContextAndUnresolvedIsCascadingUse); - - /// When performing a lookup, we may come across a capture of 'self'. We - /// will need to remember the DeclContext of the innermost captured self so - /// that it can be used as the base DeclContext if we find a lookup result - /// in the enclosing type. \c capturedSelfContext tracks this. - void lookupNamesIntroducedBy(const ContextAndUnresolvedIsCascadingUse, - DeclContext *capturedSelfContext); - - void finishLookingInContext( - AddGenericParameters addGenericParameters, - DeclContext *lookupContextForThisContext, - Optional &&resultFinderForTypeContext, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupInModuleScopeContext(DeclContext *, Optional isCascadingUse); - - void lookupNamesIntroducedByPatternBindingInitializer( - PatternBindingInitializer *PBI, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void - lookupNamesIntroducedByLazyVariableInitializer(PatternBindingInitializer *PBI, - ParamDecl *selfParam, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByInitializerOfStoredPropertyOfAType( - PatternBindingInitializer *PBI, Optional isCascadingUse); - - /// An initializer of a global name, or a function-likelocal name. - void lookupNamesIntroducedByInitializerOfGlobalOrLocal( - PatternBindingInitializer *PBI, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByFunctionDecl(AbstractFunctionDecl *AFD, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByMemberFunction(AbstractFunctionDecl *AFD, - bool isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByPureFunction(AbstractFunctionDecl *AFD, - bool isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByClosure(AbstractClosureExpr *ACE, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - template - void lookupNamesIntroducedByNominalTypeOrExtension( - NominalTypeDeclOrExtensionDecl *D, Optional isCascadingUse); - - void lookupNamesIntroducedByDefaultArgumentInitializer( - DefaultArgumentInitializer *I, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByMiscContext(DeclContext *dc, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookForLocalVariablesIn(AbstractFunctionDecl *AFD, - Optional isCascadingUse); - void lookForLocalVariablesIn(ClosureExpr *); - void lookForLocalVariablesIn(SourceFile *); - + bool isOutsideBodyOfFunction(const AbstractFunctionDecl *const AFD) const; - void addGenericParametersForContext(DeclContext *dc); - void addGenericParametersForContext(GenericParamList *); - - /// Consume generic parameters - void addGenericParametersForFunction(AbstractFunctionDecl *AFD); - - static GenericParamList *getGenericParams(const DeclContext *const dc); - /// For diagnostic purposes, move aside the unavailables, and put /// them back as a last-ditch effort. /// Could be cleaner someday with a richer interface to UnqualifiedLookup. void setAsideUnavailableResults(size_t firstPossiblyUnavailableResult); - void recordDependencyOnTopLevelName(DeclContext *topLevelContext, - DeclNameRef name, bool isCascadingUse); - void addImportedResults(DeclContext *const dc); void addNamesKnownToDebugClient(DeclContext *dc); @@ -372,19 +199,6 @@ namespace { : None; } - static bool resolveIsCascadingUse(const DeclContext *const dc, - Optional isCascadingUse, - bool onlyCareAboutFunctionBody) { - return isCascadingUse.getValueOr(dc->isCascadingContextForLookup( - /*functionsAreNonCascading=*/onlyCareAboutFunctionBody)); - } - - static bool resolveIsCascadingUse(ContextAndUnresolvedIsCascadingUse x, - bool onlyCareAboutFunctionBody) { - return resolveIsCascadingUse(x.whereToLook, x.isCascadingUse, - onlyCareAboutFunctionBody); - } - void findResultsAndSaveUnavailables( DeclContext *lookupContextForThisContext, ResultFinderForTypeContext &&resultFinderForTypeContext, @@ -399,13 +213,6 @@ namespace { void print(raw_ostream &OS) const; void printResults(raw_ostream &OS) const; - bool verifyEqualTo(const UnqualifiedLookupFactory &&, StringRef thisLabel, - StringRef otherLabel) const; - - /// Legacy lookup is wrong here; we should NOT find this symbol. - bool shouldDiffer() const; - StringRef getSourceFileName() const; - #ifndef NDEBUG bool isTargetLookup() const; void stopForDebuggingIfStartingTargetLookup(bool isASTScopeLookup) const; @@ -493,50 +300,24 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() { "performUnqualifedLookup", DC->getParentSourceFile()); - const Optional initialIsCascadingUse = getInitialIsCascadingUse(); - - ContextAndUnresolvedIsCascadingUse contextAndIsCascadingUse{ - DC, initialIsCascadingUse}; - const bool crosscheckUnqualifiedLookup = - Ctx.LangOpts.CrosscheckUnqualifiedLookup; - if (useASTScopesForLookup()) { - static bool haveWarned = false; - if (!haveWarned && Ctx.LangOpts.WarnIfASTScopeLookup) { - haveWarned = true; - llvm::errs() << "WARNING: TRYING Scope exclusively\n"; - } + if (Loc.isValid()) { lookInASTScopes(); } else { + assert(DC->isModuleScopeContext() && + "Unqualified lookup without a source location must start from " + "a module-scope context"); + #ifndef NDEBUG stopForDebuggingIfStartingTargetLookup(false); #endif - - if (Name.isOperator()) - lookupOperatorInDeclContexts(contextAndIsCascadingUse); - else - lookupNamesIntroducedBy(contextAndIsCascadingUse, NULL); } - if (crosscheckUnqualifiedLookup && - wouldUseASTScopesForLookupIfItWereEnabled()) { - ResultsVector results; - size_t indexOfFirstOuterResult = 0; - UnqualifiedLookupFactory altLookup(Name, DC, Loc, options, results, - indexOfFirstOuterResult); - if (!useASTScopesForLookup()) - altLookup.lookInASTScopes(); - else if (Name.isOperator()) - altLookup.lookupOperatorInDeclContexts(contextAndIsCascadingUse); - else - altLookup.lookupNamesIntroducedBy(contextAndIsCascadingUse, NULL); - - const auto *ASTScopeLabel = "ASTScope lookup"; - const auto *contextLabel = "context-bsed lookup"; - const auto *mainLabel = - useASTScopesForLookup() ? ASTScopeLabel : contextLabel; - const auto *alternateLabel = - useASTScopesForLookup() ? contextLabel : ASTScopeLabel; - assert(verifyEqualTo(std::move(altLookup), mainLabel, alternateLabel)); + recordCompletionOfAScope(); + if (!isFirstResultEnough()) { + // If no result has been found yet, the dependency must be on a top-level + // name, since up to now, the search has been for non-top-level names. + auto *moduleScopeContext = DC->getModuleScopeContext(); + lookUpTopLevelNamesInModuleScopeContext(moduleScopeContext); } } @@ -561,386 +342,8 @@ void UnqualifiedLookupFactory::lookUpTopLevelNamesInModuleScopeContext( recordCompletionOfAScope(); } -bool UnqualifiedLookupFactory::useASTScopesForLookup() const { - return Ctx.LangOpts.EnableASTScopeLookup && - wouldUseASTScopesForLookupIfItWereEnabled(); -} - -bool UnqualifiedLookupFactory::wouldUseASTScopesForLookupIfItWereEnabled() - const { - if (!Loc.isValid()) - return false; - return (bool) DC->getParentSourceFile(); -} - #pragma mark context-based lookup definitions -void UnqualifiedLookupFactory::lookupOperatorInDeclContexts( - const ContextAndUnresolvedIsCascadingUse contextAndUseArg) { - ContextAndResolvedIsCascadingUse contextAndResolvedIsCascadingUse{ - // Operators are global - contextAndUseArg.whereToLook->getModuleScopeContext(), - resolveIsCascadingUse(contextAndUseArg, - /*onlyCareAboutFunctionBody*/ true)}; - lookupInModuleScopeContext(contextAndResolvedIsCascadingUse.DC, - contextAndResolvedIsCascadingUse.isCascadingUse); -} - -// TODO: Unify with LookupVisibleDecls.cpp::lookupVisibleDeclsImpl -void UnqualifiedLookupFactory::lookupNamesIntroducedBy( - const ContextAndUnresolvedIsCascadingUse contextAndIsCascadingUseArg, - DeclContext *capturedSelfContext) { -#ifndef NDEBUG - stopForDebuggingIfDuringTargetLookup(false); -#endif - DeclContext *const dc = contextAndIsCascadingUseArg.whereToLook; - const auto isCascadingUseSoFar = contextAndIsCascadingUseArg.isCascadingUse; - if (dc->isModuleScopeContext()) { - assert(capturedSelfContext == NULL && "By the time we reach module scope," - " there should be no 'self'."); - lookupInModuleScopeContext(dc, isCascadingUseSoFar); - } - else if (auto *PBI = dyn_cast(dc)) - lookupNamesIntroducedByPatternBindingInitializer(PBI, isCascadingUseSoFar, - capturedSelfContext); - else if (auto *AFD = dyn_cast(dc)) - lookupNamesIntroducedByFunctionDecl(AFD, isCascadingUseSoFar, - capturedSelfContext); - else if (auto *ACE = dyn_cast(dc)) - lookupNamesIntroducedByClosure(ACE, isCascadingUseSoFar, - capturedSelfContext); - else if (auto *ED = dyn_cast(dc)) { - assert(capturedSelfContext == NULL && "When we recurse into type context," - " 'self' should be forgotten."); - lookupNamesIntroducedByNominalTypeOrExtension(ED, isCascadingUseSoFar); - } - else if (auto *ND = dyn_cast(dc)) { - assert(capturedSelfContext == NULL && "When we recurse into type context," - " 'self' should be forgotten."); - lookupNamesIntroducedByNominalTypeOrExtension(ND, isCascadingUseSoFar); - } - else if (auto I = dyn_cast(dc)) - lookupNamesIntroducedByDefaultArgumentInitializer(I, isCascadingUseSoFar, - capturedSelfContext); - else - lookupNamesIntroducedByMiscContext(dc, isCascadingUseSoFar, - capturedSelfContext); -} - -void UnqualifiedLookupFactory::lookupInModuleScopeContext( - DeclContext *dc, Optional isCascadingUse) { - if (auto SF = dyn_cast(dc)) { - resultsSizeBeforeLocalsPass = Results.size(); - lookForLocalVariablesIn(SF); - } - ifNotDoneYet([&] { - // If no result has been found yet, the dependency must be on a top-level - // name, since up to now, the search has been for non-top-level names. - recordDependencyOnTopLevelName(dc, Name, isCascadingUse.getValueOr(true)); - lookUpTopLevelNamesInModuleScopeContext(dc); - }); -} - -void UnqualifiedLookupFactory::lookupNamesIntroducedByPatternBindingInitializer( - PatternBindingInitializer *PBI, Optional isCascadingUse, - DeclContext *capturedSelfContext) { - // Lazy variable initializer contexts have a 'self' parameter for - // instance member lookup. - if (auto *selfParam = PBI->getImplicitSelfDecl()) - lookupNamesIntroducedByLazyVariableInitializer(PBI, selfParam, - isCascadingUse, - capturedSelfContext); - else if (PBI->getParent()->isTypeContext()) { - assert(capturedSelfContext == NULL && "If we were in a type's property" - " initializer, there should be no 'self' to have been captured."); - lookupNamesIntroducedByInitializerOfStoredPropertyOfAType( - PBI, - isCascadingUse); - } - else - lookupNamesIntroducedByInitializerOfGlobalOrLocal(PBI, isCascadingUse, - capturedSelfContext); -} - - void UnqualifiedLookupFactory::lookupNamesIntroducedByLazyVariableInitializer( - PatternBindingInitializer *PBI, ParamDecl *selfParam, - Optional isCascadingUse, DeclContext *capturedSelfContext) { - Consumer.foundDecl(selfParam, DeclVisibilityKind::FunctionParameter); - ifNotDoneYet([&] { - DeclContext *const patternContainer = PBI->getParent(); - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - patternContainer, - ResultFinderForTypeContext(this, PBI, patternContainer), - resolveIsCascadingUse(PBI, isCascadingUse, - /*onlyCareAboutFunctionBody=*/false), - capturedSelfContext); - // clang-format on - }); -} - -void UnqualifiedLookupFactory:: - lookupNamesIntroducedByInitializerOfStoredPropertyOfAType( - PatternBindingInitializer *PBI, Optional isCascadingUse) { - // Initializers for stored properties of types perform static - // lookup into the surrounding context. - DeclContext *const storedPropertyContainer = PBI->getParent(); - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - storedPropertyContainer, - ResultFinderForTypeContext( - this, storedPropertyContainer, storedPropertyContainer), - resolveIsCascadingUse(storedPropertyContainer, None, - /*onlyCareAboutFunctionBody=*/false), - /*capturedSelfContext=*/NULL); - // clang-format on -} - -void UnqualifiedLookupFactory:: - lookupNamesIntroducedByInitializerOfGlobalOrLocal( - PatternBindingInitializer *PBI, Optional isCascadingUse, - DeclContext *capturedSelfContext) { - // There's not much to find here, we'll keep going up to a parent - // context. - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - PBI, - None, // not looking in the partic type - resolveIsCascadingUse(PBI, isCascadingUse, - /*onlyCareAboutFunctionBody=*/false), - capturedSelfContext); - // clang-format on -} - -void UnqualifiedLookupFactory::lookupNamesIntroducedByFunctionDecl( - AbstractFunctionDecl *AFD, Optional isCascadingUseArg, - DeclContext *capturedSelfContext) { - - // DOUG: how does this differ from isOutsideBodyOfFunction below? - const bool isCascadingUse = - AFD->isCascadingContextForLookup(false) && - (isCascadingUseArg.getValueOr( - Loc.isInvalid() || AFD->getBodySourceRange().isInvalid() || - !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc))); - - if (AFD->getDeclContext()->isTypeContext()) - lookupNamesIntroducedByMemberFunction(AFD, isCascadingUse, - capturedSelfContext); - else - lookupNamesIntroducedByPureFunction(AFD, isCascadingUse, - capturedSelfContext); -} - -void UnqualifiedLookupFactory::lookupNamesIntroducedByMemberFunction( - AbstractFunctionDecl *AFD, bool isCascadingUse, - DeclContext *capturedSelfContext) { - lookForLocalVariablesIn(AFD, isCascadingUse); - ifNotDoneYet( - [&] { - // If we're inside a function context, we're about to move to - // the parent DC, so we have to check the function's generic - // parameters first. - // Cannot start here in finishLookingInContext because AFD's - // getOuterParameters may be null even when AFD's parent has generics. - addGenericParametersForFunction(AFD); - }, - [&] { - DeclContext *const fnDeclContext = AFD->getDeclContext(); - // If we're not in the body of the function (for example, we - // might be type checking a default argument expression and - // performing name lookup from there), the base declaration - // is the nominal type, not 'self'. If we've captured self - // somewhere down the tree, we should use that as the context - // for lookup. - DeclContext *const BaseDC = - isOutsideBodyOfFunction(AFD) ? fnDeclContext - : capturedSelfContext ? capturedSelfContext - : AFD; - // If we are inside of a method, check to see if there are any ivars in - // scope, and if so, whether this is a reference to one of them. - // FIXME: We should persist this information between lookups. - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - AFD->getParent(), - ResultFinderForTypeContext(this, BaseDC, fnDeclContext), - isCascadingUse, - NULL); - // clang-format on - }); -} - -void UnqualifiedLookupFactory::lookupNamesIntroducedByPureFunction( - AbstractFunctionDecl *AFD, bool isCascadingUse, - DeclContext *capturedSelfContext) { - lookForLocalVariablesIn(AFD, isCascadingUse); - ifNotDoneYet([&] { - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - AFD, - None, - isCascadingUse, - capturedSelfContext); - }); -} - - -void UnqualifiedLookupFactory::lookupNamesIntroducedByClosure( - AbstractClosureExpr *ACE, Optional isCascadingUse, - DeclContext *capturedSelfContext) { - if (auto *CE = dyn_cast(ACE)) { - lookForLocalVariablesIn(CE); - // If we don't already have a captured self context, and this closure - // captures the self param (not weakly, so that implicit self is available), - // remember that. - if (capturedSelfContext == nullptr) - if (CE->capturesSelfEnablingImplictSelf()) - capturedSelfContext = CE; - } - ifNotDoneYet([&] { - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - ACE, - None, - resolveIsCascadingUse(ACE, isCascadingUse, - /*onlyCareAboutFunctionBody=*/false), - capturedSelfContext); - // clang-format on - }); -} - -template -void UnqualifiedLookupFactory::lookupNamesIntroducedByNominalTypeOrExtension( - NominalTypeDeclOrExtensionDecl *D, Optional isCascadingUse) { - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - D, - shouldLookupMembers(D, Loc) - ? Optional( - ResultFinderForTypeContext(this, D, D)) - : None, - resolveIsCascadingUse(D, isCascadingUse, - /*onlyCareAboutFunctionBody=*/false), - /*capturedSelfContext=*/NULL); - - // clang-format on -} - -void UnqualifiedLookupFactory:: - lookupNamesIntroducedByDefaultArgumentInitializer( - DefaultArgumentInitializer *I, Optional isCascadingUse, - DeclContext *capturedSelfContext) { - // In a default argument, skip immediately out of both the - // initializer and the function. - finishLookingInContext(AddGenericParameters::No, I->getParent(), None, false, - capturedSelfContext); -} - -void UnqualifiedLookupFactory::lookupNamesIntroducedByMiscContext( - DeclContext *dc, Optional isCascadingUse, - DeclContext *capturedSelfContext) { - // clang-format off - assert(isa(dc) || - isa(dc) || - isa(dc) || - isa(dc) || - isa(dc)); - finishLookingInContext( - AddGenericParameters::Yes, - dc, - None, - resolveIsCascadingUse(DC, isCascadingUse, - /*onlyCareAboutFunctionBody=*/false), - capturedSelfContext); - // clang-format on -} - - -void UnqualifiedLookupFactory::finishLookingInContext( - const AddGenericParameters addGenericParameters, - DeclContext *const lookupContextForThisContext, - Optional &&resultFinderForTypeContext, - const Optional isCascadingUse, - DeclContext *capturedSelfContext) { -#ifndef NDEBUG - stopForDebuggingIfDuringTargetLookup(false); -#endif - // When a generic has the same name as a member, Swift prioritizes the generic - // because the member could still be named by qualifying it. But there is no - // corresponding way to qualify a generic parameter. - // So, look for generics first. - if (addGenericParameters == AddGenericParameters::Yes) - addGenericParametersForContext(lookupContextForThisContext); - - ifNotDoneYet( - [&] { - if (resultFinderForTypeContext) - findResultsAndSaveUnavailables(lookupContextForThisContext, - std::move(*resultFinderForTypeContext), - *isCascadingUse, baseNLOptions); - }, - // Recurse into the next context. - [&] { - lookupNamesIntroducedBy(ContextAndUnresolvedIsCascadingUse{ - lookupContextForThisContext->getParentForLookup(), isCascadingUse}, - capturedSelfContext); - }); -} - - -void UnqualifiedLookupFactory::lookForLocalVariablesIn( - AbstractFunctionDecl *AFD, Optional isCascadingUse) { - // Look for local variables; normally, the parser resolves these - // for us, but it can't do the right thing inside local types. - // FIXME: when we can parse and typecheck the function body partially - // for code completion, AFD->getBody() check can be removed. - - if (Loc.isInvalid() || AFD->getBodySourceRange().isInvalid() || - !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc) || - !AFD->getBody()) { - return; - } - - namelookup::FindLocalVal localVal(SM, Loc, Consumer); - localVal.visit(AFD->getBody()); - - ifNotDoneYet([&] { - if (auto *P = AFD->getImplicitSelfDecl()) - localVal.checkValueDecl(P, DeclVisibilityKind::FunctionParameter); - localVal.checkParameterList(AFD->getParameters()); - }); -} - -void UnqualifiedLookupFactory::lookForLocalVariablesIn(ClosureExpr *CE) { - // Look for local variables; normally, the parser resolves these - // for us, but it can't do the right thing inside local types. - if (Loc.isInvalid()) - return; - namelookup::FindLocalVal localVal(SM, Loc, Consumer); - if (auto body = CE->getBody()) - localVal.visit(body); - ifNotDoneYet([&] { - if (auto params = CE->getParameters()) - localVal.checkParameterList(params); - }); -} - -void UnqualifiedLookupFactory::lookForLocalVariablesIn(SourceFile *SF) { - if (Loc.isInvalid()) - return; - // Look for local variables in top-level code; normally, the parser - // resolves these for us, but it can't do the right thing for - // local types. - namelookup::FindLocalVal localVal(SM, Loc, Consumer); - localVal.checkSourceFile(*SF); -} - bool UnqualifiedLookupFactory::isOutsideBodyOfFunction( const AbstractFunctionDecl *const AFD) const { return !AFD->isImplicit() && Loc.isValid() && @@ -948,48 +351,6 @@ bool UnqualifiedLookupFactory::isOutsideBodyOfFunction( !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc); } -GenericParamList * -UnqualifiedLookupFactory::getGenericParams(const DeclContext *const dc) { - if (auto nominal = dyn_cast(dc)) - return nominal->getGenericParams(); - if (auto ext = dyn_cast(dc)) - return ext->getGenericParams(); - if (auto subscript = dyn_cast(dc)) - return subscript->getGenericParams(); - if (auto func = dyn_cast(dc)) - return func->getGenericParams(); - return nullptr; -} - -void UnqualifiedLookupFactory::addGenericParametersForContext( - DeclContext *dc) { - // Generics can be nested, so visit the generic list, innermost first. - // Cannot use DeclContext::forEachGenericContext because this code breaks out - // if it finds a match and isFirstResultEnough() - addGenericParametersForContext(getGenericParams(dc)); -} - -void UnqualifiedLookupFactory::addGenericParametersForContext( - GenericParamList *dcGenericParams) { - if (!dcGenericParams) - return; - namelookup::FindLocalVal localVal(SM, Loc, Consumer); - localVal.checkGenericParams(dcGenericParams); - ifNotDoneYet([&] { - addGenericParametersForContext( - dcGenericParams->getOuterParameters()); - }); -} - -void UnqualifiedLookupFactory::addGenericParametersForFunction( - AbstractFunctionDecl *AFD) { - GenericParamList *GenericParams = AFD->getGenericParams(); - if (GenericParams) { - namelookup::FindLocalVal localVal(SM, Loc, Consumer); - localVal.checkGenericParams(GenericParams); - } -} - void UnqualifiedLookupFactory::ResultFinderForTypeContext::findResults( const DeclNameRef &Name, bool isCascadingUse, NLOptions baseNLOptions, DeclContext *contextForLookup, @@ -1043,13 +404,6 @@ void UnqualifiedLookupFactory::setAsideUnavailableResults( filterForDiscriminator(Results, DebugClient); } - -void UnqualifiedLookupFactory::recordDependencyOnTopLevelName( - DeclContext *topLevelContext, DeclNameRef name, bool isCascadingUse) { - recordedSF = dyn_cast(topLevelContext); - recordedIsCascadingUse = isCascadingUse; -} - void UnqualifiedLookupFactory::addImportedResults(DeclContext *const dc) { using namespace namelookup; SmallVector CurModuleResults; @@ -1189,28 +543,8 @@ void UnqualifiedLookupFactory::lookInASTScopes() { stopForDebuggingIfStartingTargetLookup(true); #endif - const auto history = ASTScope::unqualifiedLookup(DC->getParentSourceFile(), - Name, Loc, DC, consumer); - - ifNotDoneYet([&] { - // Copied from lookupInModuleScopeContext - // If no result has been found yet, the dependency must be on a top-level - // name, since up to now, the search has been for non-top-level names. - auto *const moduleScopeContext = DC->getParentSourceFile(); - - const Optional isCascadingUseAtStartOfLookup = - !Name.isOperator() - ? getInitialIsCascadingUse() - : resolveIsCascadingUse(DC, getInitialIsCascadingUse(), - /*onlyCareAboutFunctionBody*/ true); - - const Optional isCascadingUseAfterLookup = - ASTScope::computeIsCascadingUse(history, isCascadingUseAtStartOfLookup); - - recordDependencyOnTopLevelName(moduleScopeContext, Name, - isCascadingUseAfterLookup.getValueOr(true)); - lookUpTopLevelNamesInModuleScopeContext(moduleScopeContext); - }); + ASTScope::unqualifiedLookup(DC->getParentSourceFile(), + Name, Loc, DC, consumer); } bool ASTScopeDeclConsumerForUnqualifiedLookup::consume( @@ -1335,124 +669,6 @@ void UnqualifiedLookupFactory::print(raw_ostream &OS) const { OS << "\n"; } -#pragma mark debugging: output utilities for grepping - -static void writeLine(std::string s) { - llvm::errs() << "\n+-+-+-+- " << s << "\n"; -} - -StringRef UnqualifiedLookupFactory::getSourceFileName() const { - return DC->getParentSourceFile()->getFilename(); -} - -static void writeFirstLine(const UnqualifiedLookupFactory &ul, llvm::Twine s) { - std::string line = - std::string("In file: ") + ul.getSourceFileName().str() + ", " + s.str(); - writeLine(line); -} - -static void writeInconsistent(const UnqualifiedLookupFactory &me, - StringRef thisLabel, - const UnqualifiedLookupFactory &other, - StringRef otherLabel, llvm::Twine s) { - writeFirstLine(me, s); - other.print(llvm::errs()); - llvm::errs() << "\n" << thisLabel << " Results:\n"; - me.printResults(llvm::errs()); - llvm::errs() << "\n" << otherLabel << " Results:\n"; - other.printResults(llvm::errs()); - me.printScopes(llvm::errs()); -} - -#pragma mark comparing results - -bool UnqualifiedLookupFactory::verifyEqualTo( - const UnqualifiedLookupFactory &&other, const StringRef thisLabel, - StringRef otherLabel) const { - if (shouldDiffer()) { - return true; - } - auto writeErr = [&](llvm::Twine s) { - writeInconsistent(*this, thisLabel, other, otherLabel, s); - }; - if (Results.size() != other.Results.size()) { - writeErr(thisLabel + " found " + std::to_string(Results.size()) + " but " + - otherLabel + " found " + std::to_string(other.Results.size())); - assert(false && "mismatch in number of results"); - } - for (size_t i : indices(Results)) { - const auto &e = Results[i]; - const auto &oe = other.Results[i]; - if (e.getValueDecl() != oe.getValueDecl()) { - // print_ast_tc_function_bodies.swift generic from subscript vs get fn - std::string a; llvm::raw_string_ostream as(a); - std::string b; llvm::raw_string_ostream bs(b); - e.getValueDecl()->print(as); - oe.getValueDecl()->print(bs); - if (a == b) - llvm::errs() << "ValueDecls differ but print same\n"; - else { - writeErr(std::string( "ValueDecls differ at ") + std::to_string(i)); - assert(false && "other lookup found different Decl"); - } - } - if (e.getDeclContext() != oe.getDeclContext()) { - writeErr((std::string("Contexts differ at ")) + std::to_string(i)); - assert(false && "ASTScopeImpl found different context"); - } - // unsigned printContext(llvm::raw_ostream &OS, unsigned indent = 0, - // bool onlyAPartialLine = false) const; - } - if (IndexOfFirstOuterResult != other.IndexOfFirstOuterResult) { - writeErr( std::string("IndexOfFirstOuterResult differs, should be: ") - + std::to_string(IndexOfFirstOuterResult) - + std::string( ", is: ") - + std::to_string(other.IndexOfFirstOuterResult)); - assert(false && "other lookup IndexOfFirstOuterResult differs"); - } - if (recordedSF != other.recordedSF) { - writeErr(std::string("recordedSF differs: shouldBe: ") + - (recordedSF ? recordedSF->getFilename().str() - : std::string("")) + - std::string(" is: ") + - (other.recordedSF ? other.recordedSF->getFilename().str() - : std::string(""))); - assert(false && "other lookup recordedSF differs"); - } - if (recordedSF && recordedIsCascadingUse != other.recordedIsCascadingUse) { - writeErr(std::string("recordedIsCascadingUse differs: shouldBe: ") + - std::to_string(recordedIsCascadingUse) + std::string(" is: ") + - std::to_string(other.recordedIsCascadingUse)); - assert(false && "other lookup recordedIsCascadingUse differs"); - } - return true; -} - -bool UnqualifiedLookupFactory::shouldDiffer() const { - auto *SF = dyn_cast(DC->getModuleScopeContext()); - if (!SF) - return false; - - static std::vector testsThatShouldDiffer { - "swift/test/Constraints/diagnostics.swift", - "swift/test/Constraints/enum_cases.swift", - "swift/test/Constraints/rdar39401774.swift", - "swift/test/Constraints/rdar39401774-astscope.swift", - "swift/test/Interpreter/repl.swift", - "swift/test/Sema/diag_defer_captures.swift", - "swift/test/Sema/diag_use_before_declaration.swift", - "swift/test/SourceKit/CodeFormat/indent-closure.swift", - "swift/test/TypeCoercion/overload_noncall.swift", - "swift/test/expr/capture/nested_class.swift", - "swift/test/expr/capture/order.swift", - "swift/test/NameLookup/name_lookup2.swift" - }; - StringRef fileName = SF->getFilename(); - return llvm::any_of(testsThatShouldDiffer, [&](const char *testFile) { - return fileName.endswith(testFile); - }); -} - #pragma mark breakpointing #ifndef NDEBUG diff --git a/lib/Basic/FileTypes.cpp b/lib/Basic/FileTypes.cpp index d2c1570495dd8..f4af753c5e56a 100644 --- a/lib/Basic/FileTypes.cpp +++ b/lib/Basic/FileTypes.cpp @@ -94,6 +94,7 @@ bool file_types::isTextual(ID Id) { case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_LLVM_BC: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: @@ -138,6 +139,7 @@ bool file_types::isAfterLLVM(ID Id) { case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftOverlayFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: @@ -189,6 +191,7 @@ bool file_types::isPartOfSwiftCompilation(ID Id) { case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftOverlayFile: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: case file_types::TY_SwiftDeps: diff --git a/lib/Basic/Platform.cpp b/lib/Basic/Platform.cpp index c90a1d95b7243..29b8fc9223c58 100644 --- a/lib/Basic/Platform.cpp +++ b/lib/Basic/Platform.cpp @@ -489,3 +489,47 @@ swift::getTargetSDKVersion(clang::driver::DarwinSDKInfo &SDKInfo, return SDKVersion; } + +static std::string getPlistEntry(const llvm::Twine &Path, StringRef KeyName) { + auto BufOrErr = llvm::MemoryBuffer::getFile(Path); + if (!BufOrErr) { + // FIXME: diagnose properly + return {}; + } + + std::string Key = ""; + Key += KeyName; + Key += ""; + + StringRef Lines = BufOrErr.get()->getBuffer(); + while (!Lines.empty()) { + StringRef CurLine; + std::tie(CurLine, Lines) = Lines.split('\n'); + if (CurLine.find(Key) != StringRef::npos) { + std::tie(CurLine, Lines) = Lines.split('\n'); + unsigned Begin = CurLine.find("") + strlen(""); + unsigned End = CurLine.find(""); + return CurLine.substr(Begin, End - Begin).str(); + } + } + + return {}; +} + +std::string swift::getSDKBuildVersionFromPlist(StringRef Path) { + return getPlistEntry(Path, "ProductBuildVersion"); +} + +std::string swift::getSDKBuildVersion(StringRef Path) { + return getSDKBuildVersionFromPlist((llvm::Twine(Path) + + "/System/Library/CoreServices/SystemVersion.plist").str()); +} + +std::string swift::getSDKName(StringRef Path) { + std::string Name = getPlistEntry(llvm::Twine(Path)+"/SDKSettings.plist", + "CanonicalName"); + if (Name.empty() && Path.endswith(".sdk")) { + Name = llvm::sys::path::filename(Path).drop_back(strlen(".sdk")).str(); + } + return Name; +} diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e82e1638b593a..8bada4e358315 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -27,6 +27,7 @@ add_subdirectory(IDE) add_subdirectory(Immediate) add_subdirectory(IRGen) add_subdirectory(LLVMPasses) +add_subdirectory(Localization) add_subdirectory(Markup) add_subdirectory(Migrator) add_subdirectory(Option) diff --git a/lib/ClangImporter/ClangAdapter.cpp b/lib/ClangImporter/ClangAdapter.cpp index eddac5d46b3bf..6c38957639336 100644 --- a/lib/ClangImporter/ClangAdapter.cpp +++ b/lib/ClangImporter/ClangAdapter.cpp @@ -77,11 +77,26 @@ importer::getDefinitionForClangTypeDecl(const clang::Decl *D) { return None; } +static bool isInLocalScope(const clang::Decl *D) { + const clang::DeclContext *LDC = D->getLexicalDeclContext(); + while (true) { + if (LDC->isFunctionOrMethod()) + return true; + if (!isa(LDC)) + return false; + if (const auto *CRD = dyn_cast(LDC)) + if (CRD->isLambda()) + return true; + LDC = LDC->getLexicalParent(); + } + return false; +} + const clang::Decl * importer::getFirstNonLocalDecl(const clang::Decl *D) { D = D->getCanonicalDecl(); auto iter = llvm::find_if(D->redecls(), [](const clang::Decl *next) -> bool { - return !next->isLexicallyWithinFunctionOrMethod(); + return !isInLocalScope(next); }); if (iter == D->redecls_end()) return nullptr; @@ -344,6 +359,7 @@ OmissionTypeName importer::getClangTypeNameForOmission(clang::ASTContext &ctx, case clang::BuiltinType::ARCUnbridgedCast: case clang::BuiltinType::BoundMember: case clang::BuiltinType::BuiltinFn: + case clang::BuiltinType::IncompleteMatrixIdx: case clang::BuiltinType::Overload: case clang::BuiltinType::PseudoObject: case clang::BuiltinType::UnknownAny: @@ -376,6 +392,7 @@ OmissionTypeName importer::getClangTypeNameForOmission(clang::ASTContext &ctx, case clang::BuiltinType::SatULongFract: case clang::BuiltinType::Half: case clang::BuiltinType::LongDouble: + case clang::BuiltinType::BFloat16: case clang::BuiltinType::Float16: case clang::BuiltinType::Float128: case clang::BuiltinType::NullPtr: @@ -446,21 +463,14 @@ OmissionTypeName importer::getClangTypeNameForOmission(clang::ASTContext &ctx, // OpenMP types that don't have Swift equivalents. case clang::BuiltinType::OMPArraySection: + case clang::BuiltinType::OMPArrayShaping: + case clang::BuiltinType::OMPIterator: return OmissionTypeName(); // SVE builtin types that don't have Swift equivalents. - case clang::BuiltinType::SveInt8: - case clang::BuiltinType::SveInt16: - case clang::BuiltinType::SveInt32: - case clang::BuiltinType::SveInt64: - case clang::BuiltinType::SveUint8: - case clang::BuiltinType::SveUint16: - case clang::BuiltinType::SveUint32: - case clang::BuiltinType::SveUint64: - case clang::BuiltinType::SveFloat16: - case clang::BuiltinType::SveFloat32: - case clang::BuiltinType::SveFloat64: - case clang::BuiltinType::SveBool: +#define SVE_TYPE(Name, Id, ...) \ + case clang::BuiltinType::Id: +#include "clang/Basic/AArch64SVEACLETypes.def" return OmissionTypeName(); } } @@ -714,8 +724,7 @@ bool importer::isUnavailableInSwift( return false; } -OptionalTypeKind importer::getParamOptionality(version::Version swiftVersion, - const clang::ParmVarDecl *param, +OptionalTypeKind importer::getParamOptionality(const clang::ParmVarDecl *param, bool knownNonNull) { auto &clangCtx = param->getASTContext(); diff --git a/lib/ClangImporter/ClangAdapter.h b/lib/ClangImporter/ClangAdapter.h index 0b066364bd622..9a15bbd523efa 100644 --- a/lib/ClangImporter/ClangAdapter.h +++ b/lib/ClangImporter/ClangAdapter.h @@ -161,15 +161,11 @@ bool isUnavailableInSwift(const clang::Decl *decl, const PlatformAvailability &, /// Determine the optionality of the given Clang parameter. /// -/// \param swiftLanguageVersion What version of Swift we're using, which affects -/// how optionality is inferred. -/// /// \param param The Clang parameter. /// /// \param knownNonNull Whether a function- or method-level "nonnull" attribute /// applies to this parameter. -OptionalTypeKind getParamOptionality(version::Version swiftLanguageVersion, - const clang::ParmVarDecl *param, +OptionalTypeKind getParamOptionality(const clang::ParmVarDecl *param, bool knownNonNull); } } diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 19f6dc6c0c97e..0cf5f19cdac90 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -32,7 +32,6 @@ #include "swift/Basic/Range.h" #include "swift/Basic/StringExtras.h" #include "swift/Basic/Version.h" -#include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Config.h" #include "swift/Demangling/Demangle.h" @@ -410,11 +409,10 @@ bool ClangImporter::Implementation::shouldIgnoreBridgeHeaderTopLevelDecl( } ClangImporter::ClangImporter(ASTContext &ctx, - const ClangImporterOptions &clangImporterOpts, DependencyTracker *tracker, DWARFImporterDelegate *dwarfImporterDelegate) : ClangModuleLoader(tracker), - Impl(*new Implementation(ctx, clangImporterOpts, dwarfImporterDelegate)) { + Impl(*new Implementation(ctx, dwarfImporterDelegate)) { } ClangImporter::~ClangImporter() { @@ -466,12 +464,11 @@ getGlibcModuleMapPath(SearchPathOptions& Opts, llvm::Triple triple, void importer::getNormalInvocationArguments( std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts) { + ASTContext &ctx) { const auto &LangOpts = ctx.LangOpts; const llvm::Triple &triple = LangOpts.Target; SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; - + ClangImporterOptions &importerOpts = ctx.ClangImporterOpts; auto languageVersion = ctx.LangOpts.EffectiveLanguageVersion; if (llvm::sys::path::extension(importerOpts.BridgingHeader) @@ -692,8 +689,7 @@ importer::getNormalInvocationArguments( static void getEmbedBitcodeInvocationArguments(std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts) { + ASTContext &ctx) { invocationArgStrs.insert(invocationArgStrs.end(), { // Backend mode. "-fembed-bitcode", @@ -708,11 +704,11 @@ getEmbedBitcodeInvocationArguments(std::vector &invocationArgStrs, void importer::addCommonInvocationArguments( std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts) { + ASTContext &ctx) { using ImporterImpl = ClangImporter::Implementation; const llvm::Triple &triple = ctx.LangOpts.Target; SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; + const ClangImporterOptions &importerOpts = ctx.ClangImporterOpts; invocationArgStrs.push_back("-target"); invocationArgStrs.push_back(triple.str()); @@ -924,25 +920,24 @@ ClangImporter::getOrCreatePCH(const ClangImporterOptions &ImporterOptions, } std::vector -ClangImporter::getClangArguments(ASTContext &ctx, - const ClangImporterOptions &importerOpts) { - if (importerOpts.ExtraArgsOnly) { - return importerOpts.ExtraArgs; +ClangImporter::getClangArguments(ASTContext &ctx) { + if (ctx.ClangImporterOpts.ExtraArgsOnly) { + return ctx.ClangImporterOpts.ExtraArgs; } std::vector invocationArgStrs; // Clang expects this to be like an actual command line. So we need to pass in // "clang" for argv[0] invocationArgStrs.push_back("clang"); - switch (importerOpts.Mode) { + switch (ctx.ClangImporterOpts.Mode) { case ClangImporterOptions::Modes::Normal: case ClangImporterOptions::Modes::PrecompiledModule: - getNormalInvocationArguments(invocationArgStrs, ctx, importerOpts); + getNormalInvocationArguments(invocationArgStrs, ctx); break; case ClangImporterOptions::Modes::EmbedBitcode: - getEmbedBitcodeInvocationArguments(invocationArgStrs, ctx, importerOpts); + getEmbedBitcodeInvocationArguments(invocationArgStrs, ctx); break; } - addCommonInvocationArguments(invocationArgStrs, ctx, importerOpts); + addCommonInvocationArguments(invocationArgStrs, ctx); return invocationArgStrs; } @@ -978,19 +973,15 @@ ClangImporter::createClangInvocation(ClangImporter *importer, nullptr, false, CC1Args); } -ArrayRef ClangImporter::getExtraClangArgs() const { - return Impl.ExtraClangArgs; -} - std::unique_ptr -ClangImporter::create(ASTContext &ctx, const ClangImporterOptions &importerOpts, +ClangImporter::create(ASTContext &ctx, std::string swiftPCHHash, DependencyTracker *tracker, DWARFImporterDelegate *dwarfImporterDelegate) { std::unique_ptr importer{ - new ClangImporter(ctx, importerOpts, tracker, dwarfImporterDelegate)}; - importer->Impl.ClangArgs = getClangArguments(ctx, importerOpts); + new ClangImporter(ctx, tracker, dwarfImporterDelegate)}; + auto &importerOpts = ctx.ClangImporterOpts; + importer->Impl.ClangArgs = getClangArguments(ctx); ArrayRef invocationArgStrs = importer->Impl.ClangArgs; - importer->Impl.ExtraClangArgs = importerOpts.ExtraArgs; if (importerOpts.DumpClangDiagnostics) { llvm::errs() << "'"; llvm::interleave( @@ -1601,6 +1592,30 @@ ClangImporter::emitBridgingPCH(StringRef headerPath, return false; } +bool ClangImporter::runPreprocessor(StringRef inputPath, StringRef outputPath) { + auto emitInstance = cloneCompilerInstanceForPrecompiling(); + auto &invocation = emitInstance->getInvocation(); + auto LangOpts = invocation.getLangOpts(); + auto &OutputOpts = invocation.getPreprocessorOutputOpts(); + OutputOpts.ShowCPP = 1; + OutputOpts.ShowComments = 0; + OutputOpts.ShowLineMarkers = 0; + OutputOpts.ShowMacros = 0; + OutputOpts.ShowMacroComments = 0; + auto language = getLanguageFromOptions(LangOpts); + auto inputFile = clang::FrontendInputFile(inputPath, language); + + auto &FrontendOpts = invocation.getFrontendOpts(); + FrontendOpts.Inputs = {inputFile}; + FrontendOpts.OutputFile = outputPath.str(); + FrontendOpts.ProgramAction = clang::frontend::PrintPreprocessedInput; + + auto action = wrapActionForIndexingIfEnabled( + FrontendOpts, std::make_unique()); + emitInstance->ExecuteAction(*action); + return emitInstance->getDiagnostics().hasErrorOccurred(); +} + bool ClangImporter::emitPrecompiledModule(StringRef moduleMapPath, StringRef moduleName, StringRef outputPath) { @@ -1718,7 +1733,6 @@ bool ClangImporter::canImportModule(Located moduleID) { ModuleDecl *ClangImporter::Implementation::loadModuleClang( SourceLoc importLoc, ArrayRef> path) { - auto &clangContext = getClangASTContext(); auto &clangHeaderSearch = getClangPreprocessor().getHeaderSearchInfo(); // Look up the top-level module first, to see if it exists at all. @@ -1732,8 +1746,9 @@ ModuleDecl *ClangImporter::Implementation::loadModuleClang( SmallVector, 4> clangPath; for (auto component : path) { - clangPath.push_back({&clangContext.Idents.get(component.Item.str()), - exportSourceLoc(component.Loc)}); + clangPath.emplace_back( + getClangPreprocessor().getIdentifierInfo(component.Item.str()), + exportSourceLoc(component.Loc)); } auto &rawDiagClient = Instance->getDiagnosticClient(); @@ -1996,20 +2011,20 @@ bool PlatformAvailability::treatDeprecatedAsUnavailable( } ClangImporter::Implementation::Implementation( - ASTContext &ctx, const ClangImporterOptions &opts, + ASTContext &ctx, DWARFImporterDelegate *dwarfImporterDelegate) : SwiftContext(ctx), - ImportForwardDeclarations(opts.ImportForwardDeclarations), - InferImportAsMember(opts.InferImportAsMember), - DisableSwiftBridgeAttr(opts.DisableSwiftBridgeAttr), - BridgingHeaderExplicitlyRequested(!opts.BridgingHeader.empty()), - DisableOverlayModules(opts.DisableOverlayModules), + ImportForwardDeclarations(ctx.ClangImporterOpts.ImportForwardDeclarations), + InferImportAsMember(ctx.ClangImporterOpts.InferImportAsMember), + DisableSwiftBridgeAttr(ctx.ClangImporterOpts.DisableSwiftBridgeAttr), + BridgingHeaderExplicitlyRequested(!ctx.ClangImporterOpts.BridgingHeader.empty()), + DisableOverlayModules(ctx.ClangImporterOpts.DisableOverlayModules), IsReadingBridgingPCH(false), CurrentVersion(ImportNameVersion::fromOptions(ctx.LangOpts)), BridgingHeaderLookupTable(new SwiftLookupTable(nullptr)), BuffersForDiagnostics(ctx.SourceMgr), platformAvailability(ctx.LangOpts), nameImporter(), - DisableSourceImport(opts.DisableSourceImport), + DisableSourceImport(ctx.ClangImporterOpts.DisableSourceImport), DWARFImporter(dwarfImporterDelegate) {} ClangImporter::Implementation::~Implementation() { @@ -3337,7 +3352,7 @@ StringRef ClangModuleUnit::getModuleDefiningPath() const { return clangSourceMgr.getFilename(clangModule->DefinitionLoc); } -Optional +Optional ClangModuleUnit::getASTSourceDescriptor() const { if (clangModule) { assert(ASTSourceDescriptor.getModuleOrNull() == clangModule); @@ -3685,6 +3700,7 @@ void ClangImporter::Implementation::lookupValue( clangDecl->getMostRecentDecl(); CurrentVersion.forEachOtherImportNameVersion( + SwiftContext.LangOpts.EnableExperimentalConcurrency, [&](ImportNameVersion nameVersion) { if (anyMatching) return; @@ -3694,6 +3710,12 @@ void ClangImporter::Implementation::lookupValue( if (!newName.getDeclName().matchesRef(name)) return; + // If we asked for an async import and didn't find one, skip this. + // This filters out duplicates. + if (nameVersion.supportsConcurrency() && + !newName.getAsyncInfo()) + return; + const clang::DeclContext *clangDC = newName.getEffectiveContext().getAsDeclContext(); if (!clangDC || !clangDC->isFileContext()) diff --git a/lib/ClangImporter/ClangModuleDependencyScanner.cpp b/lib/ClangImporter/ClangModuleDependencyScanner.cpp index 6c44002d46dbb..fbc693e5b22ef 100644 --- a/lib/ClangImporter/ClangModuleDependencyScanner.cpp +++ b/lib/ClangImporter/ClangModuleDependencyScanner.cpp @@ -16,7 +16,6 @@ #include "ImporterImpl.h" #include "swift/AST/ModuleDependencies.h" #include "swift/ClangImporter/ClangImporter.h" -#include "swift/ClangImporter/ClangImporterOptions.h" #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" #include "llvm/Support/FileSystem.h" @@ -87,11 +86,11 @@ namespace { : Command(std::move(Cmd)) {} virtual std::vector - getCompileCommands(StringRef FilePath) const { + getCompileCommands(StringRef FilePath) const override { return {Command}; } - virtual std::vector getAllCompileCommands() const { + virtual std::vector getAllCompileCommands() const override { return {Command}; } @@ -105,9 +104,7 @@ namespace { // adds search paths to Clang's data structures rather than to its // command line. static void addSearchPathInvocationArguments( - std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts) { + std::vector &invocationArgStrs, ASTContext &ctx) { SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; for (const auto &framepath : searchPathOpts.FrameworkSearchPaths) { invocationArgStrs.push_back(framepath.IsSystem ? "-iframework" : "-F"); @@ -123,15 +120,14 @@ static void addSearchPathInvocationArguments( /// Create the command line for Clang dependency scanning. static std::vector getClangDepScanningInvocationArguments( ASTContext &ctx, - const ClangImporterOptions &importerOpts, StringRef sourceFileName) { std::vector commandLineArgs; // Form the basic command line. commandLineArgs.push_back("clang"); - importer::getNormalInvocationArguments(commandLineArgs, ctx, importerOpts); - importer::addCommonInvocationArguments(commandLineArgs, ctx, importerOpts); - addSearchPathInvocationArguments(commandLineArgs, ctx, importerOpts); + importer::getNormalInvocationArguments(commandLineArgs, ctx); + importer::addCommonInvocationArguments(commandLineArgs, ctx); + addSearchPathInvocationArguments(commandLineArgs, ctx); auto sourceFilePos = std::find( commandLineArgs.begin(), commandLineArgs.end(), @@ -254,6 +250,18 @@ void ClangImporter::recordModuleDependencies( swiftArgs.push_back("-module-name"); swiftArgs.push_back(clangModuleDep.ModuleName); + // Pass down search paths to the -emit-module action. + // Unlike building Swift modules, we need to include all search paths to + // the clang invocation to build PCMs because transitive headers can only + // be found via search paths. Passing these headers as explicit inputs can + // be quite challenging. + for (auto &path: Impl.SwiftContext.SearchPathOpts.ImportSearchPaths) { + addClangArg("-I" + path); + } + for (auto &path: Impl.SwiftContext.SearchPathOpts.FrameworkSearchPaths) { + addClangArg((path.IsSystem ? "-Fsystem": "-F") + path.Path); + } + // Swift frontend option for input file path (Foo.modulemap). swiftArgs.push_back(clangModuleDep.ClangModuleMapFile); // Module-level dependencies. @@ -291,15 +299,11 @@ Optional ClangImporter::getModuleDependencies( // FIXME: Emit a diagnostic here. return None; } - // Reform the Clang importer options. - // FIXME: Just save a reference or copy so we can get this back. - ClangImporterOptions importerOpts; // Determine the command-line arguments for dependency scanning. auto &ctx = Impl.SwiftContext; std::vector commandLineArgs = - getClangDepScanningInvocationArguments( - ctx, importerOpts, *importHackFile); + getClangDepScanningInvocationArguments(ctx, *importHackFile); std::string workingDir = ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get(); @@ -334,18 +338,13 @@ bool ClangImporter::addBridgingHeaderDependencies( // Retrieve or create the shared state. auto clangImpl = getOrCreateClangImpl(cache); - // Reform the Clang importer options. - // FIXME: Just save a reference or copy so we can get this back. - ClangImporterOptions importerOpts; - // Retrieve the bridging header. std::string bridgingHeader = *targetModule.getBridgingHeader(); // Determine the command-line arguments for dependency scanning. auto &ctx = Impl.SwiftContext; std::vector commandLineArgs = - getClangDepScanningInvocationArguments( - ctx, importerOpts, bridgingHeader); + getClangDepScanningInvocationArguments(ctx, bridgingHeader); std::string workingDir = ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get(); diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index e35b0aed470b7..db5dd761a2ebe 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -16,7 +16,6 @@ #include "CFTypeInfo.h" #include "ImporterImpl.h" -#include "swift/Strings.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/Attr.h" @@ -36,15 +35,19 @@ #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/Stmt.h" -#include "swift/AST/Types.h" #include "swift/AST/TypeCheckRequests.h" +#include "swift/AST/Types.h" #include "swift/Basic/Defer.h" #include "swift/Basic/PrettyStackTrace.h" +#include "swift/Basic/Statistic.h" #include "swift/ClangImporter/ClangModule.h" -#include "swift/Parse/Lexer.h" #include "swift/Config.h" +#include "swift/Parse/Lexer.h" +#include "swift/Strings.h" + #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/DeclObjCCommon.h" #include "clang/AST/DeclCXX.h" #include "clang/Basic/CharInfo.h" #include "swift/Basic/Statistic.h" @@ -160,10 +163,10 @@ static FuncDecl *createFuncOrAccessor(ASTContext &ctx, SourceLoc funcLoc, DeclName name, SourceLoc nameLoc, ParameterList *bodyParams, Type resultTy, + bool async, bool throws, DeclContext *dc, ClangNode clangNode) { - TypeLoc resultTypeLoc = resultTy ? TypeLoc::withoutLoc(resultTy) : TypeLoc(); if (accessorInfo) { return AccessorDecl::create(ctx, funcLoc, /*accessorKeywordLoc*/ SourceLoc(), @@ -175,16 +178,10 @@ static FuncDecl *createFuncOrAccessor(ASTContext &ctx, SourceLoc funcLoc, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, bodyParams, - resultTypeLoc, dc, clangNode); + resultTy, dc, clangNode); } else { - return FuncDecl::create(ctx, /*StaticLoc=*/SourceLoc(), - StaticSpellingKind::None, - funcLoc, name, nameLoc, - /*Async=*/false, /*AsyncLoc=*/SourceLoc(), - throws, /*ThrowsLoc=*/SourceLoc(), - /*GenericParams=*/nullptr, - bodyParams, - resultTypeLoc, dc, clangNode); + return FuncDecl::createImported(ctx, funcLoc, name, nameLoc, async, throws, + bodyParams, resultTy, dc, clangNode); } } @@ -380,6 +377,7 @@ getSwiftStdlibType(const clang::TypedefNameDecl *D, case clang::TargetInfo::VoidPtrBuiltinVaList: case clang::TargetInfo::PowerABIBuiltinVaList: case clang::TargetInfo::AAPCSABIBuiltinVaList: + case clang::TargetInfo::HexagonBuiltinVaList: assert(ClangCtx.getTypeSize(ClangCtx.VoidPtrTy) == ClangTypeSize && "expected va_list type to be sizeof(void *)"); break; @@ -611,7 +609,7 @@ static void makeEnumRawValueGetter(ClangImporter::Implementation &Impl, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(rawTy), enumDecl); + rawTy, enumDecl); getterDecl->setImplicit(); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); @@ -687,7 +685,7 @@ static AccessorDecl *makeStructRawValueGetter( /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(computedType), structDecl); + computedType, structDecl); getterDecl->setImplicit(); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); @@ -717,7 +715,7 @@ static AccessorDecl *makeFieldGetterDecl(ClangImporter::Implementation &Impl, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(getterType), importedDecl, clangNode); + getterType, importedDecl, clangNode); getterDecl->setAccess(AccessLevel::Public); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); @@ -750,7 +748,7 @@ static AccessorDecl *makeFieldSetterDecl(ClangImporter::Implementation &Impl, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(voidTy), importedDecl, clangNode); + voidTy, importedDecl, clangNode); setterDecl->setIsObjC(false); setterDecl->setIsDynamic(false); setterDecl->setSelfAccessKind(SelfAccessKind::Mutating); @@ -1218,15 +1216,16 @@ makeBitFieldAccessors(ClangImporter::Implementation &Impl, fieldType, clang::VK_RValue, clang::SourceLocation()); - - auto cSetterExpr = new (Ctx) clang::BinaryOperator(cSetterMemberExpr, - cSetterValueExpr, - clang::BO_Assign, - fieldType, - clang::VK_RValue, - clang::OK_Ordinary, - clang::SourceLocation(), - clang::FPOptions()); + + auto cSetterExpr = clang::BinaryOperator::Create(Ctx, + cSetterMemberExpr, + cSetterValueExpr, + clang::BO_Assign, + fieldType, + clang::VK_RValue, + clang::OK_Ordinary, + clang::SourceLocation(), + clang::FPOptionsOverride()); cSetterDecl->setBody(cSetterExpr); } @@ -1684,8 +1683,7 @@ buildSubscriptGetterDecl(ClangImporter::Implementation &Impl, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, - params, - TypeLoc::withoutLoc(elementTy), dc, + params, elementTy, dc, getter->getClangNode()); thunk->setAccess(getOverridableAccessLevel(dc)); @@ -1737,7 +1735,7 @@ buildSubscriptSetterDecl(ClangImporter::Implementation &Impl, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, valueIndicesPL, - TypeLoc::withoutLoc(TupleType::getEmpty(C)), dc, + TupleType::getEmpty(C), dc, setter->getClangNode()); thunk->setAccess(getOverridableAccessLevel(dc)); @@ -1922,7 +1920,7 @@ static bool addErrorDomain(NominalTypeDecl *swiftDecl, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(stringTy), swiftDecl); + stringTy, swiftDecl); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(false); @@ -2065,7 +2063,7 @@ classImplementsProtocol(const clang::ObjCInterfaceDecl *constInterface, static void applyPropertyOwnership(VarDecl *prop, - clang::ObjCPropertyDecl::PropertyAttributeKind attrs) { + clang::ObjCPropertyAttribute::Kind attrs) { Type ty = prop->getInterfaceType(); if (auto innerTy = ty->getOptionalObjectType()) ty = innerTy; @@ -2073,19 +2071,19 @@ applyPropertyOwnership(VarDecl *prop, return; ASTContext &ctx = prop->getASTContext(); - if (attrs & clang::ObjCPropertyDecl::OBJC_PR_copy) { + if (attrs & clang::ObjCPropertyAttribute::kind_copy) { prop->getAttrs().add(new (ctx) NSCopyingAttr(false)); return; } - if (attrs & clang::ObjCPropertyDecl::OBJC_PR_weak) { + if (attrs & clang::ObjCPropertyAttribute::kind_weak) { prop->getAttrs().add(new (ctx) ReferenceOwnershipAttr(ReferenceOwnership::Weak)); prop->setInterfaceType(WeakStorageType::get( prop->getInterfaceType(), ctx)); return; } - if ((attrs & clang::ObjCPropertyDecl::OBJC_PR_assign) || - (attrs & clang::ObjCPropertyDecl::OBJC_PR_unsafe_unretained)) { + if ((attrs & clang::ObjCPropertyAttribute::kind_assign) || + (attrs & clang::ObjCPropertyAttribute::kind_unsafe_unretained)) { prop->getAttrs().add( new (ctx) ReferenceOwnershipAttr(ReferenceOwnership::Unmanaged)); prop->setInterfaceType(UnmanagedStorageType::get( @@ -2262,7 +2260,7 @@ namespace { /// Whether the names we're importing are from the language version the user /// requested, or if these are decls from another version bool isActiveSwiftVersion() const { - return getVersion() == getActiveSwiftVersion(); + return getVersion().withConcurrency(false) == getActiveSwiftVersion().withConcurrency(false); } void recordMemberInContext(const DeclContext *dc, ValueDecl *member) { @@ -2308,7 +2306,7 @@ namespace { return canonicalName; } - // Special handling when we import using the older Swift name. + // Special handling when we import using the alternate Swift name. // // Import using the alternate Swift name. If that fails, or if it's // identical to the active Swift name, we won't introduce an alternate @@ -2317,6 +2315,19 @@ namespace { if (!alternateName) return ImportedName(); + // Importing for concurrency is special in that the same declaration + // is imported both with a completion handler parameter and as 'async', + // creating two separate declarations. + if (getVersion().supportsConcurrency()) { + // If the resulting name isn't special for concurrency, it's not + // different. + if (!alternateName.getAsyncInfo()) + return ImportedName(); + + // Otherwise, it's a legitimately different import. + return alternateName; + } + if (alternateName.getDeclName() == canonicalName.getDeclName() && alternateName.getEffectiveContext().equalsWithoutResolving( canonicalName.getEffectiveContext())) { @@ -2478,6 +2489,13 @@ namespace { return; } + // If this the active and current Swift versions differ based on + // concurrency, it's not actually a variant. + if (getVersion().supportsConcurrency() != + getActiveSwiftVersion().supportsConcurrency()) { + return; + } + // TODO: some versions should be deprecated instead of unavailable ASTContext &ctx = decl->getASTContext(); @@ -3477,14 +3495,33 @@ namespace { Decl *VisitClassTemplateSpecializationDecl( const clang::ClassTemplateSpecializationDecl *decl) { - // FIXME: We could import specializations, but perhaps only as unnamed - // structural types. - return nullptr; + // `Sema::isCompleteType` will try to instantiate the class template as a + // side-effect and we rely on this here. `decl->getDefinition()` can + // return nullptr before the call to sema and return its definition + // afterwards. + if (!Impl.getClangSema().isCompleteType( + decl->getLocation(), + Impl.getClangASTContext().getRecordType(decl))) { + // If we got nullptr definition now it means the type is not complete. + // We don't import incomplete types. + return nullptr; + } + auto def = dyn_cast( + decl->getDefinition()); + assert(def && "Class template instantiation didn't have definition"); + // FIXME: This will instantiate all members of the specialization (and detect + // instantiation failures in them), which can be more than is necessary + // and is more than what Clang does. As a result we reject some C++ + // programs that Clang accepts. + Impl.getClangSema().InstantiateClassTemplateSpecializationMembers( + def->getLocation(), def, clang::TSK_ExplicitInstantiationDefinition); + + return VisitRecordDecl(def); } Decl *VisitClassTemplatePartialSpecializationDecl( - const clang::ClassTemplatePartialSpecializationDecl *decl) { - // Note: templates are not imported. + const clang::ClassTemplatePartialSpecializationDecl *decl) { + // Note: partial template specializations are not imported. return nullptr; } @@ -3826,9 +3863,10 @@ namespace { // FIXME: Poor location info. auto nameLoc = Impl.importSourceLoc(decl->getLocation()); - result = createFuncOrAccessor(Impl.SwiftContext, loc, accessorInfo, name, - nameLoc, bodyParams, resultTy, - /*throws*/ false, dc, decl); + result = createFuncOrAccessor( + Impl.SwiftContext, loc, accessorInfo, name, + nameLoc, bodyParams, resultTy, + /*async*/ false, /*throws*/ false, dc, decl); if (!dc->isModuleScopeContext()) { if (selfIsInOut) @@ -4342,6 +4380,7 @@ namespace { kind = SpecialMethodKind::NSDictionarySubscriptGetter; // Import the type that this method will have. + Optional asyncConvention; Optional errorConvention; // If we have a property accessor, find the corresponding property @@ -4380,7 +4419,7 @@ namespace { importedType = Impl.importMethodParamsAndReturnType( dc, decl, decl->parameters(), decl->isVariadic(), isInSystemModule(dc), &bodyParams, importedName, - errorConvention, kind); + asyncConvention, errorConvention, kind); } if (!importedType) return nullptr; @@ -4399,16 +4438,15 @@ namespace { } } - auto result = createFuncOrAccessor(Impl.SwiftContext, - /*funcLoc*/SourceLoc(), - accessorInfo, - importedName.getDeclName(), - /*nameLoc*/SourceLoc(), - bodyParams, Type(), - importedName.getErrorInfo().hasValue(), - dc, decl); - - result->setAccess(getOverridableAccessLevel(dc)); + // Determine whether the function is throwing and/or async. + bool throws = importedName.getErrorInfo().hasValue(); + bool async = false; + auto asyncInfo = importedName.getAsyncInfo(); + if (asyncInfo) { + async = true; + if (asyncInfo->isThrowing()) + throws = true; + } auto resultTy = importedType.getType(); auto isIUO = importedType.isImplicitlyUnwrapped(); @@ -4433,8 +4471,15 @@ namespace { } } - // Record the return type. - result->getBodyResultTypeLoc().setType(resultTy); + auto result = createFuncOrAccessor(Impl.SwiftContext, + /*funcLoc*/SourceLoc(), + accessorInfo, + importedName.getDeclName(), + /*nameLoc*/SourceLoc(), + bodyParams, resultTy, + async, throws, dc, decl); + + result->setAccess(getOverridableAccessLevel(dc)); // Optional methods in protocols. if (decl->getImplementationControl() == clang::ObjCMethodDecl::Optional && @@ -4464,6 +4509,11 @@ namespace { result->setForeignErrorConvention(*errorConvention); } + // Record the async convention. + if (asyncConvention) { + result->setForeignAsyncConvention(*asyncConvention); + } + // Handle attributes. if (decl->hasAttr() && isa(result) && @@ -4495,6 +4545,7 @@ namespace { Impl.addAlternateDecl(result, cast(imported)); } } + return result; } @@ -6331,11 +6382,14 @@ ConstructorDecl *SwiftDeclConverter::importConstructor( assert(ownerNominal && "Method in non-type context?"); // Import the type that this method will have. + Optional asyncConvention; Optional errorConvention; ParameterList *bodyParams; auto importedType = Impl.importMethodParamsAndReturnType( dc, objcMethod, args, variadic, isInSystemModule(dc), &bodyParams, - importedName, errorConvention, SpecialMethodKind::Constructor); + importedName, asyncConvention, errorConvention, + SpecialMethodKind::Constructor); + assert(!asyncConvention && "Initializers don't have async conventions"); if (!importedType) return nullptr; @@ -6435,6 +6489,7 @@ ConstructorDecl *SwiftDeclConverter::importConstructor( return known->second; // Create the actual constructor. + assert(!importedName.getAsyncInfo()); auto result = Impl.createDeclWithClangNode( objcMethod, AccessLevel::Public, importedName.getDeclName(), /*NameLoc=*/SourceLoc(), failability, /*FailabilityLoc=*/SourceLoc(), @@ -6864,12 +6919,14 @@ SwiftDeclConverter::importSubscript(Decl *decl, auto &C = Impl.SwiftContext; auto bodyParams = ParameterList::create(C, getterIndex); DeclName name(C, DeclBaseName::createSubscript(), {Identifier()}); - auto subscript = Impl.createDeclWithClangNode( - getter->getClangNode(), getOverridableAccessLevel(dc), name, - /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, - decl->getLoc(), bodyParams, decl->getLoc(), - TypeLoc::withoutLoc(elementTy), dc, - /*GenericParams=*/nullptr); + auto *const subscript = SubscriptDecl::createImported(C, + name, decl->getLoc(), + bodyParams, decl->getLoc(), + elementTy, dc, + getter->getClangNode()); + const auto access = getOverridableAccessLevel(dc); + subscript->setAccess(access); + subscript->setSetterAccess(access); // Build the thunks. AccessorDecl *getterThunk = @@ -7135,6 +7192,11 @@ void SwiftDeclConverter::importMirroredProtocolMembers( if (isa(afd)) return; + // Asynch methods are also always imported without async, so don't + // record them here. + if (afd->hasAsync()) + return; + auto objcMethod = dyn_cast_or_null(member->getClangDecl()); if (!objcMethod) @@ -8538,8 +8600,7 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, - params, - TypeLoc::withoutLoc(type), dc); + params, type, dc); func->setStatic(isStatic); func->setAccess(getOverridableAccessLevel(dc)); func->setIsObjC(false); @@ -8885,7 +8946,7 @@ ClangImporter::getEnumConstantName(const clang::EnumConstantDecl *enumConstant){ // linkage dependency. struct ClangDeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const clang::Decl *CD = static_cast(Entity); @@ -8908,7 +8969,7 @@ struct ClangDeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter { } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; if (CSM) { diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 1611d20507369..972e9ca887bf7 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -29,10 +29,11 @@ #include "swift/AST/TypeRepr.h" #include "swift/AST/Types.h" #include "swift/Basic/StringExtras.h" -#include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/Parse/Parser.h" +#include "swift/Strings.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/Mangle.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Module.h" #include "clang/Basic/OperatorKinds.h" @@ -805,8 +806,6 @@ static bool omitNeedlessWordsInFunctionName( Optional errorParamIndex, bool returnsSelf, bool isInstanceMethod, NameImporter &nameImporter) { clang::ASTContext &clangCtx = nameImporter.getClangContext(); - const version::Version &swiftLanguageVersion = - nameImporter.getLangOpts().EffectiveLanguageVersion; // Collect the parameter type names. StringRef firstParamName; @@ -835,8 +834,7 @@ static bool omitNeedlessWordsInFunctionName( bool hasDefaultArg = ClangImporter::Implementation::inferDefaultArgument( param->getType(), - getParamOptionality(swiftLanguageVersion, param, - !nonNullArgs.empty() && nonNullArgs[i]), + getParamOptionality(param, !nonNullArgs.empty() && nonNullArgs[i]), nameImporter.getIdentifier(baseName), argumentName, i == 0, isLastParameter, nameImporter) != DefaultArgumentKind::None; @@ -1137,6 +1135,183 @@ Optional NameImporter::considerErrorImport( return None; } +/// Whether the given parameter name identifies a completion handler. +static bool isCompletionHandlerParamName(StringRef paramName) { + return paramName == "completionHandler" || paramName == "completion" || + paramName == "withCompletionHandler"; +} + +/// Whether the give base name implies that the first parameter is a completion +/// handler. +/// +/// \returns a trimmed base name when it does, \c None others +static Optional isCompletionHandlerInBaseName(StringRef basename) { + if (basename.endswith("WithCompletionHandler")) { + return basename.drop_back(strlen("WithCompletionHandler")); + } + + if (basename.endswith("WithCompletion")) { + return basename.drop_back(strlen("WithCompletion")); + } + + return None; +} + + +// Determine whether the given type is a nullable NSError type. +static bool isNullableNSErrorType( + clang::ASTContext &clangCtx, clang::QualType type) { + auto objcPtrType = type->getAs(); + if (!objcPtrType) + return false; + + auto iface = objcPtrType->getInterfaceDecl(); + if (!iface || iface->getName() != "NSError") + return false; + + // If nullability is specified, check it. + if (auto nullability = type->getNullability(clangCtx)) { + switch (translateNullability(*nullability)) { + case OTK_None: + return false; + + case OTK_ImplicitlyUnwrappedOptional: + case OTK_Optional: + return true; + } + } + + // Otherwise, assume it's nullable. + return true; +} + +Optional +NameImporter::considerAsyncImport( + const clang::ObjCMethodDecl *clangDecl, + StringRef &baseName, + SmallVectorImpl ¶mNames, + ArrayRef params, + bool isInitializer, bool hasCustomName, + Optional errorInfo) { + // If there are no unclaimed parameters, there's no . + unsigned errorParamAdjust = errorInfo ? 1 : 0; + if (params.size() - errorParamAdjust == 0) + return None; + + // If the # of parameter names doesn't line up with the # of parameters, + // bail out. There are extra C parameters on the method or a custom name + // was incorrect. + if (params.size() != paramNames.size() + errorParamAdjust) + return None; + + // The last parameter will be the completion handler for an async function. + unsigned completionHandlerParamIndex = params.size() - 1; + unsigned completionHandlerParamNameIndex = paramNames.size() - 1; + + // Determine whether the naming indicates that this is a completion + // handler. + Optional newBaseName; + if (isCompletionHandlerParamName( + paramNames[completionHandlerParamNameIndex])) { + // The argument label itself has an appropriate name. + } else if (!hasCustomName && completionHandlerParamIndex == 0 && + (newBaseName = isCompletionHandlerInBaseName(baseName))) { + // The base name implies that the first parameter is a completion handler. + } else if (isCompletionHandlerParamName( + params[completionHandlerParamIndex]->getName())) { + // The parameter has an appropriate name. + } else { + return None; + } + + // Used for returns once we've determined that the method cannot be + // imported as async, even though it has what looks like a completion handler + // parameter. + auto notAsync = [&](const char *reason) -> + Optional { +#ifdef ASYNC_IMPORT_DEBUG + llvm::errs() << "*** failed async import: " << reason << "\n"; + clangDecl->dump(llvm::errs()); +#endif + + return None; + }; + + // Initializers cannot be 'async'. + // FIXME: We might eventually allow this. + if (isInitializer) + return notAsync("initializers cannot be async"); + + // Accessors are never imported as async. + if (clangDecl->isPropertyAccessor()) + return notAsync("method is a property accessor"); + + // Check whether we method has a suitable return type. + if (clangDecl->getReturnType()->isVoidType()) { + // 'void' is the common case; the method produces no synchronous result. + } else if (errorInfo && + ForeignErrorConvention::resultTypeErasedToVoid( + errorInfo->getKind())) { + // The method has been imported as throwing in a manner that erased the + // result type to Void. + } else { + return notAsync("method does not return void"); + } + + // The completion handler parameter must have block type. + auto completionHandlerParam = params[completionHandlerParamIndex]; + if (!isBlockParameter(completionHandlerParam)) + return notAsync("parameter is not a block"); + + // Dig out the function type of the completion handler's block type. + // If there is no prototype, (e.g., the completion handler is of type + // void (^)()), we cannot importer it. + auto completionHandlerFunctionType = + completionHandlerParam->getType()->castAs() + ->getPointeeType()->getAs(); + if (!completionHandlerFunctionType) + return notAsync("block parameter does not have a prototype"); + + // The completion handler parameter must itself return 'void'. + if (!completionHandlerFunctionType->getReturnType()->isVoidType()) + return notAsync("completion handler parameter does not return 'void'"); + + // Scan the parameters of the block type to look for a parameter of a + // nullable NSError type, which would indicate that the async method could + // throw. + Optional completionHandlerErrorParamIndex; + auto completionHandlerParamTypes = + completionHandlerFunctionType->getParamTypes(); + auto &clangCtx = clangDecl->getASTContext(); + for (unsigned paramIdx : indices(completionHandlerParamTypes)) { + auto paramType = completionHandlerParamTypes[paramIdx]; + + // We are only interested in nullable NSError parameters. + if (!isNullableNSErrorType(clangCtx, paramType)) + continue; + + // If this is the first nullable error parameter, note that. + if (!completionHandlerErrorParamIndex) { + completionHandlerErrorParamIndex = paramIdx; + continue; + } + + // More than one nullable NSError parameter. Don't import as throwing. + completionHandlerErrorParamIndex = None; + break; + } + + // Drop the completion handler parameter name. + paramNames.erase(paramNames.begin() + completionHandlerParamNameIndex); + + // Update the base name, if needed. + if (newBaseName && !hasCustomName) + baseName = *newBaseName; + + return ForeignAsyncConvention::Info( + completionHandlerParamIndex, completionHandlerErrorParamIndex); +} + bool NameImporter::hasErrorMethodNameCollision( const clang::ObjCMethodDecl *method, unsigned paramIndex, StringRef suffixToStrip) { @@ -1348,7 +1523,8 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, else if (parsedName.IsSetter) result.info.accessorKind = ImportedAccessorKind::PropertySetter; - if (method && parsedName.IsFunctionName) { + if (method && parsedName.IsFunctionName && + result.info.accessorKind == ImportedAccessorKind::None) { // Get the parameters. ArrayRef params{method->param_begin(), method->param_end()}; @@ -1360,6 +1536,21 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, result.info.hasErrorInfo = true; result.info.errorInfo = *errorInfo; } + + if (version.supportsConcurrency()) { + if (auto asyncInfo = considerAsyncImport( + method, parsedName.BaseName, parsedName.ArgumentLabels, + params, isInitializer, /*hasCustomName=*/true, + result.getErrorInfo())) { + result.info.hasAsyncInfo = true; + result.info.asyncInfo = *asyncInfo; + + // Update the name to reflect the new parameter labels. + result.declName = formDeclName( + swiftCtx, parsedName.BaseName, parsedName.ArgumentLabels, + /*isFunction=*/true, isInitializer); + } + } } return result; @@ -1622,6 +1813,17 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, result.info.accessorKind = ImportedAccessorKind::SubscriptSetter; } + if (version.supportsConcurrency() && + result.info.accessorKind == ImportedAccessorKind::None) { + if (auto asyncInfo = considerAsyncImport( + objcMethod, baseName, argumentNames, params, isInitializer, + /*hasCustomName=*/false, + result.getErrorInfo())) { + result.info.hasAsyncInfo = true; + result.info.asyncInfo = *asyncInfo; + } + } + break; } } @@ -1698,6 +1900,34 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, } } + if (auto classTemplateSpecDecl = + dyn_cast(D)) { + if (!isa(D)) { + + auto &astContext = classTemplateSpecDecl->getASTContext(); + // Itanium mangler produces valid Swift identifiers, use it to generate a name for + // this instantiation. + clang::MangleContext *mangler = clang::ItaniumMangleContext::create( + astContext, astContext.getDiagnostics()); + llvm::SmallString<128> storage; + llvm::raw_svector_ostream buffer(storage); + mangler->mangleTypeName(astContext.getRecordType(classTemplateSpecDecl), + buffer); + + // The Itanium mangler does not provide a way to get the mangled + // representation of a type. Instead, we call mangleTypeName() that + // returns the name of the RTTI typeinfo symbol, and remove the _ZTS + // prefix. Then we prepend __CxxTemplateInst to reduce chances of conflict + // with regular C and C++ structs. + llvm::SmallString<128> mangledNameStorage; + llvm::raw_svector_ostream mangledName(mangledNameStorage); + assert(buffer.str().take_front(4) == "_ZTS"); + mangledName << CXX_TEMPLATE_INST_PREFIX << buffer.str().drop_front(4); + + baseName = swiftCtx.getIdentifier(mangledName.str()).get(); + } + } + // swift_newtype-ed declarations may have common words with the type name // stripped. if (auto newtypeDecl = findSwiftNewtype(D, clangSema, version)) { @@ -1865,6 +2095,7 @@ bool NameImporter::forEachDistinctImportName( seenNames.push_back(key); activeVersion.forEachOtherImportNameVersion( + swiftCtx.LangOpts.EnableExperimentalConcurrency, [&](ImportNameVersion nameVersion) { // Check to see if the name is different. ImportedName newName = importName(decl, nameVersion); diff --git a/lib/ClangImporter/ImportName.h b/lib/ClangImporter/ImportName.h index ddb4b0aa4105c..5f5d9a027343e 100644 --- a/lib/ClangImporter/ImportName.h +++ b/lib/ClangImporter/ImportName.h @@ -23,6 +23,7 @@ #include "swift/Basic/Version.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "clang/Sema/Sema.h" @@ -42,15 +43,18 @@ enum { NumImportedAccessorKindBits = 3 }; /// The name version class ImportNameVersion : public RelationalOperationsBase { - unsigned rawValue; + unsigned rawValue : 31; + unsigned concurrency : 1; + friend llvm::DenseMapInfo; enum AsConstExpr_t { AsConstExpr }; - constexpr ImportNameVersion() : rawValue(0) {} + constexpr ImportNameVersion() : rawValue(0), concurrency(false) {} constexpr ImportNameVersion(unsigned version, AsConstExpr_t) - : rawValue(version) {} - explicit ImportNameVersion(unsigned version) : rawValue(version) { + : rawValue(version), concurrency(false) {} + explicit ImportNameVersion(unsigned version, bool concurrency = false) + : rawValue(version), concurrency(concurrency) { assert(version >= 2 && "only Swift 2 and later are supported"); } public: @@ -67,7 +71,7 @@ class ImportNameVersion : public RelationalOperationsBase { return ImportNameVersion::swift4_2(); } unsigned major = version[0]; - return ImportNameVersion(major >= 5 ? major + 1 : major); + return ImportNameVersion(major >= 5 ? major + 1 : major, false); } unsigned majorVersionNumber() const { @@ -89,11 +93,21 @@ class ImportNameVersion : public RelationalOperationsBase { return llvm::VersionTuple(majorVersionNumber(), minorVersionNumber()); } + /// Whether to consider importing functions as 'async'. + bool supportsConcurrency() const { return concurrency; } + + ImportNameVersion withConcurrency(bool concurrency) const { + ImportNameVersion result = *this; + result.concurrency = concurrency; + return result; + } + bool operator==(ImportNameVersion other) const { - return rawValue == other.rawValue; + return rawValue == other.rawValue && concurrency == other.concurrency; } bool operator<(ImportNameVersion other) const { - return rawValue < other.rawValue; + return rawValue < other.rawValue || + (rawValue == other.rawValue && concurrency < other.concurrency); } /// Calls \p action for each name version other than this one, first going @@ -102,10 +116,19 @@ class ImportNameVersion : public RelationalOperationsBase { /// /// This is the most useful order for importing compatibility stubs. void forEachOtherImportNameVersion( + bool withConcurrency, llvm::function_ref action) const { assert(*this >= ImportNameVersion::swift2()); ImportNameVersion nameVersion = *this; + assert(!nameVersion.supportsConcurrency()); + + // If we've been asked to also consider concurrency, do so for the + // primary version (only). + if (withConcurrency) { + action(nameVersion.withConcurrency(true)); + } + while (nameVersion > ImportNameVersion::swift2()) { --nameVersion.rawValue; action(nameVersion); @@ -175,6 +198,10 @@ class ImportedName { /// throwing Swift methods, describes how the mapping is performed. ForeignErrorConvention::Info errorInfo; + /// For names that map Objective-C completion handlers into async + /// Swift methods, describes how the mapping is performed. + ForeignAsyncConvention::Info asyncInfo; + /// For a declaration name that makes the declaration into an /// instance member, the index of the "Self" parameter. unsigned selfIndex; @@ -201,11 +228,13 @@ class ImportedName { unsigned hasErrorInfo : 1; + unsigned hasAsyncInfo : 1; + Info() : errorInfo(), selfIndex(), initKind(CtorInitializerKind::Designated), accessorKind(ImportedAccessorKind::None), hasCustomName(false), droppedVariadic(false), importAsMember(false), hasSelfIndex(false), - hasErrorInfo(false) {} + hasErrorInfo(false), hasAsyncInfo(false) {} } info; public: @@ -239,6 +268,14 @@ class ImportedName { return None; } + /// For names that map Objective-C methods with completion handlers into + /// async Swift methods, describes how the mapping is performed. + Optional getAsyncInfo() const { + if (info.hasAsyncInfo) + return info.asyncInfo; + return None; + } + /// For a declaration name that makes the declaration into an /// instance member, the index of the "Self" parameter. Optional getSelfIndex() const { @@ -416,6 +453,14 @@ class NameImporter { ArrayRef params, bool isInitializer, bool hasCustomName); + Optional + considerAsyncImport(const clang::ObjCMethodDecl *clangDecl, + StringRef &baseName, + SmallVectorImpl ¶mNames, + ArrayRef params, + bool isInitializer, bool hasCustomName, + Optional errorInfo); + EffectiveClangContext determineEffectiveContext(const clang::NamedDecl *, const clang::DeclContext *, ImportNameVersion version); diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 15da7f4e5ed9b..145fee6dbb2d6 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -34,6 +34,7 @@ #include "swift/Strings.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjCCommon.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Lex/Preprocessor.h" @@ -248,6 +249,7 @@ namespace { case clang::BuiltinType::ARCUnbridgedCast: case clang::BuiltinType::BoundMember: case clang::BuiltinType::BuiltinFn: + case clang::BuiltinType::IncompleteMatrixIdx: case clang::BuiltinType::Overload: case clang::BuiltinType::PseudoObject: case clang::BuiltinType::UnknownAny: @@ -278,6 +280,7 @@ namespace { case clang::BuiltinType::SatUShortFract: case clang::BuiltinType::SatUFract: case clang::BuiltinType::SatULongFract: + case clang::BuiltinType::BFloat16: case clang::BuiltinType::Float128: case clang::BuiltinType::NullPtr: case clang::BuiltinType::Char8: @@ -348,32 +351,35 @@ namespace { // OpenMP types that don't have Swift equivalents. case clang::BuiltinType::OMPArraySection: + case clang::BuiltinType::OMPArrayShaping: + case clang::BuiltinType::OMPIterator: return Type(); // SVE builtin types that don't have Swift equivalents. - case clang::BuiltinType::SveInt8: - case clang::BuiltinType::SveInt16: - case clang::BuiltinType::SveInt32: - case clang::BuiltinType::SveInt64: - case clang::BuiltinType::SveUint8: - case clang::BuiltinType::SveUint16: - case clang::BuiltinType::SveUint32: - case clang::BuiltinType::SveUint64: - case clang::BuiltinType::SveFloat16: - case clang::BuiltinType::SveFloat32: - case clang::BuiltinType::SveFloat64: - case clang::BuiltinType::SveBool: +#define SVE_TYPE(Name, Id, ...) \ + case clang::BuiltinType::Id: +#include "clang/Basic/AArch64SVEACLETypes.def" return Type(); } llvm_unreachable("Invalid BuiltinType."); } + ImportResult VisitExtIntType(const clang::ExtIntType *) { + // ExtInt is not supported in Swift. + return Type(); + } + ImportResult VisitPipeType(const clang::PipeType *) { // OpenCL types are not supported in Swift. return Type(); } + ImportResult VisitMatrixType(const clang::MatrixType *ty) { + // Matrix types are not supported in Swift. + return Type(); + } + ImportResult VisitComplexType(const clang::ComplexType *type) { // FIXME: Implement once Complex is in the library. return Type(); @@ -1589,8 +1595,8 @@ bool ClangImporter::Implementation::shouldAllowNSUIntegerAsInt( ImportedType ClangImporter::Implementation::importPropertyType( const clang::ObjCPropertyDecl *decl, bool isFromSystemModule) { const auto assignOrUnsafeUnretained = - clang::ObjCPropertyDecl::OBJC_PR_assign | - clang::ObjCPropertyDecl::OBJC_PR_unsafe_unretained; + clang::ObjCPropertyAttribute::kind_assign | + clang::ObjCPropertyAttribute::kind_unsafe_unretained; ImportTypeKind importKind; // HACK: Certain decls are always imported using bridged types, @@ -1747,8 +1753,7 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList( // Check nullability of the parameter. OptionalTypeKind OptionalityOfParam = - getParamOptionality(SwiftContext.LangOpts.EffectiveLanguageVersion, - param, !nonNullArgs.empty() && nonNullArgs[index]); + getParamOptionality(param, !nonNullArgs.empty() && nonNullArgs[index]); ImportTypeKind importKind = ImportTypeKind::Parameter; if (param->hasAttr()) @@ -1989,11 +1994,48 @@ static Type mapGenericArgs(const DeclContext *fromDC, return type.subst(subs); } +/// Decompose the type of a completion handler parameter in a function +/// imported as 'async' and produce the result type of the 'async' function. +static Type decomposeCompletionHandlerType( + Type paramTy, ForeignAsyncConvention::Info info) { + auto fnType = paramTy->lookThroughAllOptionalTypes()->getAs(); + if (!fnType) + return Type(); + + SmallVector resultTypeElts; + auto params = fnType->getParams(); + for (unsigned paramIdx : indices(params)) { + const auto ¶m = params[paramIdx]; + if (param.isInOut() || param.isVariadic()) + return Type(); + + // If there is an error parameter to the completion handler, it is + // not part of the result type of the asynchronous function. + if (info.completionHandlerErrorParamIndex() && + paramIdx == *info.completionHandlerErrorParamIndex()) + continue; + + resultTypeElts.push_back(param.getPlainType()); + } + + switch (resultTypeElts.size()) { + case 0: + return paramTy->getASTContext().getVoidDecl()->getDeclaredInterfaceType(); + + case 1: + return resultTypeElts.front().getType(); + + default: + return TupleType::get(resultTypeElts, paramTy->getASTContext()); + } +} + ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( const DeclContext *dc, const clang::ObjCMethodDecl *clangDecl, ArrayRef params, bool isVariadic, bool isFromSystemModule, ParameterList **bodyParams, ImportedName importedName, + Optional &asyncConvention, Optional &foreignErrorInfo, SpecialMethodKind kind) { @@ -2025,6 +2067,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( CanType origSwiftResultTy; Optional errorInfo = importedName.getErrorInfo(); + auto asyncInfo = importedName.getAsyncInfo(); OptionalTypeKind OptionalityOfReturn; if (clangDecl->hasAttr()) { OptionalityOfReturn = OTK_None; @@ -2087,6 +2130,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( swiftResultTy = mapGenericArgs(origDC, dc, swiftResultTy); CanType errorParamType; + CanType completionHandlerType; SmallBitVector nonNullArgs = getNonNullArgs(clangDecl, params); @@ -2123,12 +2167,14 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( continue; } + bool paramIsCompletionHandler = + asyncInfo && paramIndex == asyncInfo->CompletionHandlerParamIndex; + // Import the parameter type into Swift. // Check nullability of the parameter. OptionalTypeKind optionalityOfParam - = getParamOptionality(SwiftContext.LangOpts.EffectiveLanguageVersion, - param, + = getParamOptionality(param, !nonNullArgs.empty() && nonNullArgs[paramIndex]); bool allowNSUIntegerAsIntInParam = isFromSystemModule; @@ -2193,6 +2239,19 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( continue; } + // If this is a completion handler, figure out it's effect on the result + // type but don't build it into the parameter type. + if (paramIsCompletionHandler) { + if (Type replacedSwiftResultTy = + decomposeCompletionHandlerType(swiftParamTy, *asyncInfo)) { + swiftResultTy = replacedSwiftResultTy; + completionHandlerType = swiftParamTy->getCanonicalType(); + continue; + } + + llvm_unreachable("async info computed incorrectly?"); + } + // Map __attribute__((noescape)) to @noescape. bool addNoEscapeAttr = false; if (param->hasAttr()) { @@ -2281,6 +2340,12 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( swiftResultTy = SwiftContext.getNeverType(); } + if (asyncInfo) { + asyncConvention = ForeignAsyncConvention( + completionHandlerType, asyncInfo->CompletionHandlerParamIndex, + asyncInfo->CompletionHandlerErrorParamIndex); + } + if (errorInfo) { foreignErrorInfo = getForeignErrorInfo(*errorInfo, errorParamType, origSwiftResultTy); diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 977b2b268d726..8ee400018ba1e 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -313,7 +313,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation using Version = importer::ImportNameVersion; public: - Implementation(ASTContext &ctx, const ClangImporterOptions &opts, + Implementation(ASTContext &ctx, DWARFImporterDelegate *dwarfImporterDelegate); ~Implementation(); @@ -393,8 +393,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// Clang arguments used to create the Clang invocation. std::vector ClangArgs; - /// Extra clang args specified via "-Xcc" - std::vector ExtraClangArgs; public: /// Mapping of already-imported declarations. llvm::DenseMap, Decl *> ImportedDecls; @@ -1161,6 +1159,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation bool isFromSystemModule, ParameterList **bodyParams, importer::ImportedName importedName, + Optional &asyncConv, Optional &errorConv, SpecialMethodKind kind); @@ -1430,13 +1429,11 @@ bool isSpecialUIKitStructZeroProperty(const clang::NamedDecl *decl); /// Add command-line arguments for a normal import of Clang code. void getNormalInvocationArguments(std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts); + ASTContext &ctx); /// Add command-line arguments common to all imports of Clang code. void addCommonInvocationArguments(std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts); + ASTContext &ctx); /// Finds a particular kind of nominal by looking through typealiases. template diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index 74a64dcb025d5..6653b2d0ee38d 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -1857,6 +1857,7 @@ SwiftNameLookupExtension::hashExtension(llvm::hash_code code) const { SWIFT_LOOKUP_TABLE_VERSION_MAJOR, SWIFT_LOOKUP_TABLE_VERSION_MINOR, inferImportAsMember, + swiftCtx.LangOpts.EnableExperimentalConcurrency, version::getSwiftFullVersion()); } @@ -1881,10 +1882,16 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table, // struct names when relevant, not just pointer names. That way we can check // both CFDatabase.def and the objc_bridge attribute and cover all our bases. if (auto *tagDecl = dyn_cast(named)) { - if (!tagDecl->getDefinition()) + // We add entries for ClassTemplateSpecializations that don't have + // definition. It's possible that the decl will be instantiated by + // SwiftDeclConverter later on. We cannot force instantiating + // ClassTemplateSPecializations here because we're currently writing the + // AST, so we cannot modify it. + if (!isa(named) && + !tagDecl->getDefinition()) { return; + } } - // If we have a name to import as, add this entry to the table. auto currentVersion = ImportNameVersion::fromOptions(nameImporter.getLangOpts()); @@ -2077,6 +2084,19 @@ void SwiftLookupTableWriter::populateTableWithDecl(SwiftLookupTable &table, // Add this entry to the lookup table. addEntryToLookupTable(table, named, nameImporter); + if (auto typedefDecl = dyn_cast(named)) { + if (auto typedefType = dyn_cast( + typedefDecl->getUnderlyingType())) { + if (auto CTSD = dyn_cast( + typedefType->getAsTagDecl())) { + // Adding template instantiation behind typedef as a top-level entry + // so the instantiation appears in the API. + assert(!isa(CTSD) && + "Class template partial specialization cannot appear behind typedef"); + addEntryToLookupTable(table, CTSD, nameImporter); + } + } + } } void SwiftLookupTableWriter::populateTable(SwiftLookupTable &table, diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 3628481d8a47e..f49ba90261714 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -2669,7 +2669,7 @@ NodePointer Demangler::demangleSpecAttributes(Node::Kind SpecKind) { } NodePointer Demangler::demangleWitness() { - switch (nextChar()) { + switch (char c = nextChar()) { case 'C': return createWithChild(Node::Kind::EnumCase, popNode(isEntity)); @@ -2811,6 +2811,30 @@ NodePointer Demangler::demangleWitness() { return nullptr; } } + case 'Z': + case 'z': { + auto declList = createNode(Node::Kind::GlobalVariableOnceDeclList); + std::vector vars; + while (auto sig = popNode(Node::Kind::FirstElementMarker)) { + auto identifier = popNode(isDeclName); + if (!identifier) + return nullptr; + vars.push_back(identifier); + } + for (auto i = vars.rbegin(); i != vars.rend(); ++i) { + declList->addChild(*i, *this); + } + + auto context = popContext(); + if (!context) + return nullptr; + Node::Kind kind = c == 'Z' + ? Node::Kind::GlobalVariableOnceFunction + : Node::Kind::GlobalVariableOnceToken; + return createWithChildren(kind, + context, + declList); + } default: return nullptr; } diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index e7ea0e52e29d6..3a7fc824699b2 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -552,6 +552,9 @@ class NodePrinter { case Node::Kind::CanonicalSpecializedGenericTypeMetadataAccessFunction: case Node::Kind::NoncanonicalSpecializedGenericTypeMetadata: case Node::Kind::NoncanonicalSpecializedGenericTypeMetadataCache: + case Node::Kind::GlobalVariableOnceDeclList: + case Node::Kind::GlobalVariableOnceFunction: + case Node::Kind::GlobalVariableOnceToken: return false; } printer_unreachable("bad node kind"); @@ -2466,6 +2469,28 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { Printer << "cache variable for noncanonical specialized generic type metadata for "; print(Node->getChild(0)); return nullptr; + case Node::Kind::GlobalVariableOnceToken: + case Node::Kind::GlobalVariableOnceFunction: + Printer << (kind == Node::Kind::GlobalVariableOnceToken + ? "one-time initialization token for " + : "one-time initialization function for "); + printContext(Node->getChild(0)); + print(Node->getChild(1)); + return nullptr; + case Node::Kind::GlobalVariableOnceDeclList: + if (Node->getNumChildren() == 1) { + print(Node->getChild(0)); + } else { + Printer << '('; + for (unsigned i = 0, e = Node->getNumChildren(); i < e; ++i) { + if (i != 0) { + Printer << ", "; + } + print(Node->getChild(i)); + } + Printer << ')'; + } + return nullptr; } printer_unreachable("bad node kind!"); } diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index ba7ca2eb51960..7df26cbfad047 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -2139,6 +2139,15 @@ void Remangler::mangleAccessorFunctionReference(Node *node) { void Remangler::mangleMetadataInstantiationCache(Node *node) { unreachable("unsupported"); } +void Remangler::mangleGlobalVariableOnceToken(Node *node) { + unreachable("unsupported"); +} +void Remangler::mangleGlobalVariableOnceFunction(Node *node) { + unreachable("unsupported"); +} +void Remangler::mangleGlobalVariableOnceDeclList(Node *node) { + unreachable("unsupported"); +} void Remangler::mangleCanonicalSpecializedGenericMetaclass(Node *node) { Buffer << "MM"; diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 60dfeafaee925..8abad3f38cf0f 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -2566,6 +2566,23 @@ void Remangler::mangleNoncanonicalSpecializedGenericTypeMetadataCache(Node *node Buffer << "MJ"; } +void Remangler::mangleGlobalVariableOnceToken(Node *node) { + mangleChildNodes(node); + Buffer << "Wz"; +} + +void Remangler::mangleGlobalVariableOnceFunction(Node *node) { + mangleChildNodes(node); + Buffer << "WZ"; +} + +void Remangler::mangleGlobalVariableOnceDeclList(Node *node) { + for (unsigned i = 0, e = node->getNumChildren(); i < e; ++i) { + mangle(node->getChild(i)); + Buffer << '_'; + } +} + } // anonymous namespace /// The top-level interface to the remangler. diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index 0dcde774e73f8..25117800eed96 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -33,6 +33,7 @@ const char *Action::getClassName(Kind AC) { case Kind::GenerateDSYMJob: return "generate-dSYM"; case Kind::VerifyDebugInfoJob: return "verify-debug-info"; case Kind::GeneratePCHJob: return "generate-pch"; + case Kind::VerifyModuleInterfaceJob: return "verify-module-interface"; } llvm_unreachable("invalid class"); @@ -65,3 +66,5 @@ void GenerateDSYMJobAction::anchor() {} void VerifyDebugInfoJobAction::anchor() {} void GeneratePCHJobAction::anchor() {} + +void VerifyModuleInterfaceJobAction::anchor() {} diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 74640ed9ac387..72f55d8a712ca 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -1990,6 +1990,7 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftOverlayFile: case file_types::TY_JSONDependencies: @@ -2194,6 +2195,30 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, TopLevelActions.push_back(MergeModuleAction); TopLevelActions.append(AllLinkerInputs.begin(), AllLinkerInputs.end()); } + +#ifdef NDEBUG + bool verifyInterfacesByDefault = false; +#else + bool verifyInterfacesByDefault = true; +#endif + + if (MergeModuleAction + && Args.hasFlag(options::OPT_verify_emitted_module_interface, + options::OPT_no_verify_emitted_module_interface, + verifyInterfacesByDefault)) { + if (Args.hasArgNoClaim(options::OPT_emit_module_interface, + options::OPT_emit_module_interface_path)) { + TopLevelActions.push_back( + C.createAction(MergeModuleAction, + file_types::TY_SwiftModuleInterfaceFile)); + } + + if (Args.hasArgNoClaim(options::OPT_emit_private_module_interface_path)) { + TopLevelActions.push_back( + C.createAction(MergeModuleAction, + file_types::TY_PrivateSwiftModuleInterfaceFile)); + } + } } bool Driver::handleImmediateArgs(const ArgList &Args, const ToolChain &TC) { @@ -2817,6 +2842,10 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA, Output.get()); } + if (isa(JA)) { + chooseModuleSummaryPath(C, OutputMap, workingDirectory, Buf, Output.get()); + } + if (isa(JA) || (isa(JA) && OI.CompilerMode == OutputInfo::Mode::SingleCompile)) { @@ -3170,6 +3199,22 @@ void Driver::chooseModuleInterfacePath(Compilation &C, const JobAction *JA, output->setAdditionalOutputForType(fileType, outputPath); } +void Driver::chooseModuleSummaryPath(Compilation &C, + const TypeToPathMap *OutputMap, + StringRef workingDirectory, + llvm::SmallString<128> &Buf, + CommandOutput *Output) const { + StringRef pathFromArgs; + if (const Arg *A = + C.getArgs().getLastArg(options::OPT_emit_module_summary_path)) { + pathFromArgs = A->getValue(); + } + + addAuxiliaryOutput(C, *Output, file_types::TY_SwiftModuleSummaryFile, + OutputMap, workingDirectory, pathFromArgs, + /*requireArg=*/options::OPT_emit_module_summary); +} + void Driver::chooseSerializedDiagnosticsPath(Compilation &C, const JobAction *JA, const TypeToPathMap *OutputMap, diff --git a/lib/Driver/FrontendUtil.cpp b/lib/Driver/FrontendUtil.cpp index 7d796ddfc722c..75b95de1b6d0f 100644 --- a/lib/Driver/FrontendUtil.cpp +++ b/lib/Driver/FrontendUtil.cpp @@ -20,6 +20,7 @@ #include "swift/Driver/ToolChain.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Host.h" #include "llvm/Support/StringSaver.h" using namespace swift; diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 784348922f6fb..522a9727c454a 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -111,6 +111,7 @@ std::unique_ptr ToolChain::constructJob( CASE(GeneratePCHJob) CASE(AutolinkExtractJob) CASE(REPLJob) + CASE(VerifyModuleInterfaceJob) #undef CASE case Action::Kind::Input: llvm_unreachable("not a JobAction"); diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index d92cb1c568bc4..771f32290e7d6 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -212,7 +212,6 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_require_explicit_availability_target); inputArgs.AddLastArg(arguments, options::OPT_enable_testing); inputArgs.AddLastArg(arguments, options::OPT_enable_private_imports); - inputArgs.AddLastArg(arguments, options::OPT_enable_cxx_interop); inputArgs.AddLastArg(arguments, options::OPT_g_Group); inputArgs.AddLastArg(arguments, options::OPT_debug_info_format); inputArgs.AddLastArg(arguments, options::OPT_import_underlying_module); @@ -260,8 +259,6 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_debug_diagnostic_names); inputArgs.AddLastArg(arguments, options::OPT_print_educational_notes); inputArgs.AddLastArg(arguments, options::OPT_diagnostic_style); - inputArgs.AddLastArg(arguments, options::OPT_enable_astscope_lookup); - inputArgs.AddLastArg(arguments, options::OPT_disable_astscope_lookup); inputArgs.AddLastArg(arguments, options::OPT_disable_parser_lookup); inputArgs.AddLastArg(arguments, options::OPT_enable_experimental_concise_pound_file); @@ -621,6 +618,7 @@ const char *ToolChain::JobContext::computeFrontendModeForCompile() const { case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftOverlayFile: @@ -766,6 +764,9 @@ void ToolChain::JobContext::addFrontendSupplementaryOutputArguments( "-emit-loaded-module-trace-path"); addOutputsOfType(arguments, Output, Args, file_types::TY_TBD, "-emit-tbd-path"); + addOutputsOfType(arguments, Output, Args, + file_types::TY_SwiftModuleSummaryFile, + "-emit-module-summary-path"); } ToolChain::InvocationInfo @@ -878,6 +879,7 @@ ToolChain::constructInvocation(const BackendJobAction &job, case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftOverlayFile: @@ -1047,6 +1049,41 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job, return II; } +ToolChain::InvocationInfo +ToolChain::constructInvocation(const VerifyModuleInterfaceJobAction &job, + const JobContext &context) const { + InvocationInfo II{SWIFT_EXECUTABLE_NAME}; + ArgStringList &Arguments = II.Arguments; + II.allowsResponseFiles = true; + + for (auto &s : getDriver().getSwiftProgramArgs()) + Arguments.push_back(s.c_str()); + Arguments.push_back("-frontend"); + + Arguments.push_back("-typecheck-module-from-interface"); + + size_t sizeBefore = Arguments.size(); + addInputsOfType(Arguments, context.Inputs, context.Args, job.getInputType()); + + (void)sizeBefore; + assert(Arguments.size() - sizeBefore == 1 && + "should verify exactly one module interface per job"); + + addCommonFrontendArgs(context.OI, context.Output, context.Args, Arguments); + addRuntimeLibraryFlags(context.OI, Arguments); + + addOutputsOfType(Arguments, context.Output, context.Args, + file_types::TY_SerializedDiagnostics, + "-serialize-diagnostics-path"); + + context.Args.AddLastArg(Arguments, options::OPT_import_objc_header); + + Arguments.push_back("-module-name"); + Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName)); + + return II; +} + ToolChain::InvocationInfo ToolChain::constructInvocation(const ModuleWrapJobAction &job, const JobContext &context) const { diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 05b0ed04f5083..7ab50175bc688 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -147,7 +147,8 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.RequestedAction = determineRequestedAction(Args); } - if (Opts.RequestedAction == FrontendOptions::ActionType::CompileModuleFromInterface) { + if (Opts.RequestedAction == FrontendOptions::ActionType::CompileModuleFromInterface || + Opts.RequestedAction == FrontendOptions::ActionType::TypecheckModuleFromInterface) { // The situations where we use this action, e.g. explicit module building and // generating prebuilt module cache, don't need synchronization. We should avoid // using lock files for them. @@ -354,6 +355,8 @@ ArgsToFrontendOptionsConverter::determineRequestedAction(const ArgList &args) { return FrontendOptions::ActionType::EmitImportedModules; if (Opt.matches(OPT_scan_dependencies)) return FrontendOptions::ActionType::ScanDependencies; + if (Opt.matches(OPT_scan_clang_dependencies)) + return FrontendOptions::ActionType::ScanClangDependencies; if (Opt.matches(OPT_parse)) return FrontendOptions::ActionType::Parse; if (Opt.matches(OPT_resolve_imports)) @@ -389,6 +392,8 @@ ArgsToFrontendOptionsConverter::determineRequestedAction(const ArgList &args) { return FrontendOptions::ActionType::Immediate; if (Opt.matches(OPT_compile_module_from_interface)) return FrontendOptions::ActionType::CompileModuleFromInterface; + if (Opt.matches(OPT_typecheck_module_from_interface)) + return FrontendOptions::ActionType::TypecheckModuleFromInterface; llvm_unreachable("Unhandled mode option"); } @@ -401,8 +406,7 @@ bool ArgsToFrontendOptionsConverter::setUpInputKindAndImmediateArgs() { if (Opts.InputsAndOutputs.verifyInputs( Diags, treatAsSIL, Opts.RequestedAction == FrontendOptions::ActionType::REPL, - (Opts.RequestedAction == FrontendOptions::ActionType::NoneAction || - Opts.RequestedAction == FrontendOptions::ActionType::PrintVersion))){ + !FrontendOptions::doesActionRequireInputs(Opts.RequestedAction))) { return true; } if (Opts.RequestedAction == FrontendOptions::ActionType::Immediate) { @@ -560,6 +564,11 @@ bool ArgsToFrontendOptionsConverter::checkUnusedSupplementaryOutputPaths() Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_interface); return true; } + if (!FrontendOptions::canActionEmitModuleSummary(Opts.RequestedAction) && + Opts.InputsAndOutputs.hasModuleSummaryOutputPath()) { + Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module_summary); + return true; + } return false; } diff --git a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp index ef9f200ccdd42..37b5afee63aba 100644 --- a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp @@ -306,11 +306,13 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() options::OPT_emit_module_source_info_path); auto ldAddCFileOutput = getSupplementaryFilenamesFromArguments( options::OPT_emit_ldadd_cfile_path); + auto moduleSummaryOutput = getSupplementaryFilenamesFromArguments( + options::OPT_emit_module_summary_path); if (!objCHeaderOutput || !moduleOutput || !moduleDocOutput || !dependenciesFile || !referenceDependenciesFile || !serializedDiagnostics || !fixItsOutput || !loadedModuleTrace || !TBD || !moduleInterfaceOutput || !privateModuleInterfaceOutput || - !moduleSourceInfoOutput || !ldAddCFileOutput) { + !moduleSourceInfoOutput || !ldAddCFileOutput || !moduleSummaryOutput) { return None; } std::vector result; @@ -334,6 +336,7 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() sop.PrivateModuleInterfaceOutputPath = (*privateModuleInterfaceOutput)[i]; sop.ModuleSourceInfoOutputPath = (*moduleSourceInfoOutput)[i]; sop.LdAddCFilePath = (*ldAddCFileOutput)[i]; + sop.ModuleSummaryOutputPath = (*moduleSummaryOutput)[i]; result.push_back(sop); } return result; @@ -422,6 +425,10 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput( OPT_emit_module_source_info, pathsFromArguments.ModuleSourceInfoOutputPath, file_types::TY_SwiftSourceInfoFile, "", defaultSupplementaryOutputPathExcludingExtension); + auto moduleSummaryOutputPath = determineSupplementaryOutputFilename( + OPT_emit_module_summary, pathsFromArguments.ModuleSummaryOutputPath, + file_types::TY_SwiftModuleSummaryFile, "", + defaultSupplementaryOutputPathExcludingExtension); // There is no non-path form of -emit-interface-path auto ModuleInterfaceOutputPath = @@ -456,6 +463,7 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput( sop.PrivateModuleInterfaceOutputPath = PrivateModuleInterfaceOutputPath; sop.ModuleSourceInfoOutputPath = moduleSourceInfoOutputPath; sop.LdAddCFilePath = pathsFromArguments.LdAddCFilePath; + sop.ModuleSummaryOutputPath = moduleSummaryOutputPath; return sop; } @@ -537,6 +545,7 @@ createFromTypeToPathMap(const TypeToPathMap *map) { {file_types::TY_TBD, paths.TBDPath}, {file_types::TY_SwiftModuleInterfaceFile, paths.ModuleInterfaceOutputPath}, + {file_types::TY_SwiftModuleSummaryFile, paths.ModuleSummaryOutputPath}, {file_types::TY_PrivateSwiftModuleInterfaceFile, paths.PrivateModuleInterfaceOutputPath}}; for (const std::pair &typeAndString : diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 0cb3c72b15b96..08988f9a078ee 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -23,6 +23,7 @@ target_link_libraries(swiftFrontend PRIVATE swiftSILGen swiftSILOptimizer swiftIRGen + swiftLocalization swiftSema swiftSerialization swiftTBDGen) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 32ba70f163950..2019dba1c8b83 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -108,11 +108,11 @@ void CompilerInvocation::setDefaultPrebuiltCacheIfNecessary() { llvm::sys::path::append(defaultPrebuiltPathWithSDKVer, ver->getAsString()); // If the versioned prebuilt module cache exists in the disk, use it. if (llvm::sys::fs::exists(defaultPrebuiltPathWithSDKVer)) { - FrontendOpts.PrebuiltModuleCachePath = defaultPrebuiltPathWithSDKVer.str(); + FrontendOpts.PrebuiltModuleCachePath = std::string(defaultPrebuiltPathWithSDKVer.str()); return; } } - FrontendOpts.PrebuiltModuleCachePath = defaultPrebuiltPath.str(); + FrontendOpts.PrebuiltModuleCachePath = std::string(defaultPrebuiltPath.str()); } static void updateRuntimeLibraryPaths(SearchPathOptions &SearchPathOpts, @@ -325,6 +325,8 @@ static void ParseModuleInterfaceArgs(ModuleInterfaceOptions &Opts, Args.hasArg(OPT_experimental_print_full_convention); Opts.ExperimentalSPIImports |= Args.hasArg(OPT_experimental_spi_imports); + Opts.DebugPrintInvalidSyntax |= + Args.hasArg(OPT_debug_emit_invalid_swiftinterface_syntax); } /// Save a copy of any flags marked as ModuleInterfaceOption, if running @@ -441,15 +443,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, } Opts.DisableParserLookup |= Args.hasArg(OPT_disable_parser_lookup); - Opts.EnableASTScopeLookup = - Args.hasFlag(options::OPT_enable_astscope_lookup, - options::OPT_disable_astscope_lookup, Opts.EnableASTScopeLookup) || - Opts.DisableParserLookup; - Opts.CrosscheckUnqualifiedLookup |= - Args.hasArg(OPT_crosscheck_unqualified_lookup); Opts.StressASTScopeLookup |= Args.hasArg(OPT_stress_astscope_lookup); - Opts.WarnIfASTScopeLookup |= Args.hasArg(OPT_warn_if_astscope_lookup); - Opts.LazyASTScopes |= Args.hasArg(OPT_lazy_astscopes); Opts.EnableNewOperatorLookup = Args.hasFlag(OPT_enable_new_operator_lookup, OPT_disable_new_operator_lookup, /*default*/ false); @@ -913,7 +907,8 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, } if (const Arg *A = Args.getLastArg(OPT_placeholder_dependency_module_map)) Opts.PlaceholderDependencyModuleMap = A->getValue(); - + if (const Arg *A = Args.getLastArg(OPT_batch_scan_input_file)) + Opts.BatchScanInputFilePath = A->getValue(); // Opts.RuntimeIncludePath is set by calls to // setRuntimeIncludePath() or setMainExecutablePath(). // Opts.RuntimeImportPath is set by calls to @@ -1112,6 +1107,8 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, Opts.AssumeSingleThreaded = true; } + Opts.IgnoreAlwaysInline |= Args.hasArg(OPT_ignore_always_inline); + // Parse the assert configuration identifier. if (const Arg *A = Args.getLastArg(OPT_AssertConfig)) { StringRef Configuration = A->getValue(); diff --git a/lib/Frontend/DependencyVerifier.cpp b/lib/Frontend/DependencyVerifier.cpp index b8950be51032d..2e468f83de842 100644 --- a/lib/Frontend/DependencyVerifier.cpp +++ b/lib/Frontend/DependencyVerifier.cpp @@ -481,71 +481,50 @@ bool DependencyVerifier::verifyObligations( auto &diags = SF->getASTContext().Diags; for (auto &expectation : ExpectedDependencies) { const bool wantsCascade = expectation.isCascading(); - switch (expectation.Info.Kind) { - case Expectation::Kind::Negative: + if (expectation.Info.Kind == Expectation::Kind::Negative) { // We'll verify negative expectations separately. NegativeExpectations.insert({expectation.MessageRange, expectation}); - break; - case Expectation::Kind::Member: - matchExpectationOrFail( - OM, expectation, - [&](Obligation &p) { - const auto haveCascade = p.getCascades(); + continue; + } + + matchExpectationOrFail( + OM, expectation, + [&](Obligation &O) { + const auto haveCascade = O.getCascades(); + switch (expectation.Info.Kind) { + case Expectation::Kind::Negative: + llvm_unreachable("Should have been handled above!"); + case Expectation::Kind::Member: if (haveCascade != wantsCascade) { diagnose(diags, expectation.MessageRange.begin(), diag::dependency_cascading_mismatch, wantsCascade, haveCascade); - return p.fail(); + return O.fail(); + } else { + return O.fullfill(); } - - return p.fullfill(); - }, - [&](const Expectation &e) { - diagnose( - diags, e.MessageRange.begin(), diag::missing_member_dependency, - static_cast(expectation.Info.Kind), e.MessageRange); - }); - break; - case Expectation::Kind::PotentialMember: - matchExpectationOrFail( - OM, expectation, - [&](Obligation &p) { - assert(p.getName().empty()); - const auto haveCascade = p.getCascades(); + case Expectation::Kind::PotentialMember: + assert(O.getName().empty()); if (haveCascade != wantsCascade) { diagnose(diags, expectation.MessageRange.begin(), diag::potential_dependency_cascading_mismatch, wantsCascade, haveCascade); - return p.fail(); + return O.fail(); + } else { + return O.fullfill(); } - - return p.fullfill(); - }, - [&](const Expectation &e) { - diagnose( - diags, e.MessageRange.begin(), diag::missing_member_dependency, - static_cast(expectation.Info.Kind), e.MessageRange); - }); - break; - case Expectation::Kind::Provides: - matchExpectationOrFail( - OM, expectation, [](Obligation &O) { return O.fullfill(); }, - [&](const Expectation &e) { - diagnose( - diags, e.MessageRange.begin(), diag::missing_member_dependency, - static_cast(expectation.Info.Kind), e.MessageRange); - }); - break; - case Expectation::Kind::DynamicMember: - matchExpectationOrFail( - OM, expectation, [](Obligation &O) { return O.fullfill(); }, - [&](const Expectation &e) { - diagnose( - diags, e.MessageRange.begin(), diag::missing_member_dependency, - static_cast(expectation.Info.Kind), e.MessageRange); - }); - break; - } + case Expectation::Kind::Provides: + case Expectation::Kind::DynamicMember: + return O.fullfill(); + } + + llvm_unreachable("Unhandled expectation kind!"); + }, + [&](const Expectation &e) { + diagnose(diags, e.MessageRange.begin(), + diag::missing_member_dependency, + static_cast(expectation.Info.Kind), e.MessageRange); + }); } return false; diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 7e000a0b6a563..5efc9c5571e43 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -33,6 +33,7 @@ #include "swift/SILOptimizer/Utils/Generics.h" #include "swift/Serialization/SerializationOptions.h" #include "swift/Serialization/SerializedModuleLoader.h" +#include "swift/Serialization/ModuleDependencyScanner.h" #include "swift/Strings.h" #include "swift/Subsystems.h" #include "clang/AST/ASTContext.h" @@ -192,7 +193,9 @@ void CompilerInstance::recordPrimaryInputBuffer(unsigned BufID) { bool CompilerInstance::setUpASTContextIfNeeded() { if (Invocation.getFrontendOptions().RequestedAction == - FrontendOptions::ActionType::CompileModuleFromInterface) { + FrontendOptions::ActionType::CompileModuleFromInterface || + Invocation.getFrontendOptions().RequestedAction == + FrontendOptions::ActionType::TypecheckModuleFromInterface) { // Compiling a module interface from source uses its own CompilerInstance // with options read from the input file. Don't bother setting up an // ASTContext at this level. @@ -201,7 +204,9 @@ bool CompilerInstance::setUpASTContextIfNeeded() { Context.reset(ASTContext::get( Invocation.getLangOptions(), Invocation.getTypeCheckerOptions(), - Invocation.getSearchPathOptions(), SourceMgr, Diagnostics)); + Invocation.getSearchPathOptions(), + Invocation.getClangImporterOptions(), + SourceMgr, Diagnostics)); registerParseRequestFunctions(Context->evaluator); registerTypeCheckerRequestFunctions(Context->evaluator); registerSILGenRequestFunctions(Context->evaluator); @@ -478,8 +483,8 @@ bool CompilerInstance::setUpModuleLoaders() { // Otherwise, we just keep it around as our interface to Clang's ABI // knowledge. std::unique_ptr clangImporter = - ClangImporter::create(*Context, Invocation.getClangImporterOptions(), - Invocation.getPCHHash(), getDependencyTracker()); + ClangImporter::create(*Context, Invocation.getPCHHash(), + getDependencyTracker()); if (!clangImporter) { Diagnostics.diagnose(SourceLoc(), diag::error_clang_importer_create_fail); return true; @@ -520,9 +525,36 @@ bool CompilerInstance::setUpModuleLoaders() { this->DefaultSerializedLoader = ISML.get(); Context->addModuleLoader(std::move(ISML)); } - + Context->addModuleLoader(std::move(clangImporter), /*isClang*/ true); + // When scanning for dependencies, we must add the scanner loaders in order to handle + // ASTContext operations such as canImportModule + if (Invocation.getFrontendOptions().RequestedAction == + FrontendOptions::ActionType::ScanDependencies) { + auto ModuleCachePath = getModuleCachePathFromClang(Context + ->getClangModuleLoader()->getClangInstance()); + auto &FEOpts = Invocation.getFrontendOptions(); + ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); + InterfaceSubContextDelegateImpl ASTDelegate(Context->SourceMgr, Context->Diags, + Context->SearchPathOpts, Context->LangOpts, + Context->ClangImporterOpts, + LoaderOpts, + /*buildModuleCacheDirIfAbsent*/false, + ModuleCachePath, + FEOpts.PrebuiltModuleCachePath, + FEOpts.SerializeModuleInterfaceDependencyHashes, + FEOpts.shouldTrackSystemDependencies()); + auto mainModuleName = Context->getIdentifier(FEOpts.ModuleName); + std::unique_ptr PSMS = + std::make_unique(*Context, + MLM, + mainModuleName, + Context->SearchPathOpts.PlaceholderDependencyModuleMap, + ASTDelegate); + Context->addModuleLoader(std::move(PSMS)); + } + return false; } @@ -818,7 +850,7 @@ void CompilerInstance::setMainModule(ModuleDecl *newMod) { Context->addLoadedModule(newMod); } -void CompilerInstance::performParseAndResolveImportsOnly() { +bool CompilerInstance::performParseAndResolveImportsOnly() { FrontendStatsTracer tracer(getStatsReporter(), "parse-and-resolve-imports"); // Resolve imports for all the source files. @@ -837,6 +869,7 @@ void CompilerInstance::performParseAndResolveImportsOnly() { mainModule->setHasResolvedImports(); bindExtensions(*mainModule); + return Context->hadError(); } void CompilerInstance::performSema() { diff --git a/lib/Frontend/FrontendInputsAndOutputs.cpp b/lib/Frontend/FrontendInputsAndOutputs.cpp index edb0bbdc6c273..52d1e823f6f1f 100644 --- a/lib/Frontend/FrontendInputsAndOutputs.cpp +++ b/lib/Frontend/FrontendInputsAndOutputs.cpp @@ -466,6 +466,12 @@ bool FrontendInputsAndOutputs::hasPrivateModuleInterfaceOutputPath() const { return outs.PrivateModuleInterfaceOutputPath; }); } +bool FrontendInputsAndOutputs::hasModuleSummaryOutputPath() const { + return hasSupplementaryOutputPath( + [](const SupplementaryOutputPaths &outs) -> const std::string & { + return outs.ModuleSummaryOutputPath; + }); +} bool FrontendInputsAndOutputs::hasTBDPath() const { return hasSupplementaryOutputPath( [](const SupplementaryOutputPaths &outs) -> const std::string & { diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 1e1253ddcb6c5..20e0e8434d4a8 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -51,6 +51,7 @@ bool FrontendOptions::needsProperModuleName(ActionType action) { case ActionType::EmitModuleOnly: case ActionType::MergeModules: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: return true; case ActionType::Immediate: case ActionType::REPL: @@ -64,6 +65,7 @@ bool FrontendOptions::needsProperModuleName(ActionType action) { case ActionType::DumpTypeInfo: case ActionType::EmitPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: return true; } llvm_unreachable("Unknown ActionType"); @@ -71,19 +73,104 @@ bool FrontendOptions::needsProperModuleName(ActionType action) { bool FrontendOptions::shouldActionOnlyParse(ActionType action) { switch (action) { - case FrontendOptions::ActionType::Parse: - case FrontendOptions::ActionType::DumpParse: - case FrontendOptions::ActionType::EmitSyntax: - case FrontendOptions::ActionType::DumpInterfaceHash: - case FrontendOptions::ActionType::EmitImportedModules: - case FrontendOptions::ActionType::ScanDependencies: - case FrontendOptions::ActionType::PrintVersion: + case ActionType::Parse: + case ActionType::DumpParse: + case ActionType::EmitSyntax: + case ActionType::DumpInterfaceHash: + case ActionType::EmitImportedModules: + case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: + case ActionType::PrintVersion: return true; default: return false; } } +bool FrontendOptions::doesActionRequireSwiftStandardLibrary(ActionType action) { + switch (action) { + case ActionType::NoneAction: + case ActionType::Parse: + case ActionType::DumpParse: + case ActionType::EmitSyntax: + case ActionType::DumpInterfaceHash: + case ActionType::EmitImportedModules: + case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: + case ActionType::PrintVersion: + case ActionType::EmitPCH: + case ActionType::EmitPCM: + case ActionType::DumpPCM: + case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: + return false; + case ActionType::ResolveImports: + case ActionType::Typecheck: + case ActionType::DumpAST: + case ActionType::PrintAST: + case ActionType::DumpScopeMaps: + case ActionType::DumpTypeRefinementContexts: + case ActionType::EmitSILGen: + case ActionType::EmitSIL: + case ActionType::EmitModuleOnly: + case ActionType::MergeModules: + case ActionType::EmitSIBGen: + case ActionType::EmitSIB: + case ActionType::Immediate: + case ActionType::REPL: + case ActionType::EmitAssembly: + case ActionType::EmitIR: + case ActionType::EmitBC: + case ActionType::EmitObject: + case ActionType::DumpTypeInfo: + assert(!FrontendOptions::shouldActionOnlyParse(action) && + "Parse-only actions should not load modules!"); + return true; + } + llvm_unreachable("Unknown ActionType"); +} + +bool FrontendOptions::doesActionRequireInputs(ActionType action) { + switch (action) { + case ActionType::NoneAction: + case ActionType::PrintVersion: + return false; + case ActionType::REPL: + case ActionType::Parse: + case ActionType::DumpParse: + case ActionType::EmitSyntax: + case ActionType::DumpInterfaceHash: + case ActionType::EmitImportedModules: + case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: + case ActionType::EmitPCH: + case ActionType::EmitPCM: + case ActionType::DumpPCM: + case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: + case ActionType::ResolveImports: + case ActionType::Typecheck: + case ActionType::DumpAST: + case ActionType::PrintAST: + case ActionType::DumpScopeMaps: + case ActionType::DumpTypeRefinementContexts: + case ActionType::EmitSILGen: + case ActionType::EmitSIL: + case ActionType::EmitModuleOnly: + case ActionType::MergeModules: + case ActionType::EmitSIBGen: + case ActionType::EmitSIB: + case ActionType::Immediate: + case ActionType::EmitAssembly: + case ActionType::EmitIR: + case ActionType::EmitBC: + case ActionType::EmitObject: + case ActionType::DumpTypeInfo: + return true; + } + llvm_unreachable("Unknown ActionType"); +} + void FrontendOptions::forAllOutputPaths( const InputFile &input, llvm::function_ref fn) const { if (RequestedAction != FrontendOptions::ActionType::EmitModuleOnly && @@ -118,6 +205,7 @@ FrontendOptions::formatForPrincipalOutputFileForAction(ActionType action) { case ActionType::Parse: case ActionType::ResolveImports: case ActionType::Typecheck: + case ActionType::TypecheckModuleFromInterface: case ActionType::DumpParse: case ActionType::DumpInterfaceHash: case ActionType::DumpAST: @@ -174,6 +262,7 @@ FrontendOptions::formatForPrincipalOutputFileForAction(ActionType action) { return TY_ClangModuleFile; case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: return TY_JSONDependencies; } llvm_unreachable("unhandled action"); @@ -192,6 +281,7 @@ bool FrontendOptions::canActionEmitDependencies(ActionType action) { case ActionType::DumpTypeRefinementContexts: case ActionType::DumpTypeInfo: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::DumpPCM: @@ -213,6 +303,7 @@ bool FrontendOptions::canActionEmitDependencies(ActionType action) { case ActionType::EmitImportedModules: case ActionType::EmitPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: return true; } llvm_unreachable("unhandled action"); @@ -232,11 +323,13 @@ bool FrontendOptions::canActionEmitReferenceDependencies(ActionType action) { case ActionType::DumpTypeRefinementContexts: case ActionType::DumpTypeInfo: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::Typecheck: @@ -265,6 +358,47 @@ bool FrontendOptions::canActionEmitCompiledSource(ActionType action) { return canActionEmitReferenceDependencies(action); } +bool FrontendOptions::canActionEmitModuleSummary(ActionType action) { + switch (action) { + case ActionType::NoneAction: + case ActionType::Parse: + case ActionType::ResolveImports: + case ActionType::DumpParse: + case ActionType::DumpInterfaceHash: + case ActionType::DumpAST: + case ActionType::EmitSyntax: + case ActionType::PrintAST: + case ActionType::EmitImportedModules: + case ActionType::EmitPCH: + case ActionType::DumpScopeMaps: + case ActionType::DumpTypeRefinementContexts: + case ActionType::DumpTypeInfo: + case ActionType::EmitSILGen: + case ActionType::EmitSIBGen: + case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: + case ActionType::Immediate: + case ActionType::REPL: + case ActionType::EmitPCM: + case ActionType::DumpPCM: + case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: + case ActionType::Typecheck: + case ActionType::MergeModules: + case ActionType::EmitModuleOnly: + case ActionType::PrintVersion: + return false; + case ActionType::EmitSIL: + case ActionType::EmitSIB: + case ActionType::EmitIR: + case ActionType::EmitBC: + case ActionType::EmitAssembly: + case ActionType::EmitObject: + return true; + } + llvm_unreachable("unhandled action"); +} + bool FrontendOptions::canActionEmitObjCHeader(ActionType action) { switch (action) { case ActionType::NoneAction: @@ -280,11 +414,13 @@ bool FrontendOptions::canActionEmitObjCHeader(ActionType action) { case ActionType::DumpTypeRefinementContexts: case ActionType::DumpTypeInfo: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::Typecheck: @@ -317,11 +453,13 @@ bool FrontendOptions::canActionEmitLoadedModuleTrace(ActionType action) { case ActionType::DumpTypeRefinementContexts: case ActionType::DumpTypeInfo: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::ResolveImports: @@ -360,11 +498,13 @@ bool FrontendOptions::canActionEmitModule(ActionType action) { case ActionType::DumpTypeInfo: case ActionType::EmitSILGen: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::MergeModules: @@ -404,11 +544,13 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) { case ActionType::EmitSILGen: case ActionType::EmitSIBGen: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: return false; case ActionType::Typecheck: case ActionType::MergeModules: @@ -450,10 +592,12 @@ bool FrontendOptions::doesActionProduceOutput(ActionType action) { case ActionType::EmitImportedModules: case ActionType::MergeModules: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::DumpTypeInfo: case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: return true; case ActionType::NoneAction: @@ -484,6 +628,7 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) { case ActionType::Parse: case ActionType::ResolveImports: case ActionType::Typecheck: + case ActionType::TypecheckModuleFromInterface: case ActionType::DumpParse: case ActionType::DumpInterfaceHash: case ActionType::DumpAST: @@ -499,6 +644,7 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) { case ActionType::DumpTypeInfo: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return true; } @@ -521,9 +667,11 @@ bool FrontendOptions::doesActionGenerateSIL(ActionType action) { case ActionType::EmitImportedModules: case ActionType::EmitPCH: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::EmitSILGen: @@ -557,6 +705,7 @@ bool FrontendOptions::doesActionGenerateIR(ActionType action) { case ActionType::DumpTypeRefinementContexts: case ActionType::DumpTypeInfo: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Typecheck: case ActionType::ResolveImports: case ActionType::MergeModules: @@ -570,6 +719,7 @@ bool FrontendOptions::doesActionGenerateIR(ActionType action) { case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::Immediate: diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 4e118f04c0e5a..58ba8c45ef46b 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -161,10 +161,10 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( llvm::RestorePrettyStackState(savedInnerPrettyStackState); }; - SubError = subASTDelegate.runInSubCompilerInstance(moduleName, - interfacePath, - OutPath, - diagnosticLoc, + SubError = (bool)subASTDelegate.runInSubCompilerInstance(moduleName, + interfacePath, + OutPath, + diagnosticLoc, [&](SubCompilerInstanceInfo &info) { auto &SubInstance = *info.Instance; auto subInvocation = SubInstance.getInvocation(); @@ -173,9 +173,11 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( .getModuleInterfaceLoader())->tryEmitForwardingModule(moduleName, interfacePath, CompiledCandidates, OutPath)) { - return false; + return std::error_code(); } FrontendOptions &FEOpts = subInvocation.getFrontendOptions(); + bool isTypeChecking = + (FEOpts.RequestedAction == FrontendOptions::ActionType::Typecheck); const auto &InputInfo = FEOpts.InputsAndOutputs.firstInput(); StringRef InPath = InputInfo.file(); const auto &OutputInfo = @@ -198,9 +200,9 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( getSwiftInterfaceCompilerVersionForCurrentCompiler( SubInstance.getASTContext()); StringRef emittedByCompiler = info.CompilerVersion; - diagnose(diag::module_interface_build_failed, moduleName, - emittedByCompiler == builtByCompiler, emittedByCompiler, - builtByCompiler); + diagnose(diag::module_interface_build_failed, isTypeChecking, + moduleName, emittedByCompiler == builtByCompiler, + emittedByCompiler, builtByCompiler); } }; @@ -208,7 +210,7 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( SubInstance.performSema(); if (SubInstance.getASTContext().hadError()) { LLVM_DEBUG(llvm::dbgs() << "encountered errors\n"); - return true; + return std::make_error_code(std::errc::not_supported); } SILOptions &SILOpts = subInvocation.getSILOptions(); @@ -217,7 +219,7 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( auto SILMod = performASTLowering(Mod, TC, SILOpts); if (!SILMod) { LLVM_DEBUG(llvm::dbgs() << "SILGen did not produce a module\n"); - return true; + return std::make_error_code(std::errc::not_supported); } // Setup the callbacks for serialization, which can occur during the @@ -237,11 +239,14 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( SmallVector Deps; bool serializeHashes = FEOpts.SerializeModuleInterfaceDependencyHashes; if (collectDepsForSerialization(SubInstance, Deps, serializeHashes)) { - return true; + return std::make_error_code(std::errc::not_supported); } if (ShouldSerializeDeps) SerializationOpts.Dependencies = Deps; SILMod->setSerializeSILAction([&]() { + if (isTypeChecking) + return; + // We don't want to serialize module docs in the cache -- they // will be serialized beside the interface file. serializeToBuffers(Mod, SerializationOpts, ModuleBuffer, @@ -253,9 +258,12 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( LLVM_DEBUG(llvm::dbgs() << "Running SIL processing passes\n"); if (SubInstance.performSILProcessing(SILMod.get())) { LLVM_DEBUG(llvm::dbgs() << "encountered errors\n"); - return true; + return std::make_error_code(std::errc::not_supported); + } + if (SubInstance.getDiags().hadAnyError()) { + return std::make_error_code(std::errc::not_supported); } - return SubInstance.getDiags().hadAnyError(); + return std::error_code(); }); }); return !RunSuccess || SubError; diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index fed69f9a43f13..1f2df7b25a0c8 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -286,10 +286,18 @@ struct ModuleRebuildInfo { /// Emits a diagnostic for all out-of-date compiled or forwarding modules /// encountered while trying to load a module. void diagnose(ASTContext &ctx, SourceLoc loc, StringRef moduleName, - StringRef interfacePath) { + StringRef interfacePath, StringRef prebuiltCacheDir) { ctx.Diags.diagnose(loc, diag::rebuilding_module_from_interface, moduleName, interfacePath); - + auto SDKVer = getSDKBuildVersion(ctx.SearchPathOpts.SDKPath); + llvm::SmallString<64> buffer = prebuiltCacheDir; + llvm::sys::path::append(buffer, "SystemVersion.plist"); + auto PBMVer = getSDKBuildVersionFromPlist(buffer.str()); + if (!SDKVer.empty() && !PBMVer.empty()) { + // Remark the potential version difference. + ctx.Diags.diagnose(loc, diag::sdk_version_pbm_version, SDKVer, + PBMVer); + } // We may have found multiple failing modules, that failed for different // reasons. Emit a note for each of them. for (auto &mod : outOfDateModules) { @@ -624,7 +632,7 @@ class ModuleInterfaceLoaderImpl { if (shouldLoadAdjacentModule) { if (fs.exists(modulePath)) { - result.first = modulePath; + result.first = modulePath.str(); } } @@ -641,7 +649,7 @@ class ModuleInterfaceLoaderImpl { } if (path) { if (fs.exists(*path)) { - result.second = *path; + result.second = path->str(); } } } @@ -844,8 +852,8 @@ class ModuleInterfaceLoaderImpl { } InterfaceSubContextDelegateImpl astDelegate(ctx.SourceMgr, ctx.Diags, ctx.SearchPathOpts, ctx.LangOpts, + ctx.ClangImporterOpts, Opts, - ctx.getClangModuleLoader(), /*buildModuleCacheDirIfAbsent*/true, cacheDir, prebuiltCacheDir, @@ -911,7 +919,7 @@ class ModuleInterfaceLoaderImpl { // Diagnose that we didn't find a loadable module, if we were asked to. auto remarkRebuild = [&]() { rebuildInfo.diagnose(ctx, diagnosticLoc, moduleName, - interfacePath); + interfacePath, prebuiltCacheDir); }; // If we found an out-of-date .swiftmodule, we still want to add it as // a dependency of the .swiftinterface. That way if it's updated, but @@ -950,7 +958,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory( SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) { + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { // If running in OnlySerialized mode, ModuleInterfaceLoader // should not have been constructed at all. @@ -1083,20 +1092,12 @@ bool ModuleInterfaceLoader::buildSwiftModuleFromSwiftInterface( bool SerializeDependencyHashes, bool TrackSystemDependencies, ModuleInterfaceLoaderOptions LoaderOpts) { InterfaceSubContextDelegateImpl astDelegate(SourceMgr, Diags, - SearchPathOpts, LangOpts, + SearchPathOpts, LangOpts, ClangOpts, LoaderOpts, - /*clangImporter*/nullptr, /*CreateCacheDirIfAbsent*/true, CacheDir, PrebuiltCacheDir, SerializeDependencyHashes, TrackSystemDependencies); - // At this point we don't have an ClangImporter instance because the instance - // is created later when we create a new ASTContext to build the interface. - // Thus, we have to add these extra clang flags manually here to ensure explict - // module building works. - for (auto &Arg: ClangOpts.ExtraArgs) { - astDelegate.addExtraClangArg(Arg); - } ModuleInterfaceBuilder builder(SourceMgr, Diags, astDelegate, InPath, ModuleName, CacheDir, PrebuiltCacheDir, LoaderOpts.disableInterfaceLock); @@ -1204,7 +1205,7 @@ bool InterfaceSubContextDelegateImpl::extractSwiftInterfaceVersionAndArgs( if (CompRe.match(SB, &CompMatches)) { assert(CompMatches.size() == 2); - CompilerVersion = ArgSaver.save(CompMatches[1]); + CompilerVersion = ArgSaver.save(CompMatches[1]).str(); } else { // Don't diagnose; handwritten module interfaces don't include this field. @@ -1237,19 +1238,13 @@ bool InterfaceSubContextDelegateImpl::extractSwiftInterfaceVersionAndArgs( return false; } -void InterfaceSubContextDelegateImpl::addExtraClangArg(StringRef arg) { - genericSubInvocation.getClangImporterOptions().ExtraArgs.push_back(arg); - GenericArgs.push_back("-Xcc"); - GenericArgs.push_back(ArgSaver.save(arg)); -} - InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( SourceManager &SM, DiagnosticEngine &Diags, const SearchPathOptions &searchPathOpts, const LangOptions &langOpts, + const ClangImporterOptions &clangImporterOpts, ModuleInterfaceLoaderOptions LoaderOpts, - ClangModuleLoader *clangImporter, bool buildModuleCacheDirIfAbsent, StringRef moduleCachePath, StringRef prebuiltCachePath, @@ -1259,7 +1254,7 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( inheritOptionsForBuildingInterface(searchPathOpts, langOpts); // Configure front-end input. auto &SubFEOpts = genericSubInvocation.getFrontendOptions(); - SubFEOpts.RequestedAction = FrontendOptions::ActionType::EmitModuleOnly; + SubFEOpts.RequestedAction = LoaderOpts.requestedAction; if (!moduleCachePath.empty()) { genericSubInvocation.setClangModuleCachePath(moduleCachePath); } @@ -1286,23 +1281,22 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( // FIXME: we shouldn't need this. Remove it? StringRef explictSwiftModuleMap = searchPathOpts.ExplicitSwiftModuleMap; genericSubInvocation.getSearchPathOptions().ExplicitSwiftModuleMap = - explictSwiftModuleMap; - if (clangImporter) { - // We need to add these extra clang flags because explict module building - // related flags are all there: -fno-implicit-modules, -fmodule-map-file=, - // and -fmodule-file=. - // If we don't add these flags, the interface will be built with implicit - // PCMs. - for (auto arg: static_cast(clangImporter)->getExtraClangArgs()) { - addExtraClangArg(arg); - } - // Respect the detailed-record preprocessor setting of the parent context. - // This, and the "raw" clang module format it implicitly enables, are - // required by sourcekitd. - auto &Opts = clangImporter->getClangInstance().getPreprocessorOpts(); - if (Opts.DetailedRecord) { - genericSubInvocation.getClangImporterOptions().DetailedPreprocessingRecord = true; - } + explictSwiftModuleMap.str(); + auto &subClangImporterOpts = genericSubInvocation.getClangImporterOptions(); + // Respect the detailed-record preprocessor setting of the parent context. + // This, and the "raw" clang module format it implicitly enables, are + // required by sourcekitd. + subClangImporterOpts.DetailedPreprocessingRecord = + clangImporterOpts.DetailedPreprocessingRecord; + // We need to add these extra clang flags because explict module building + // related flags are all there: -fno-implicit-modules, -fmodule-map-file=, + // and -fmodule-file=. + // If we don't add these flags, the interface will be built with implicit + // PCMs. + subClangImporterOpts.ExtraArgs = clangImporterOpts.ExtraArgs; + for (auto arg: subClangImporterOpts.ExtraArgs) { + GenericArgs.push_back("-Xcc"); + GenericArgs.push_back(ArgSaver.save(arg)); } // Tell the genericSubInvocation to serialize dependency hashes if asked to do so. @@ -1392,11 +1386,12 @@ InterfaceSubContextDelegateImpl::getCacheHash(StringRef useInterfacePath) { return llvm::APInt(64, H).toString(36, /*Signed=*/false); } -bool InterfaceSubContextDelegateImpl::runInSubContext(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref, +std::error_code +InterfaceSubContextDelegateImpl::runInSubContext(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref, ArrayRef, StringRef)> action) { return runInSubCompilerInstance(moduleName, interfacePath, outputPath, diagLoc, [&](SubCompilerInstanceInfo &info){ @@ -1408,11 +1403,12 @@ bool InterfaceSubContextDelegateImpl::runInSubContext(StringRef moduleName, }); } -bool InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref action) { +std::error_code +InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref action) { // We are about to mess up the compiler invocation by using the compiler // arguments in the textual interface file. So copy to use a new compiler // invocation. @@ -1442,7 +1438,10 @@ bool InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleN std::vector outputFiles{"/"}; std::vector ModuleOutputPaths; ModuleOutputPaths.emplace_back(); - ModuleOutputPaths.back().ModuleOutputPath = outputPath.str(); + if (subInvocation.getFrontendOptions().RequestedAction == + FrontendOptions::ActionType::EmitModuleOnly) { + ModuleOutputPaths.back().ModuleOutputPath = outputPath.str(); + } assert(subInvocation.getFrontendOptions().InputsAndOutputs.isWholeModule()); subInvocation.getFrontendOptions().InputsAndOutputs .setMainAndSupplementaryOutputs(outputFiles, ModuleOutputPaths); @@ -1456,12 +1455,12 @@ bool InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleN CompilerVersion, interfacePath, diagLoc)) { - return true; + return std::make_error_code(std::errc::not_supported); } // Insert arguments collected from the interface file. BuildArgs.insert(BuildArgs.end(), SubArgs.begin(), SubArgs.end()); if (subInvocation.parseArgs(SubArgs, Diags)) { - return true; + return std::make_error_code(std::errc::not_supported); } CompilerInstance subInstance; SubCompilerInstanceInfo info; @@ -1473,7 +1472,7 @@ bool InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleN ForwardingDiagnosticConsumer FDC(Diags); subInstance.addDiagnosticConsumer(&FDC); if (subInstance.setup(subInvocation)) { - return true; + return std::make_error_code(std::errc::not_supported); } info.BuildArguments = BuildArgs; info.Hash = CacheHash; @@ -1521,28 +1520,30 @@ ExplicitSwiftModuleLoader::ExplicitSwiftModuleLoader( ExplicitSwiftModuleLoader::~ExplicitSwiftModuleLoader() { delete &Impl; } -std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( - AccessPathElem ModuleID, - const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) { +bool ExplicitSwiftModuleLoader::findModule(AccessPathElem ModuleID, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool &IsFramework, bool &IsSystemModule) { StringRef moduleName = ModuleID.Item.str(); auto it = Impl.ExplicitModuleMap.find(moduleName); // If no explicit module path is given matches the name, return with an // error code. if (it == Impl.ExplicitModuleMap.end()) { - return std::make_error_code(std::errc::not_supported); + return false; } auto &moduleInfo = it->getValue(); if (moduleInfo.moduleBuffer) { // We found an explicit module matches the given name, give the buffer // back to the caller side. *ModuleBuffer = std::move(moduleInfo.moduleBuffer); - return std::error_code(); + return true; } + // Set IsFramework bit according to the moduleInfo + IsFramework = moduleInfo.isFramework; + auto &fs = *Ctx.SourceMgr.getFileSystem(); // Open .swiftmodule file auto moduleBuf = fs.getBufferForFile(moduleInfo.modulePath); @@ -1550,7 +1551,7 @@ std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( // We cannot read the module content, diagnose. Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_explicit_module_file, moduleInfo.modulePath); - return moduleBuf.getError(); + return false; } assert(moduleBuf); @@ -1566,13 +1567,13 @@ std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( // We cannot read the module content, diagnose. Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_explicit_module_file, moduleInfo.modulePath); - return moduleBuf.getError(); + return false; } } else { // We cannot read the module content, diagnose. Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_explicit_module_file, moduleInfo.modulePath); - return forwardingModule.getError(); + return false; } } assert(moduleBuf); @@ -1591,7 +1592,19 @@ std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( if (moduleSourceInfoBuf) *ModuleSourceInfoBuffer = std::move(moduleSourceInfoBuf.get()); } - return std::error_code(); + return true; +} + +std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { + llvm_unreachable("Not supported in the Explicit Swift Module Loader."); + return std::make_error_code(std::errc::not_supported); } bool ExplicitSwiftModuleLoader::canImportModule( diff --git a/lib/Frontend/ModuleInterfaceSupport.cpp b/lib/Frontend/ModuleInterfaceSupport.cpp index 65e094af7ccc8..21150755bdf2c 100644 --- a/lib/Frontend/ModuleInterfaceSupport.cpp +++ b/lib/Frontend/ModuleInterfaceSupport.cpp @@ -551,5 +551,8 @@ bool swift::emitSwiftInterface(raw_ostream &out, if (needDummyProtocolDeclaration) InheritedProtocolCollector::printDummyProtocolDeclaration(out); + if (Opts.DebugPrintInvalidSyntax) + out << "#__debug_emit_invalid_swiftinterface_syntax__\n"; + return false; } diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 37c2f1bf41190..2ed016111faa9 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -35,6 +35,7 @@ #include "swift/AST/IRGenRequests.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ASTMangler.h" +#include "swift/AST/TBDGenRequests.h" #include "swift/AST/TypeRefinementContext.h" #include "swift/Basic/Dwarf.h" #include "swift/Basic/Edit.h" @@ -67,6 +68,7 @@ #include "swift/TBDGen/TBDGen.h" #include "clang/AST/ASTContext.h" +#include "clang/Basic/Module.h" #include "llvm/ADT/Statistic.h" #include "llvm/IR/LLVMContext.h" @@ -84,6 +86,7 @@ #include "llvm/Support/YAMLTraits.h" #include "llvm/Target/TargetMachine.h" +#include #include #include #include @@ -178,14 +181,14 @@ static bool emitMakeDependenciesIfNeeded(DiagnosticEngine &diags, reversePathSortedFilenames(opts.InputsAndOutputs.getInputFilenames()); for (auto const &path : inputPaths) { dependencyString.push_back(' '); - dependencyString.append(frontend::utils::escapeForMake(path, buffer)); + dependencyString.append(frontend::utils::escapeForMake(path, buffer).str()); } // Then print dependencies we've picked up during compilation. auto dependencyPaths = reversePathSortedFilenames(depTracker->getDependencies()); for (auto const &path : dependencyPaths) { dependencyString.push_back(' '); - dependencyString.append(frontend::utils::escapeForMake(path, buffer)); + dependencyString.append(frontend::utils::escapeForMake(path, buffer).str()); } // FIXME: Xcode can't currently handle multiple targets in a single @@ -342,6 +345,34 @@ class ABIDependencyEvaluator { void reexposeImportedABI(ModuleDecl *module, ModuleDecl *importedModule, bool includeImportedModule = true); + /// Check if a Swift module is an overlay for some Clang module. + /// + /// FIXME: Delete this hack once SR-13363 is fixed and ModuleDecl has the + /// right API which we can use directly. + bool isOverlayOfClangModule(ModuleDecl *swiftModule); + + /// Check for cases where we have a fake cycle through an overlay. + /// + /// Sometimes, we have fake cycles in the import graph due to the Clang + /// importer injecting overlays between Clang modules. These don't represent + /// an actual cycle in the build, so we should ignore them. + /// + /// We check this lazily after detecting a cycle because it is difficult to + /// determine at the point where we see the overlay whether it was incorrectly + /// injected by the Clang importer or whether any of its imports will + /// eventually lead to a cycle. + /// + /// For more details, see [NOTE: ABIDependencyEvaluator-fake-cycle-detection] + /// + /// \param startOfCycle A pointer to the element of \c searchStack where + /// the module \em first appeared. + /// + /// \pre The module on top of \c searchStack is the same module as + /// *startOfCycle. + /// + /// \pre searchStack.begin() <= startOfCycle < searchStack.end() + bool isFakeCycleThroughOverlay(ModuleDecl **startOfCycle); + /// Recursive step in computing ABI dependencies. /// /// Use this method instead of using the \c forClangModule/\c forSwiftModule @@ -453,13 +484,116 @@ void ABIDependencyEvaluator::reexposeImportedABI( addToABIExportMap(module, reexportedModule); } +bool ABIDependencyEvaluator::isOverlayOfClangModule(ModuleDecl *swiftModule) { + assert(!swiftModule->isNonSwiftModule()); + + llvm::SmallPtrSet importList; + ::getImmediateImports(swiftModule, importList, + {ModuleDecl::ImportFilterKind::Public}); + bool isOverlay = + llvm::any_of(importList, [&](ModuleDecl *importedModule) -> bool { + return isClangOverlayOf(swiftModule, importedModule); + }); + return isOverlay; +} + +// [NOTE: ABIDependencyEvaluator-fake-cycle-detection] +// +// First, let's consider a concrete example. +// - In Clang-land, ToyKit #imports CoreDoll. +// - The Swift overlay for CoreDoll imports both CoreDoll and ToyKit. +// Importing ToyKit from CoreDoll's overlay informally violates the layering +// of frameworks, but it doesn't actually create any cycles in the build +// dependencies. +// ┌───────────────────────────┐ +// ┌───│ CoreDoll.swiftmodule │ +// │ └───────────────────────────┘ +// │ │ +// import ToyKit @_exported import CoreDoll +// │ │ +// │ │ +// ▼ │ +// ┌──────────────────────────┐ │ +// │ ToyKit (ToyKit/ToyKit.h) │ │ +// └──────────────────────────┘ │ +// │ │ +// #import │ +// │ │ +// ▼ │ +// ┌──────────────────────────────┐ │ +// │CoreDoll (CoreDoll/CoreDoll.h)│◀──┘ +// └──────────────────────────────┘ +// +// Say we are trying to build a Swift module that imports ToyKit. Due to how +// module loading works, the Clang importer inserts the CoreDoll overlay +// between the ToyKit and CoreDoll Clang modules, creating a cycle in the +// import graph. +// +// ┌──────────────────────────┐ +// │ ToyKit (ToyKit/ToyKit.h) │◀──────────┐ +// └──────────────────────────┘ │ +// │ │ +// #import import ToyKit +// │ │ +// ▼ │ +// ┌────────────────────────────┐ │ +// │ CoreDoll.swiftmodule │─────────┘ +// └────────────────────────────┘ +// │ +// @_exported import CoreDoll +// │ +// ▼ +// ┌──────────────────────────────┐ +// │CoreDoll (CoreDoll/CoreDoll.h)│ +// └──────────────────────────────┘ +// +// This means that, at some point, searchStack will look like: +// +// [others] → ToyKit → CoreDoll (overlay) → ToyKit +// +// In the general case, there may be arbitrarily many modules in the cycle, +// including submodules. +// +// [others] → ToyKit → [others] → CoreDoll (overlay) → [others] → ToyKit +// +// where "[others]" indicates 0 or more modules of any kind. +// +// To detect this, we check that the start of the cycle is a Clang module and +// that there is at least one overlay between it and its recurrence at the end +// of the searchStack. If so, we assume we have detected a benign cycle which +// can be safely ignored. + +bool ABIDependencyEvaluator::isFakeCycleThroughOverlay( + ModuleDecl **startOfCycle) { + assert(startOfCycle >= searchStack.begin() && + startOfCycle < searchStack.end() && + "startOfCycleIter points to an element in searchStack"); + // The startOfCycle module must be a Clang module. + if (!(*startOfCycle)->isNonSwiftModule()) + return false; + // Next, we must have zero or more modules followed by a Swift overlay for a + // Clang module. + return std::any_of(startOfCycle + 1, searchStack.end(), + [this](ModuleDecl *module) { + return !module->isNonSwiftModule() && + isOverlayOfClangModule(module); + }); +} + void ABIDependencyEvaluator::computeABIDependenciesForModule( ModuleDecl *module) { - if (llvm::find(searchStack, module) != searchStack.end()) { + auto moduleIter = llvm::find(searchStack, module); + if (moduleIter != searchStack.end()) { + if (isFakeCycleThroughOverlay(moduleIter)) + return; crashOnInvariantViolation([&](llvm::raw_string_ostream &os) { os << "unexpected cycle in import graph!\n"; for (auto m: searchStack) { - printModule(m, os); os << "\ndepends on "; + printModule(m, os); + if (!m->isNonSwiftModule()) { + os << " (isOverlay = " << isOverlayOfClangModule(m) << ")"; + } + os << "\ndepends on "; } printModule(module, os); os << '\n'; }); @@ -510,6 +644,10 @@ void ABIDependencyEvaluator::computeABIDependenciesForClangModule( // C' imports S. This creates a cycle: S -> C' -> ... -> S. // In practice, this case is hit for // Darwin (Swift) -> SwiftOverlayShims (Clang) -> Darwin (Swift). + // We may also hit this in a slightly different direction, in case + // the module directly imports SwiftOverlayShims: + // SwiftOverlayShims -> Darwin (Swift) -> SwiftOverlayShims + // The latter is handled later by isFakeCycleThroughOverlay. // 3. [NOTE: Intra-module-leafwards-traversal] // Cycles within the same top-level module. // These don't matter for us, since we only care about the dependency @@ -519,15 +657,15 @@ void ABIDependencyEvaluator::computeABIDependenciesForClangModule( if (import->isStdlibModule()) { continue; } - if (!import->isNonSwiftModule() - && import->findUnderlyingClangModule() != nullptr - && llvm::find(searchStack, import) != searchStack.end()) { + if (!import->isNonSwiftModule() && isOverlayOfClangModule(import) && + llvm::find(searchStack, import) != searchStack.end()) { continue; } if (import->isNonSwiftModule() && module->getTopLevelModule() == import->getTopLevelModule() - && !import->findUnderlyingClangModule() - ->isSubModuleOf(module->findUnderlyingClangModule())) { + && (module == import + || !import->findUnderlyingClangModule() + ->isSubModuleOf(module->findUnderlyingClangModule()))) { continue; } computeABIDependenciesForModule(import); @@ -1166,7 +1304,7 @@ static void verifyGenericSignaturesIfNeeded(const CompilerInvocation &Invocation GenericSignatureBuilder::verifyGenericSignaturesInModule(module); } -static void dumpAndPrintScopeMap(const CompilerInstance &Instance, +static bool dumpAndPrintScopeMap(const CompilerInstance &Instance, SourceFile *SF) { // Not const because may require reexpansion ASTScope &scope = SF->getScope(); @@ -1176,13 +1314,14 @@ static void dumpAndPrintScopeMap(const CompilerInstance &Instance, llvm::errs() << "***Complete scope map***\n"; scope.buildFullyExpandedTree(); scope.print(llvm::errs()); - return; + return Instance.getASTContext().hadError(); } // Probe each of the locations, and dump what we find. for (auto lineColumn : opts.DumpScopeMapLocations) { scope.buildFullyExpandedTree(); scope.dumpOneScopeMapLocation(lineColumn); } + return Instance.getASTContext().hadError(); } static SourceFile * @@ -1197,7 +1336,7 @@ getPrimaryOrMainSourceFile(const CompilerInstance &Instance) { /// Dumps the AST of all available primary source files. If corresponding output /// files were specified, use them; otherwise, dump the AST to stdout. -static void dumpAST(CompilerInstance &Instance) { +static bool dumpAST(CompilerInstance &Instance) { auto primaryFiles = Instance.getPrimarySourceFiles(); if (!primaryFiles.empty()) { for (SourceFile *sourceFile: primaryFiles) { @@ -1212,55 +1351,7 @@ static void dumpAST(CompilerInstance &Instance) { auto *SF = getPrimaryOrMainSourceFile(Instance); SF->dump(llvm::outs(), /*parseIfNeeded*/ true); } -} - -/// We may have been told to dump the AST (either after parsing or -/// type-checking, which is already differentiated in -/// CompilerInstance::performSema()), so dump or print the main source file and -/// return. - -static Optional dumpASTIfNeeded(CompilerInstance &Instance) { - const auto &opts = Instance.getInvocation().getFrontendOptions(); - const FrontendOptions::ActionType Action = opts.RequestedAction; - ASTContext &Context = Instance.getASTContext(); - switch (Action) { - default: - return None; - - case FrontendOptions::ActionType::PrintAST: - getPrimaryOrMainSourceFile(Instance) - ->print(llvm::outs(), PrintOptions::printEverything()); - break; - - case FrontendOptions::ActionType::DumpScopeMaps: - dumpAndPrintScopeMap(Instance, getPrimaryOrMainSourceFile(Instance)); - break; - - case FrontendOptions::ActionType::DumpTypeRefinementContexts: - getPrimaryOrMainSourceFile(Instance) - ->getTypeRefinementContext() - ->dump(llvm::errs(), Context.SourceMgr); - break; - - case FrontendOptions::ActionType::DumpInterfaceHash: - getPrimaryOrMainSourceFile(Instance)->dumpInterfaceHash(llvm::errs()); - break; - - case FrontendOptions::ActionType::EmitSyntax: - emitSyntax(getPrimaryOrMainSourceFile(Instance), - opts.InputsAndOutputs.getSingleOutputFilename()); - break; - - case FrontendOptions::ActionType::DumpParse: - case FrontendOptions::ActionType::DumpAST: - dumpAST(Instance); - break; - - case FrontendOptions::ActionType::EmitImportedModules: - emitImportedModules(Context, Instance.getMainModule(), opts); - break; - } - return Context.hadError(); + return Instance.getASTContext().hadError(); } static void emitReferenceDependenciesForAllPrimaryInputsIfNeeded( @@ -1507,7 +1598,7 @@ static bool emitAnyWholeModulePostTypeCheckSupplementaryOutputs( llvm::SmallString<32> Buffer(*opts.BridgingHeaderDirForPrint); llvm::sys::path::append(Buffer, llvm::sys::path::filename(opts.ImplicitObjCHeaderPath)); - BridgingHeaderPathForPrint = Buffer.str(); + BridgingHeaderPathForPrint = (std::string)Buffer; } else { // By default, include the given bridging header path directly. BridgingHeaderPathForPrint = opts.ImplicitObjCHeaderPath; @@ -1637,6 +1728,7 @@ static void performEndOfPipelineActions(CompilerInstance &Instance) { // it's -emit-imported-modules, which can load modules. auto action = opts.RequestedAction; if (FrontendOptions::shouldActionOnlyParse(action) && + !ctx.getLoadedModules().empty() && action != FrontendOptions::ActionType::EmitImportedModules) { assert(ctx.getNumLoadedModules() == 1 && "Loaded a module during parse-only"); @@ -1673,9 +1765,15 @@ static void performEndOfPipelineActions(CompilerInstance &Instance) { } } - // Emit dependencies and index data. + // FIXME: This predicate matches the status quo, but there's no reason + // indexing cannot run for actions that do not require stdlib e.g. to better + // facilitate tests. + if (FrontendOptions::doesActionRequireSwiftStandardLibrary(action)) { + emitIndexData(Instance); + } + + // Emit dependencies. emitReferenceDependenciesForAllPrimaryInputsIfNeeded(Instance); - emitIndexData(Instance); emitMakeDependenciesIfNeeded(Instance.getDiags(), Instance.getDependencyTracker(), opts); @@ -1684,37 +1782,190 @@ static void performEndOfPipelineActions(CompilerInstance &Instance) { emitCompiledSourceForAllPrimaryInputsIfNeeded(Instance); } +static bool printSwiftVersion(const CompilerInvocation &Invocation) { + llvm::outs() << version::getSwiftFullVersion( + version::Version::getCurrentLanguageVersion()) + << '\n'; + llvm::outs() << "Target: " << Invocation.getLangOptions().Target.str() + << '\n'; + return false; +} + +static bool +withSemanticAnalysis(CompilerInstance &Instance, FrontendObserver *observer, + llvm::function_ref cont) { + const auto &Invocation = Instance.getInvocation(); + const auto &opts = Invocation.getFrontendOptions(); + assert(!FrontendOptions::shouldActionOnlyParse(opts.RequestedAction) && + "Action may only parse, but has requested semantic analysis!"); + + Instance.performSema(); + if (observer) + observer->performedSemanticAnalysis(Instance); + + switch (opts.CrashMode) { + case FrontendOptions::DebugCrashMode::AssertAfterParse: + debugFailWithAssertion(); + return true; + case FrontendOptions::DebugCrashMode::CrashAfterParse: + debugFailWithCrash(); + return true; + case FrontendOptions::DebugCrashMode::None: + break; + } + + (void)migrator::updateCodeAndEmitRemapIfNeeded(&Instance); + + if (Instance.getASTContext().hadError()) + return true; + + return cont(Instance); +} + +static bool performScanDependencies(CompilerInstance &Instance) { + auto batchScanInput = + Instance.getASTContext().SearchPathOpts.BatchScanInputFilePath; + if (batchScanInput.empty()) { + return scanDependencies(Instance); + } else { + return batchScanModuleDependencies(Instance, batchScanInput); + } +} + +static bool performParseOnly(ModuleDecl &MainModule) { + // A -parse invocation only cares about the side effects of parsing, so + // force the parsing of all the source files. + for (auto *file : MainModule.getFiles()) { + if (auto *SF = dyn_cast(file)) + (void)SF->getTopLevelDecls(); + } + return MainModule.getASTContext().hadError(); +} + +static bool performAction(CompilerInstance &Instance, + int &ReturnValue, + FrontendObserver *observer) { + const auto &opts = Instance.getInvocation().getFrontendOptions(); + auto &Context = Instance.getASTContext(); + switch (Instance.getInvocation().getFrontendOptions().RequestedAction) { + // MARK: Trivial Actions + case FrontendOptions::ActionType::NoneAction: + return Context.hadError(); + case FrontendOptions::ActionType::PrintVersion: + return printSwiftVersion(Instance.getInvocation()); + case FrontendOptions::ActionType::REPL: + llvm::report_fatal_error("Compiler-internal integrated REPL has been " + "removed; use the LLDB-enhanced REPL instead."); + + // MARK: Actions for Clang and Clang Modules + // We've been asked to precompile a bridging header or module; we want to + // avoid touching any other inputs and just parse, emit and exit. + case FrontendOptions::ActionType::EmitPCH: + return precompileBridgingHeader(Instance); + case FrontendOptions::ActionType::EmitPCM: + return precompileClangModule(Instance); + case FrontendOptions::ActionType::DumpPCM: + return dumpPrecompiledClangModule(Instance); + + // MARK: Module Interface Actions + case FrontendOptions::ActionType::CompileModuleFromInterface: + case FrontendOptions::ActionType::TypecheckModuleFromInterface: + return buildModuleFromInterface(Instance); + + // MARK: Actions that Dump + case FrontendOptions::ActionType::DumpParse: + return dumpAST(Instance); + case FrontendOptions::ActionType::DumpAST: { + // FIXME: -dump-ast expects to be able to write output even if type checking + // fails which does not cleanly fit the model \c withSemanticAnalysis is + // trying to impose. Once there is a request for the "semantic AST", this + // point is moot. + Instance.performSema(); + return dumpAST(Instance); + } + case FrontendOptions::ActionType::PrintAST: + return withSemanticAnalysis( + Instance, observer, [](CompilerInstance &Instance) { + getPrimaryOrMainSourceFile(Instance)->print( + llvm::outs(), PrintOptions::printEverything()); + return Instance.getASTContext().hadError(); + }); + case FrontendOptions::ActionType::DumpScopeMaps: + return withSemanticAnalysis( + Instance, observer, [](CompilerInstance &Instance) { + return dumpAndPrintScopeMap(Instance, + getPrimaryOrMainSourceFile(Instance)); + }); + case FrontendOptions::ActionType::DumpTypeRefinementContexts: + return withSemanticAnalysis( + Instance, observer, [](CompilerInstance &Instance) { + getPrimaryOrMainSourceFile(Instance) + ->getTypeRefinementContext() + ->dump(llvm::errs(), Instance.getASTContext().SourceMgr); + return Instance.getASTContext().hadError(); + }); + case FrontendOptions::ActionType::DumpInterfaceHash: + getPrimaryOrMainSourceFile(Instance)->dumpInterfaceHash(llvm::errs()); + return Context.hadError(); + case FrontendOptions::ActionType::EmitSyntax: + return emitSyntax(getPrimaryOrMainSourceFile(Instance), + opts.InputsAndOutputs.getSingleOutputFilename()); + case FrontendOptions::ActionType::EmitImportedModules: + return emitImportedModules(Instance.getMainModule(), opts); + + // MARK: Dependency Scanning Actions + case FrontendOptions::ActionType::ScanDependencies: + return performScanDependencies(Instance); + case FrontendOptions::ActionType::ScanClangDependencies: + return scanClangDependencies(Instance); + + // MARK: General Compilation Actions + case FrontendOptions::ActionType::Parse: + return performParseOnly(*Instance.getMainModule()); + case FrontendOptions::ActionType::ResolveImports: + return Instance.performParseAndResolveImportsOnly(); + case FrontendOptions::ActionType::Typecheck: + return withSemanticAnalysis(Instance, observer, + [](CompilerInstance &Instance) { + return Instance.getASTContext().hadError(); + }); + case FrontendOptions::ActionType::EmitSILGen: + case FrontendOptions::ActionType::EmitSIBGen: + case FrontendOptions::ActionType::EmitSIL: + case FrontendOptions::ActionType::EmitSIB: + case FrontendOptions::ActionType::EmitModuleOnly: + case FrontendOptions::ActionType::MergeModules: + case FrontendOptions::ActionType::Immediate: + case FrontendOptions::ActionType::EmitAssembly: + case FrontendOptions::ActionType::EmitIR: + case FrontendOptions::ActionType::EmitBC: + case FrontendOptions::ActionType::EmitObject: + case FrontendOptions::ActionType::DumpTypeInfo: + return withSemanticAnalysis( + Instance, observer, [&](CompilerInstance &Instance) { + assert(FrontendOptions::doesActionGenerateSIL(opts.RequestedAction) && + "All actions not requiring SILGen must have been handled!"); + return performCompileStepsPostSema(Instance, ReturnValue, observer); + }); + } + + assert(false && "Unhandled case in performCompile!"); + return Context.hadError(); +} + /// Performs the compile requested by the user. /// \param Instance Will be reset after performIRGeneration when the verifier /// mode is NoVerify and there were no errors. /// \returns true on error static bool performCompile(CompilerInstance &Instance, - ArrayRef Args, int &ReturnValue, FrontendObserver *observer) { const auto &Invocation = Instance.getInvocation(); const auto &opts = Invocation.getFrontendOptions(); const FrontendOptions::ActionType Action = opts.RequestedAction; - // We've been asked to precompile a bridging header or module; we want to - // avoid touching any other inputs and just parse, emit and exit. - if (Action == FrontendOptions::ActionType::EmitPCH) - return precompileBridgingHeader(Instance); - if (Action == FrontendOptions::ActionType::EmitPCM) - return precompileClangModule(Instance); - if (Action == FrontendOptions::ActionType::DumpPCM) - return dumpPrecompiledClangModule(Instance); - if (Action == FrontendOptions::ActionType::PrintVersion) { - llvm::outs() << version::getSwiftFullVersion( - version::Version::getCurrentLanguageVersion()) << '\n'; - llvm::outs() << "Target: " - << Invocation.getLangOptions().Target.str() << '\n'; - return false; - } - if (Action == FrontendOptions::ActionType::CompileModuleFromInterface) - return buildModuleFromInterface(Instance); - - if (Invocation.getInputKind() == InputFileKind::LLVM) + // To compile LLVM IR, just pass it off unmodified. + if (Instance.getInvocation().getInputKind() == InputFileKind::LLVM) return compileLLVMIR(Instance); // If we aren't in a parse-only context and expect an implicit stdlib import, @@ -1723,90 +1974,33 @@ static bool performCompile(CompilerInstance &Instance, // trigger a bunch of other errors due to the stdlib being missing, or at // worst crash downstream as many call sites don't currently handle a missing // stdlib. - if (!FrontendOptions::shouldActionOnlyParse(Action)) { + if (FrontendOptions::doesActionRequireSwiftStandardLibrary(Action)) { if (Instance.loadStdlibIfNeeded()) return true; } - bool didFinishPipeline = false; - SWIFT_DEFER { - assert(didFinishPipeline && "Returned without calling finishPipeline"); - }; - - auto finishPipeline = [&](bool hadError) -> bool { - // We might have freed the ASTContext already, but in that case we would - // have already performed these actions. - if (Instance.hasASTContext()) { - performEndOfPipelineActions(Instance); - hadError |= Instance.getASTContext().hadError(); + assert([&]() -> bool { + if (FrontendOptions::shouldActionOnlyParse(Action)) { + // Parsing gets triggered lazily, but let's make sure we have the right + // input kind. + auto kind = Invocation.getInputKind(); + return kind == InputFileKind::Swift || + kind == InputFileKind::SwiftLibrary || + kind == InputFileKind::SwiftModuleInterface; } - didFinishPipeline = true; - return hadError; - }; - - auto &Context = Instance.getASTContext(); - if (FrontendOptions::shouldActionOnlyParse(Action)) { - // Parsing gets triggered lazily, but let's make sure we have the right - // input kind. - auto kind = Invocation.getInputKind(); - assert((kind == InputFileKind::Swift || - kind == InputFileKind::SwiftLibrary || - kind == InputFileKind::SwiftModuleInterface) && - "Only supports parsing .swift files"); - (void)kind; - } else if (Action == FrontendOptions::ActionType::ResolveImports) { - Instance.performParseAndResolveImportsOnly(); - return finishPipeline(Context.hadError()); - } else { - Instance.performSema(); - } - - if (Action == FrontendOptions::ActionType::Parse) { - // A -parse invocation only cares about the side effects of parsing, so - // force the parsing of all the source files. - for (auto *file : Instance.getMainModule()->getFiles()) { - if (auto *SF = dyn_cast(file)) - (void)SF->getTopLevelDecls(); - } - return finishPipeline(Context.hadError()); - } - - if (Action == FrontendOptions::ActionType::ScanDependencies) - return finishPipeline(scanDependencies(Instance)); - - if (observer) - observer->performedSemanticAnalysis(Instance); - - { - FrontendOptions::DebugCrashMode CrashMode = opts.CrashMode; - if (CrashMode == FrontendOptions::DebugCrashMode::AssertAfterParse) - debugFailWithAssertion(); - else if (CrashMode == FrontendOptions::DebugCrashMode::CrashAfterParse) - debugFailWithCrash(); - } + return true; + }() && "Only supports parsing .swift files"); - (void)migrator::updateCodeAndEmitRemapIfNeeded(&Instance); + bool hadError = performAction(Instance, ReturnValue, observer); - if (Action == FrontendOptions::ActionType::REPL) { - llvm::report_fatal_error("Compiler-internal integrated REPL has been " - "removed; use the LLDB-enhanced REPL instead."); + // We might have freed the ASTContext already, but in that case we would + // have already performed these actions. + if (Instance.hasASTContext() && + FrontendOptions::doesActionRequireInputs(Action)) { + performEndOfPipelineActions(Instance); + hadError |= Instance.getASTContext().hadError(); } - - if (auto r = dumpASTIfNeeded(Instance)) - return finishPipeline(*r); - - if (Context.hadError()) - return finishPipeline(/*hadError*/ true); - - // We've just been told to perform a typecheck, so we can return now. - if (Action == FrontendOptions::ActionType::Typecheck) - return finishPipeline(/*hadError*/ false); - - assert(FrontendOptions::doesActionGenerateSIL(Action) && - "All actions not requiring SILGen must have been handled!"); - - return finishPipeline( - performCompileStepsPostSema(Instance, ReturnValue, observer)); + return hadError; } static bool serializeSIB(SILModule *SM, const PrimarySpecificPaths &PSPs, @@ -1824,6 +2018,17 @@ static bool serializeSIB(SILModule *SM, const PrimarySpecificPaths &PSPs, return Context.hadError(); } +static bool serializeModuleSummary(SILModule *SM, + const PrimarySpecificPaths &PSPs, + const ASTContext &Context) { + auto summaryOutputPath = PSPs.SupplementaryOutputs.ModuleSummaryOutputPath; + return withOutputFile(Context.Diags, summaryOutputPath, + [&](llvm::raw_ostream &out) { + out << "Some stuff"; + return false; + }); +} + static GeneratedModule generateIR(const IRGenOptions &IRGenOpts, const TBDGenOptions &TBDOpts, std::unique_ptr SM, @@ -2048,6 +2253,12 @@ static bool performCompileStepsPostSILGen(CompilerInstance &Instance, if (observer) observer->performedSILProcessing(*SM); + if (PSPs.haveModuleSummaryOutputPath()) { + if (serializeModuleSummary(SM.get(), PSPs, Context)) { + return true; + } + } + if (Action == FrontendOptions::ActionType::EmitSIB) return serializeSIB(SM.get(), PSPs, Context, MSF); @@ -2580,7 +2791,7 @@ int swift::performFrontend(ArrayRef Args, } int ReturnValue = 0; - bool HadError = performCompile(*Instance, Args, ReturnValue, observer); + bool HadError = performCompile(*Instance, ReturnValue, observer); if (verifierEnabled) { DiagnosticEngine &diags = Instance->getDiags(); diff --git a/lib/FrontendTool/ImportedModules.cpp b/lib/FrontendTool/ImportedModules.cpp index 90a33895ee52a..d750417737264 100644 --- a/lib/FrontendTool/ImportedModules.cpp +++ b/lib/FrontendTool/ImportedModules.cpp @@ -42,9 +42,9 @@ static void findAllClangImports(const clang::Module *module, } } -bool swift::emitImportedModules(ASTContext &Context, ModuleDecl *mainModule, +bool swift::emitImportedModules(ModuleDecl *mainModule, const FrontendOptions &opts) { - + auto &Context = mainModule->getASTContext(); std::string path = opts.InputsAndOutputs.getSingleOutputFilename(); std::error_code EC; llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None); diff --git a/lib/FrontendTool/ImportedModules.h b/lib/FrontendTool/ImportedModules.h index 42b4e76babaf4..510fa4ccdedde 100644 --- a/lib/FrontendTool/ImportedModules.h +++ b/lib/FrontendTool/ImportedModules.h @@ -20,8 +20,7 @@ class FrontendOptions; class ModuleDecl; /// Emit the names of the modules imported by \c mainModule. -bool emitImportedModules(ASTContext &Context, ModuleDecl *mainModule, - const FrontendOptions &opts); +bool emitImportedModules(ModuleDecl *mainModule, const FrontendOptions &opts); } // end namespace swift #endif diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index 6a90ae8231c86..4adb17dedc172 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -31,13 +31,105 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/YAMLParser.h" #include using namespace swift; +using namespace llvm::yaml; namespace { +struct BatchScanInput { + StringRef moduleName; + StringRef arguments; + StringRef outputPath; + bool isSwift; +}; + +static std::string getScalaNodeText(Node *N) { + SmallString<32> Buffer; + return cast(N)->getValue(Buffer).str(); +} + +/// Parse an entry like this, where the "platforms" key-value pair is optional: +/// { +/// "swiftModuleName": "Foo", +/// "arguments": "-target 10.15", +/// "output": "../Foo.json" +/// }, +static bool parseBatchInputEntries(ASTContext &Ctx, llvm::StringSaver &saver, + Node *Node, std::vector &result) { + auto *SN = cast(Node); + if (!SN) + return true; + for (auto It = SN->begin(); It != SN->end(); ++It) { + auto *MN = cast(&*It); + BatchScanInput entry; + Optional> Platforms; + for (auto &Pair: *MN) { + auto Key = getScalaNodeText(Pair.getKey()); + auto* Value = Pair.getValue(); + if (Key == "clangModuleName") { + entry.moduleName = saver.save(getScalaNodeText(Value)); + entry.isSwift = false; + } else if (Key == "swiftModuleName") { + entry.moduleName = saver.save(getScalaNodeText(Value)); + entry.isSwift = true; + } else if (Key == "arguments") { + entry.arguments = saver.save(getScalaNodeText(Value)); + } else if (Key == "output") { + entry.outputPath = saver.save(getScalaNodeText(Value)); + } else { + // Future proof. + continue; + } + } + if (entry.moduleName.empty()) + return true; + if (entry.outputPath.empty()) + return true; + result.emplace_back(std::move(entry)); + } + return false; +} +static Optional> +parseBatchScanInputFile(ASTContext &ctx, StringRef batchInputPath, + llvm::StringSaver &saver) { + assert(!batchInputPath.empty()); + namespace yaml = llvm::yaml; + std::vector result; + + // Load the input file. + llvm::ErrorOr> FileBufOrErr = + llvm::MemoryBuffer::getFile(batchInputPath); + if (!FileBufOrErr) { + ctx.Diags.diagnose(SourceLoc(), diag::batch_scan_input_file_missing, + batchInputPath); + return None; + } + StringRef Buffer = FileBufOrErr->get()->getBuffer(); + + // Use a new source manager instead of the one from ASTContext because we + // don't want the Json file to be persistent. + SourceManager SM; + yaml::Stream Stream(llvm::MemoryBufferRef(Buffer, batchInputPath), + SM.getLLVMSourceMgr()); + for (auto DI = Stream.begin(); DI != Stream.end(); ++ DI) { + assert(DI != Stream.end() && "Failed to read a document"); + yaml::Node *N = DI->getRoot(); + assert(N && "Failed to find a root"); + if (parseBatchInputEntries(ctx, saver, N, result)) { + ctx.Diags.diagnose(SourceLoc(), diag::batch_scan_input_file_corrupted, + batchInputPath); + return None; + } + } + return result; +} } /// Find all of the imported Clang modules starting with the given module name. @@ -171,7 +263,7 @@ static void discoverCrosssImportOverlayDependencies( dummyMainDependencies.addModuleDependency(modName.str()); mainDep.addModuleDependency(modName.str()); }); - cache.updateDependencies({mainModuleName, ModuleDependenciesKind::Swift}, mainDep); + cache.updateDependencies({mainModuleName.str(), ModuleDependenciesKind::Swift}, mainDep); // Record the dummy main module's direct dependencies. The dummy main module // only directly depend on these newly discovered overlay modules. @@ -216,6 +308,13 @@ namespace { out << "\""; } + /// Write a boolean value as JSON. + void writeJSONValue(llvm::raw_ostream &out, + bool value, + unsigned indentLevel) { + out.write_escaped(value ? "true" : "false"); + } + /// Write a module identifier. void writeJSONValue(llvm::raw_ostream &out, const ModuleDependencyID &module, @@ -397,6 +496,11 @@ static void writeJSON(llvm::raw_ostream &out, swiftDeps->compiledModulePath, 5, /*trailingComma=*/false); } + writeJSONSingleField( + out, "isFramework", + swiftDeps->isFramework, 5, + /*trailingComma=*/!swiftDeps->extraPCMArgs.empty() || + swiftDeps->bridgingHeaderFile.hasValue()); if (!swiftDeps->extraPCMArgs.empty()) { out.indent(5 * 2); out << "\"extraPcmArgs\": [\n"; @@ -521,6 +625,123 @@ static bool diagnoseCycle(CompilerInstance &instance, return false; } +static bool scanModuleDependencies(CompilerInstance &instance, + StringRef moduleName, + bool isClang, + StringRef outputPath) { + ASTContext &ctx = instance.getASTContext(); + auto &FEOpts = instance.getInvocation().getFrontendOptions(); + ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); + auto ModuleCachePath = getModuleCachePathFromClang(ctx + .getClangModuleLoader()->getClangInstance()); + + llvm::SetVector, + std::set> allModules; + // Create the module dependency cache. + ModuleDependenciesCache cache; + InterfaceSubContextDelegateImpl ASTDelegate(ctx.SourceMgr, ctx.Diags, + ctx.SearchPathOpts, ctx.LangOpts, + ctx.ClangImporterOpts, + LoaderOpts, + /*buildModuleCacheDirIfAbsent*/false, + ModuleCachePath, + FEOpts.PrebuiltModuleCachePath, + FEOpts.SerializeModuleInterfaceDependencyHashes, + FEOpts.shouldTrackSystemDependencies()); + Optional rootDeps; + if (isClang) { + // Loading the clang module using Clang importer. + // This action will populate the cache with the main module's dependencies. + rootDeps = ctx.getModuleDependencies(moduleName, /*IsClang*/true, cache, + ASTDelegate); + } else { + // Loading the swift module's dependencies. + rootDeps = ctx.getSwiftModuleDependencies(moduleName, cache, ASTDelegate); + } + if (!rootDeps.hasValue()) { + // We cannot find the clang module, abort. + return true; + } + // Add the main module. + allModules.insert({moduleName.str(), isClang ? ModuleDependenciesKind::Clang: + ModuleDependenciesKind::Swift}); + + // Explore the dependencies of every module. + for (unsigned currentModuleIdx = 0; + currentModuleIdx < allModules.size(); + ++currentModuleIdx) { + auto module = allModules[currentModuleIdx]; + auto discoveredModules = + resolveDirectDependencies(instance, module, cache, ASTDelegate); + allModules.insert(discoveredModules.begin(), discoveredModules.end()); + } + // Write out the JSON description. + std::error_code EC; + llvm::raw_fd_ostream out(outputPath, EC, llvm::sys::fs::F_None); + writeJSON(out, instance, cache, ASTDelegate, allModules.getArrayRef()); + return false; +} + +bool swift::scanClangDependencies(CompilerInstance &instance) { + return scanModuleDependencies(instance, + instance.getMainModule()->getNameStr(), + /*isClang*/true, + instance.getInvocation().getFrontendOptions() + .InputsAndOutputs.getSingleOutputFilename()); +} + +bool swift::batchScanModuleDependencies(CompilerInstance &instance, + llvm::StringRef batchInputFile) { + const CompilerInvocation &invok = instance.getInvocation(); + + (void)instance.getMainModule(); + llvm::BumpPtrAllocator alloc; + llvm::StringSaver saver(alloc); + auto results = parseBatchScanInputFile(instance.getASTContext(), + batchInputFile, saver); + if (!results.hasValue()) + return true; + auto &diags = instance.getDiags(); + ForwardingDiagnosticConsumer FDC(diags); + // Keep track of all compiler instances we have created. + llvm::StringMap> subInstanceMap; + for (auto &entry: *results) { + CompilerInstance *pInstance = nullptr; + if (entry.arguments.empty()) { + // Use the compiler's instance if no arguments are specified. + pInstance = &instance; + } else if (subInstanceMap.count(entry.arguments)) { + // Use the previously created instance if we've seen the arguments before. + pInstance = subInstanceMap[entry.arguments].get(); + } else { + // Create a new instance by the arguments and save it in the map. + pInstance = subInstanceMap.insert({entry.arguments, + std::make_unique()}).first->getValue().get(); + SmallVector args; + llvm::cl::TokenizeGNUCommandLine(entry.arguments, saver, args); + CompilerInvocation subInvok = invok; + pInstance->addDiagnosticConsumer(&FDC); + if (subInvok.parseArgs(args, diags)) { + instance.getDiags().diagnose(SourceLoc(), diag::scanner_arguments_invalid, + entry.arguments); + return true; + } + if (pInstance->setup(subInvok)) { + instance.getDiags().diagnose(SourceLoc(), diag::scanner_arguments_invalid, + entry.arguments); + return true; + } + } + assert(pInstance); + // Scan using the chosen compiler instance. + if (scanModuleDependencies(*pInstance, entry.moduleName, !entry.isSwift, + entry.outputPath)) { + return true; + } + } + return false; +} + bool swift::scanDependencies(CompilerInstance &instance) { ASTContext &Context = instance.getASTContext(); ModuleDecl *mainModule = instance.getMainModule(); @@ -618,8 +839,8 @@ bool swift::scanDependencies(CompilerInstance &instance) { ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); InterfaceSubContextDelegateImpl ASTDelegate(ctx.SourceMgr, ctx.Diags, ctx.SearchPathOpts, ctx.LangOpts, + ctx.ClangImporterOpts, LoaderOpts, - ctx.getClangModuleLoader(), /*buildModuleCacheDirIfAbsent*/false, ModuleCachePath, FEOpts.PrebuiltModuleCachePath, diff --git a/lib/FrontendTool/ScanDependencies.h b/lib/FrontendTool/ScanDependencies.h index ece8515097608..fab7d26bbb190 100644 --- a/lib/FrontendTool/ScanDependencies.h +++ b/lib/FrontendTool/ScanDependencies.h @@ -13,13 +13,24 @@ #ifndef SWIFT_FRONTENDTOOL_SCANDEPENDENCIES_H #define SWIFT_FRONTENDTOOL_SCANDEPENDENCIES_H +#include "llvm/ADT/StringRef.h" + namespace swift { +class CompilerInvocation; class CompilerInstance; +/// Batch scan the dependencies for modules specified in \c batchInputFile. +bool batchScanModuleDependencies(CompilerInstance &instance, + llvm::StringRef batchInputFile); + /// Scans the dependencies of the main module of \c instance. bool scanDependencies(CompilerInstance &instance); +/// Scans the dependencies of the underlying clang module of the main module +/// of \c instance. +bool scanClangDependencies(CompilerInstance &instance); + } // end namespace swift #endif diff --git a/lib/FrontendTool/TBD.cpp b/lib/FrontendTool/TBD.cpp index 77a27a2152e87..f64d86ee13c38 100644 --- a/lib/FrontendTool/TBD.cpp +++ b/lib/FrontendTool/TBD.cpp @@ -17,6 +17,7 @@ #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" +#include "swift/AST/TBDGenRequests.h" #include "swift/Basic/LLVM.h" #include "swift/Demangling/Demangle.h" #include "swift/Frontend/FrontendOptions.h" diff --git a/lib/IDE/CMakeLists.txt b/lib/IDE/CMakeLists.txt index 7348c057ef63a..d028e874d39b7 100644 --- a/lib/IDE/CMakeLists.txt +++ b/lib/IDE/CMakeLists.txt @@ -7,6 +7,7 @@ add_swift_host_library(swiftIDE STATIC ConformingMethodList.cpp ExprContextAnalysis.cpp Formatting.cpp + FuzzyStringMatcher.cpp Refactoring.cpp ModuleInterfacePrinting.cpp REPLCodeCompletion.cpp @@ -21,6 +22,7 @@ add_swift_host_library(swiftIDE STATIC target_link_libraries(swiftIDE PRIVATE swiftAST swiftClangImporter + swiftDriver swiftFrontend swiftIndex swiftParse diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index d3eb0b21c6d14..d0955f257b6dd 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -2387,7 +2387,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { // i.e. cases where 'ExprType' != 'keyPathInfo.baseType'. auto *SD = keyPathInfo.subscript; - auto elementTy = SD->getElementTypeLoc().getType(); + const auto elementTy = SD->getElementInterfaceType(); if (!elementTy->hasTypeParameter()) return elementTy; @@ -3725,8 +3725,12 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { llvm::SaveAndRestore ChangeNeedOptionalUnwrap(NeedOptionalUnwrap, true); if (DotLoc.isValid()) { + // Let's not erase the dot if the completion is after a swift key path + // root because \A?.?.member is the correct way to access wrapped type + // member from an optional key path root. + auto loc = IsAfterSwiftKeyPathRoot ? DotLoc.getAdvancedLoc(1) : DotLoc; NumBytesToEraseForOptionalUnwrap = Ctx.SourceMgr.getByteDistance( - DotLoc, Ctx.SourceMgr.getCodeCompletionLoc()); + loc, Ctx.SourceMgr.getCodeCompletionLoc()); } else { NumBytesToEraseForOptionalUnwrap = 0; } @@ -4284,14 +4288,18 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (!T->mayHaveMembers()) return; - DeclContext *DC = const_cast(CurrDeclContext); - // We can only say .foo where foo is a static member of the contextual // type and has the same type (or if the member is a function, then the // same result type) as the contextual type. FilteredDeclConsumer consumer(*this, [=](ValueDecl *VD, DeclVisibilityKind Reason) { - return isReferenceableByImplicitMemberExpr(CurrModule, DC, T, VD); + if (T->getOptionalObjectType() && + VD->getModuleContext()->isStdlibModule()) { + // In optional context, ignore '.init()', 'init(nilLiteral:)', + if (isa(VD)) + return false; + } + return true; }); auto baseType = MetatypeType::get(T); @@ -5930,7 +5938,7 @@ void CodeCompletionCallbacksImpl::doneParsing() { if (!OnRoot && KPE->getComponents().back().getKind() == KeyPathExpr::Component::Kind::OptionalWrap) { // KeyPath expr with '?' (e.g. '\Ty.[0].prop?.another'). - // Althogh expected type is optional, we should unwrap it because it's + // Although expected type is optional, we should unwrap it because it's // unwrapped. baseType = baseType->getOptionalObjectType(); } @@ -6064,7 +6072,7 @@ void CodeCompletionCallbacksImpl::doneParsing() { // TypeName at attribute position after '@'. // - VarDecl: Property Wrappers. - // - ParamDecl/VarDecl/FuncDecl: Function Buildres. + // - ParamDecl/VarDecl/FuncDecl: Function Builders. if (!AttTargetDK || *AttTargetDK == DeclKind::Var || *AttTargetDK == DeclKind::Param || *AttTargetDK == DeclKind::Func) Lookup.getTypeCompletionsInDeclContext( diff --git a/lib/IDE/CodeCompletionResultPrinter.cpp b/lib/IDE/CodeCompletionResultPrinter.cpp index e5c9986ab1fde..7b61aa1835153 100644 --- a/lib/IDE/CodeCompletionResultPrinter.cpp +++ b/lib/IDE/CodeCompletionResultPrinter.cpp @@ -10,8 +10,9 @@ // //===----------------------------------------------------------------------===// -#include "swift/Basic/LLVM.h" #include "swift/IDE/CodeCompletionResultPrinter.h" +#include "swift/AST/ASTPrinter.h" +#include "swift/Basic/LLVM.h" #include "swift/IDE/CodeCompletion.h" #include "swift/Markup/XMLUtils.h" #include "llvm/Support/raw_ostream.h" @@ -255,3 +256,186 @@ void swift::ide::printCodeCompletionResultTypeNameAnnotated(const CodeCompletion AnnotatingResultPrinter printer(OS); printer.printTypeName(Result); } + +/// Provide the text for the call parameter, including constructing a typed +/// editor placeholder for it. +static void +constructTextForCallParam(ArrayRef ParamGroup, + raw_ostream &OS) { + assert(ParamGroup.front().is(ChunkKind::CallParameterBegin)); + + for (; !ParamGroup.empty(); ParamGroup = ParamGroup.slice(1)) { + auto &C = ParamGroup.front(); + if (C.isAnnotation()) + continue; + if (C.is(ChunkKind::CallParameterInternalName) || + C.is(ChunkKind::CallParameterType) || + C.is(ChunkKind::CallParameterTypeBegin) || + C.is(ChunkKind::CallParameterClosureExpr)) { + break; + } + if (!C.hasText()) + continue; + OS << C.getText(); + } + + SmallString<32> DisplayString; + SmallString<32> TypeString; + SmallString<32> ExpansionTypeString; + + for (auto i = ParamGroup.begin(), e = ParamGroup.end(); i != e; ++i) { + auto &C = *i; + if (C.is(ChunkKind::CallParameterTypeBegin)) { + assert(TypeString.empty()); + auto nestingLevel = C.getNestingLevel(); + ++i; + for (; i != e; ++i) { + if (i->endsPreviousNestedGroup(nestingLevel)) + break; + if (!i->isAnnotation() && i->hasText()) { + TypeString += i->getText(); + DisplayString += i->getText(); + } + } + --i; + continue; + } + if (C.is(ChunkKind::CallParameterClosureType)) { + assert(ExpansionTypeString.empty()); + ExpansionTypeString = C.getText(); + continue; + } + if (C.is(ChunkKind::CallParameterType)) { + assert(TypeString.empty()); + TypeString = C.getText(); + } + if (C.is(ChunkKind::CallParameterClosureExpr)) { + // We have a closure expression, so provide it directly instead of in + // a placeholder. + OS << "{"; + if (!C.getText().empty()) + OS << " " << C.getText(); + OS << "\n" << getCodePlaceholder() << "\n}"; + return; + } + if (C.isAnnotation() || !C.hasText()) + continue; + DisplayString += C.getText(); + } + + StringRef Display = DisplayString.str(); + StringRef Type = TypeString.str(); + StringRef ExpansionType = ExpansionTypeString.str(); + if (ExpansionType.empty()) + ExpansionType = Type; + + OS << "<#T##" << Display; + if (Display == Type && Display == ExpansionType) { + // Short version, display and type are the same. + } else { + OS << "##" << Type; + if (ExpansionType != Type) + OS << "##" << ExpansionType; + } + OS << "#>"; +} + +void swift::ide::printCodeCompletionResultSourceText( + const CodeCompletionResult &Result, llvm::raw_ostream &OS) { + auto Chunks = Result.getCompletionString()->getChunks(); + for (size_t i = 0; i < Chunks.size(); ++i) { + auto &C = Chunks[i]; + if (C.is(ChunkKind::BraceStmtWithCursor)) { + OS << " {\n" << getCodePlaceholder() << "\n}"; + continue; + } + if (C.is(ChunkKind::CallParameterBegin)) { + size_t Start = i++; + for (; i < Chunks.size(); ++i) { + if (Chunks[i].endsPreviousNestedGroup(C.getNestingLevel())) + break; + } + constructTextForCallParam(Chunks.slice(Start, i - Start), OS); + --i; + continue; + } + if (C.is(ChunkKind::TypeAnnotationBegin)) { + // Skip type annotation structure. + auto level = C.getNestingLevel(); + do { + ++i; + } while (i != Chunks.size() && !Chunks[i].endsPreviousNestedGroup(level)); + --i; + } + if (!C.isAnnotation() && C.hasText()) { + OS << C.getText(); + } + } +} + +void swift::ide::printCodeCompletionResultFilterName( + const CodeCompletionResult &Result, llvm::raw_ostream &OS) { + auto str = Result.getCompletionString(); + // FIXME: we need a more uniform way to handle operator completions. + if (str->getChunks().size() == 1 && str->getChunks()[0].is(ChunkKind::Dot)) { + OS << "."; + return; + } else if (str->getChunks().size() == 2 && + str->getChunks()[0].is(ChunkKind::QuestionMark) && + str->getChunks()[1].is(ChunkKind::Dot)) { + OS << "?."; + return; + } + + auto FirstTextChunk = str->getFirstTextChunkIndex(); + if (FirstTextChunk.hasValue()) { + auto chunks = str->getChunks().slice(*FirstTextChunk); + for (auto i = chunks.begin(), e = chunks.end(); i != e; ++i) { + auto &C = *i; + + if (C.is(ChunkKind::BraceStmtWithCursor)) + break; // Don't include brace-stmt in filter name. + + if (C.is(ChunkKind::Equal)) { + OS << C.getText(); + break; + } + + bool shouldPrint = !C.isAnnotation(); + switch (C.getKind()) { + case ChunkKind::TypeAnnotation: + case ChunkKind::CallParameterInternalName: + case ChunkKind::CallParameterClosureType: + case ChunkKind::CallParameterClosureExpr: + case ChunkKind::CallParameterType: + case ChunkKind::DeclAttrParamColon: + case ChunkKind::Comma: + case ChunkKind::Whitespace: + case ChunkKind::Ellipsis: + case ChunkKind::Ampersand: + case ChunkKind::OptionalMethodCallTail: + continue; + case ChunkKind::CallParameterTypeBegin: + case ChunkKind::TypeAnnotationBegin: { + // Skip call parameter type or type annotation structure. + auto nestingLevel = C.getNestingLevel(); + do { + ++i; + } while (i != e && !i->endsPreviousNestedGroup(nestingLevel)); + --i; + continue; + } + case ChunkKind::CallParameterColon: + // Since we don't add the type, also don't add the space after ':'. + if (shouldPrint) + OS << ":"; + continue; + default: + break; + } + + if (C.hasText() && shouldPrint) + OS << C.getText(); + } + } +} diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 26df36591975f..2c2babd019b7c 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -85,8 +85,6 @@ template Decl *getElementAt(const Range &Decls, unsigned N) { /// Find the equivalent \c DeclContext with \p DC from \p SF AST. /// This assumes the AST which contains \p DC has exact the same structure with /// \p SF. -/// FIXME: This doesn't support IfConfigDecl blocks. If \p DC is in an inactive -/// config block, this function returns \c false. static DeclContext *getEquivalentDeclContextFromSourceFile(DeclContext *DC, SourceFile *SF) { PrettyStackTraceDeclContext trace("getting equivalent decl context for", DC); @@ -129,7 +127,6 @@ static DeclContext *getEquivalentDeclContextFromSourceFile(DeclContext *DC, } // Not found in the decl context tree. - // FIXME: Probably DC is in an inactive #if block. if (N == ~0U) { return nullptr; } @@ -278,7 +275,7 @@ static bool areAnyDependentFilesInvalidated( } // namespace bool CompletionInstance::performCachedOperationIfPossible( - const swift::CompilerInvocation &Invocation, llvm::hash_code ArgsHash, + llvm::hash_code ArgsHash, llvm::IntrusiveRefCntPtr FileSystem, llvm::MemoryBuffer *completionBuffer, unsigned int Offset, DiagnosticConsumer *DiagC, @@ -288,7 +285,7 @@ bool CompletionInstance::performCachedOperationIfPossible( if (!CachedCI) return false; - if (CachedReuseCount >= MaxASTReuseCount) + if (CachedReuseCount >= Opts.MaxASTReuseCount) return false; if (CachedArgHash != ArgsHash) return false; @@ -326,8 +323,10 @@ bool CompletionInstance::performCachedOperationIfPossible( TypeCheckerOptions typeckOpts = CI.getASTContext().TypeCheckerOpts; SearchPathOptions searchPathOpts = CI.getASTContext().SearchPathOpts; DiagnosticEngine tmpDiags(tmpSM); + ClangImporterOptions clangOpts; std::unique_ptr tmpCtx( - ASTContext::get(langOpts, typeckOpts, searchPathOpts, tmpSM, tmpDiags)); + ASTContext::get(langOpts, typeckOpts, searchPathOpts, clangOpts, tmpSM, + tmpDiags)); registerParseRequestFunctions(tmpCtx->evaluator); registerIDERequestFunctions(tmpCtx->evaluator); registerTypeCheckerRequestFunctions(tmpCtx->evaluator); @@ -411,9 +410,14 @@ bool CompletionInstance::performCachedOperationIfPossible( oldInfo.PrevOffset = newInfo.PrevOffset; oldState->restoreCodeCompletionDelayedDeclState(oldInfo); + auto newBufferStart = SM.getRangeForBuffer(newBufferID).getStart(); + SourceRange newBodyRange(newBufferStart.getAdvancedLoc(newInfo.StartOffset), + newBufferStart.getAdvancedLoc(newInfo.EndOffset)); + auto *AFD = cast(DC); - if (AFD->isBodySkipped()) - AFD->setBodyDelayed(AFD->getBodySourceRange()); + AFD->setBodyToBeReparsed(newBodyRange); + SM.setReplacedRange({AFD->getOriginalBodySourceRange(), newBodyRange}); + oldSF->clearScope(); traceDC = AFD; break; @@ -483,8 +487,6 @@ bool CompletionInstance::performCachedOperationIfPossible( } CachedReuseCount += 1; - cacheDependencyHashIfNeeded(CI, SM.getCodeCompletionBufferID(), - InMemoryDependencyHash); return true; } @@ -568,20 +570,21 @@ bool CompletionInstance::shouldCheckDependencies() const { assert(CachedCI); using namespace std::chrono; auto now = system_clock::now(); - return DependencyCheckedTimestamp + seconds(DependencyCheckIntervalSecond) < - now; + auto threshold = DependencyCheckedTimestamp + + seconds(Opts.DependencyCheckIntervalSecond); + return threshold < now; } -void CompletionInstance::setDependencyCheckIntervalSecond(unsigned Value) { +void CompletionInstance::setOptions(CompletionInstance::Options NewOpts) { std::lock_guard lock(mtx); - DependencyCheckIntervalSecond = Value; + Opts = NewOpts; } bool swift::ide::CompletionInstance::performOperation( swift::CompilerInvocation &Invocation, llvm::ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, llvm::MemoryBuffer *completionBuffer, unsigned int Offset, - bool EnableASTCaching, std::string &Error, DiagnosticConsumer *DiagC, + std::string &Error, DiagnosticConsumer *DiagC, llvm::function_ref Callback) { // Always disable source location resolutions from .swiftsourceinfo file @@ -599,32 +602,23 @@ bool swift::ide::CompletionInstance::performOperation( // We don't need token list. Invocation.getLangOptions().CollectParsedToken = false; - // FIXME: ASTScopeLookup doesn't support code completion yet. - Invocation.disableASTScopeLookup(); + // Compute the signature of the invocation. + llvm::hash_code ArgsHash(0); + for (auto arg : Args) + ArgsHash = llvm::hash_combine(ArgsHash, StringRef(arg)); - if (EnableASTCaching) { - // Compute the signature of the invocation. - llvm::hash_code ArgsHash(0); - for (auto arg : Args) - ArgsHash = llvm::hash_combine(ArgsHash, StringRef(arg)); - - // Concurrent completions will block so that they have higher chance to use - // the cached completion instance. - std::lock_guard lock(mtx); + // Concurrent completions will block so that they have higher chance to use + // the cached completion instance. + std::lock_guard lock(mtx); - if (performCachedOperationIfPossible(Invocation, ArgsHash, FileSystem, - completionBuffer, Offset, DiagC, - Callback)) - return true; + if (performCachedOperationIfPossible(ArgsHash, FileSystem, completionBuffer, + Offset, DiagC, Callback)) { + return true; + } - if (performNewOperation(ArgsHash, Invocation, FileSystem, completionBuffer, - Offset, Error, DiagC, Callback)) - return true; - } else { - // Concurrent completions may happen in parallel when caching is disabled. - if (performNewOperation(None, Invocation, FileSystem, completionBuffer, - Offset, Error, DiagC, Callback)) - return true; + if(performNewOperation(ArgsHash, Invocation, FileSystem, completionBuffer, + Offset, Error, DiagC, Callback)) { + return true; } assert(!Error.empty()); diff --git a/lib/IDE/ConformingMethodList.cpp b/lib/IDE/ConformingMethodList.cpp index 9a843b82f0cc0..f1fcf9f6f00e0 100644 --- a/lib/IDE/ConformingMethodList.cpp +++ b/lib/IDE/ConformingMethodList.cpp @@ -154,7 +154,7 @@ void ConformingMethodListCallbacks::getMatchingMethods( Result(result) {} void foundDecl(ValueDecl *VD, DeclVisibilityKind reason, - DynamicLookupInfo) { + DynamicLookupInfo) override { if (isMatchingMethod(VD) && !VD->shouldHideFromEditor()) Result.push_back(VD); } diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 787606e321891..904f42a949f24 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -46,9 +46,11 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) { while (isa(DC)) DC = DC->getParent(); - // Make sure the extension has been bound, in case it is in an inactive #if - // or something weird like that. + // Make sure the extension has been bound. { + // Even if the extension is invalid (e.g. nested in a function or another + // type), we want to know the "intended nominal" of the extension so that + // we can know the type of 'Self'. SmallVector extensions; for (auto typeCtx = DC->getInnermostTypeContext(); typeCtx != nullptr; typeCtx = typeCtx->getParent()->getInnermostTypeContext()) { @@ -59,6 +61,20 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) { extensions.back()->computeExtendedNominal(); extensions.pop_back(); } + + // If the completion happens in the inheritance clause of the extension, + // 'DC' is the parent of the extension. We need to iterate the top level + // decls to find it. In theory, we don't need the extended nominal in the + // inheritance clause, but ASTScope lookup requires that. We don't care + // unless 'DC' is not 'SourceFile' because non-toplevel extensions are + // 'canNeverBeBound()' anyway. + if (auto *SF = dyn_cast(DC)) { + auto &SM = DC->getASTContext().SourceMgr; + for (auto *decl : SF->getTopLevelDecls()) + if (auto *ext = dyn_cast(decl)) + if (SM.rangeContainsTokenLoc(ext->getSourceRange(), Loc)) + ext->computeExtendedNominal(); + } } // Type-check this context. @@ -85,6 +101,11 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) { typeCheckPatternBinding(PBD, i); } } + } else if (auto *defaultArg = dyn_cast(DC)) { + if (auto *AFD = dyn_cast(defaultArg->getParent())) { + auto *Param = AFD->getParameters()->get(defaultArg->getIndex()); + (void)Param->getTypeCheckedDefaultExpr(); + } } break; @@ -558,6 +579,31 @@ static void collectPossibleCalleesByQualifiedLookup( } } +/// For the given \p unresolvedMemberExpr, collect possible callee types and +/// declarations. +static bool collectPossibleCalleesForUnresolvedMember( + DeclContext &DC, UnresolvedMemberExpr *unresolvedMemberExpr, + SmallVectorImpl &candidates) { + auto collectMembers = [&](Type expectedTy) { + if (!expectedTy->mayHaveMembers()) + return; + collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy), + unresolvedMemberExpr->getName(), + candidates); + }; + + // Get the context of the expression itself. + ExprContextInfo contextInfo(&DC, unresolvedMemberExpr); + for (auto expectedTy : contextInfo.getPossibleTypes()) { + collectMembers(expectedTy); + // If this is an optional type, let's also check its base type. + if (auto baseTy = expectedTy->getOptionalObjectType()) { + collectMembers(baseTy->lookThroughAllOptionalTypes()); + } + } + return !candidates.empty(); +} + /// For the given \c callExpr, collect possible callee types and declarations. static bool collectPossibleCalleesForApply( DeclContext &DC, ApplyExpr *callExpr, @@ -599,6 +645,8 @@ static bool collectPossibleCalleesForApply( } else if (auto CRCE = dyn_cast(fnExpr)) { collectPossibleCalleesByQualifiedLookup( DC, CRCE->getArg(), DeclNameRef::createConstructor(), candidates); + } else if (auto *UME = dyn_cast(fnExpr)) { + collectPossibleCalleesForUnresolvedMember(DC, UME, candidates); } if (!candidates.empty()) @@ -662,39 +710,6 @@ static bool collectPossibleCalleesForSubscript( return !candidates.empty(); } -/// For the given \p unresolvedMemberExpr, collect possible callee types and -/// declarations. -static bool collectPossibleCalleesForUnresolvedMember( - DeclContext &DC, UnresolvedMemberExpr *unresolvedMemberExpr, - SmallVectorImpl &candidates) { - auto currModule = DC.getParentModule(); - - auto collectMembers = [&](Type expectedTy) { - if (!expectedTy->mayHaveMembers()) - return; - SmallVector members; - collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy), - unresolvedMemberExpr->getName(), - members); - for (auto member : members) { - if (isReferenceableByImplicitMemberExpr(currModule, &DC, expectedTy, - member.Decl)) - candidates.push_back(member); - } - }; - - // Get the context of the expression itself. - ExprContextInfo contextInfo(&DC, unresolvedMemberExpr); - for (auto expectedTy : contextInfo.getPossibleTypes()) { - collectMembers(expectedTy); - // If this is an optional type, let's also check its base type. - if (auto baseTy = expectedTy->getOptionalObjectType()) { - collectMembers(baseTy->lookThroughAllOptionalTypes()); - } - } - return !candidates.empty(); -} - /// Get index of \p CCExpr in \p Args. \p Args is usually a \c TupleExpr /// or \c ParenExpr. /// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args. @@ -761,11 +776,6 @@ class ExprContextAnalyzer { if (!collectPossibleCalleesForSubscript(*DC, subscriptExpr, Candidates)) return false; Arg = subscriptExpr->getIndex(); - } else if (auto *unresolvedMemberExpr = dyn_cast(E)) { - if (!collectPossibleCalleesForUnresolvedMember(*DC, unresolvedMemberExpr, - Candidates)) - return false; - Arg = unresolvedMemberExpr->getArgument(); } else { llvm_unreachable("unexpected expression kind"); } @@ -840,7 +850,6 @@ class ExprContextAnalyzer { switch (Parent->getKind()) { case ExprKind::Call: case ExprKind::Subscript: - case ExprKind::UnresolvedMember: case ExprKind::Binary: case ExprKind::PrefixUnary: { analyzeApplyExpr(Parent); @@ -848,8 +857,10 @@ class ExprContextAnalyzer { } case ExprKind::Array: { if (auto type = ParsedExpr->getType()) { - recordPossibleType(type); - break; + if (!type->is()) { + recordPossibleType(type); + break; + } } // Check context types of the array literal expression. @@ -1144,7 +1155,6 @@ class ExprContextAnalyzer { case ExprKind::Assign: case ExprKind::Dictionary: case ExprKind::If: - case ExprKind::UnresolvedMember: return true; case ExprKind::Array: return (!Parent.getAsExpr() || @@ -1153,8 +1163,7 @@ class ExprContextAnalyzer { auto ParentE = Parent.getAsExpr(); return !ParentE || (!isa(ParentE) && !isa(ParentE) && - !isa(ParentE) && - !isa(ParentE)); + !isa(ParentE)); } case ExprKind::Closure: return isSingleExpressionBodyForCodeCompletion( @@ -1228,73 +1237,3 @@ ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) { singleExpressionBody); Analyzer.Analyze(); } - -//===----------------------------------------------------------------------===// -// isReferenceableByImplicitMemberExpr(ModuleD, DeclContext, Type, ValueDecl) -//===----------------------------------------------------------------------===// - -bool swift::ide::isReferenceableByImplicitMemberExpr( - ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD) { - - if (VD->isOperator()) - return false; - - if (T->getOptionalObjectType() && - VD->getModuleContext()->isStdlibModule()) { - // In optional context, ignore '.init()', 'init(nilLiteral:)', - if (isa(VD)) - return false; - // TODO: Ignore '.some()' and '.none' too *in expression - // context*. They are useful in pattern context though. - } - - // Enum element decls can always be referenced by implicit member - // expression. - if (isa(VD)) - return true; - - // Only non-failable constructors are implicitly referenceable. - if (auto CD = dyn_cast(VD)) { - return (!CD->isFailable() || CD->isImplicitlyUnwrappedOptional()); - } - - // Otherwise, check the result type matches the contextual type. - auto declTy = T->getTypeOfMember(CurrModule, VD); - if (declTy->is()) - return false; - - // Member types can also be implicitly referenceable as long as it's - // convertible to the contextual type. - if (auto CD = dyn_cast(VD)) { - declTy = declTy->getMetatypeInstanceType(); - - // Emit construction for the same type via typealias doesn't make sense - // because we are emitting all `.init()`s. - if (declTy->isEqual(T)) - return false; - - // Only non-protocol nominal type can be instantiated. - auto nominal = declTy->getAnyNominal(); - if (!nominal || isa(nominal)) - return false; - - return swift::isConvertibleTo(declTy, T, /*openArchetypes=*/true, *DC); - } - - // Only static member can be referenced. - if (!VD->isStatic()) - return false; - - if (isa(VD)) { - // Strip '(Self.Type) ->' and parameters. - declTy = declTy->castTo()->getResult(); - declTy = declTy->castTo()->getResult(); - } else if (auto FT = declTy->getAs()) { - // The compiler accepts 'static var factory: () -> T' for implicit - // member expression. - // FIXME: This emits just 'factory'. We should emit 'factory()' instead. - declTy = FT->getResult(); - } - return declTy->isEqual(T) || - swift::isConvertibleTo(declTy, T, /*openArchetypes=*/true, *DC); -} diff --git a/lib/IDE/ExprContextAnalysis.h b/lib/IDE/ExprContextAnalysis.h index 1e0b749ac065c..9c957353b68e0 100644 --- a/lib/IDE/ExprContextAnalysis.h +++ b/lib/IDE/ExprContextAnalysis.h @@ -114,10 +114,6 @@ class ExprContextInfo { } }; -/// Returns whether \p VD is referenceable with implicit member expression. -bool isReferenceableByImplicitMemberExpr( - ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD); - } // namespace ide } // namespace swift diff --git a/lib/IDE/Formatting.cpp b/lib/IDE/Formatting.cpp index 69b9fc92f4b7a..6100a21d41669 100644 --- a/lib/IDE/Formatting.cpp +++ b/lib/IDE/Formatting.cpp @@ -61,6 +61,13 @@ getLocForContentStartOnSameLine(SourceManager &SM, SourceLoc Loc) { return LineStart.getAdvancedLoc(Indentation.size()); } +/// \returns true if the line at \c Loc is either empty or only contains whitespace +static bool isLineAtLocEmpty(SourceManager &SM, SourceLoc Loc) { + SourceLoc LineStart = Lexer::getLocForStartOfLine(SM, Loc); + SourceLoc Next = Lexer::getTokenAtLocation(SM, LineStart, CommentRetentionMode::ReturnAsTokens).getLoc(); + return Next.isInvalid() || !isOnSameLine(SM, Loc, Next); +} + /// \returns the first token after the token at \c Loc. static Optional getTokenAfter(SourceManager &SM, SourceLoc Loc, bool SkipComments = true) { @@ -136,6 +143,21 @@ static ClosureExpr *findTrailingClosureFromArgument(Expr *arg) { return nullptr; } +static size_t calcVisibleWhitespacePrefix(StringRef Line, + CodeFormatOptions Options) { + size_t Indent = 0; + for (auto Char : Line) { + if (Char == '\t') { + Indent += Options.TabWidth; + } else if (Char == ' ' || Char == '\v' || Char == '\f') { + Indent++; + } else { + break; + } + } + return Indent; +} + /// An indentation context of the target location struct IndentContext { enum ContextKind { Exact, LineStart }; @@ -258,16 +280,14 @@ class FormatContext { Optional InnermostCtx; bool InDocCommentBlock; bool InCommentLine; - bool InStringLiteral; public: FormatContext(SourceManager &SM, Optional IndentCtx, bool InDocCommentBlock = false, - bool InCommentLine = false, - bool InStringLiteral = false) + bool InCommentLine = false) :SM(SM), InnermostCtx(IndentCtx), InDocCommentBlock(InDocCommentBlock), - InCommentLine(InCommentLine), InStringLiteral(InStringLiteral) { } + InCommentLine(InCommentLine) { } bool IsInDocCommentBlock() { return InDocCommentBlock; @@ -277,10 +297,6 @@ class FormatContext { return InCommentLine; } - bool IsInStringLiteral() const { - return InStringLiteral; - } - void padToExactColumn(StringBuilder &Builder, const CodeFormatOptions &FmtOptions) { assert(isExact() && "Context is not exact?"); @@ -1208,8 +1224,9 @@ class FormatWalker : public ASTWalker { bool InDocCommentBlock = false; /// Whether the target location appears within a line comment. bool InCommentLine = false; - /// Whether the target location appears within a string literal. - bool InStringLiteral = false; + + /// The range of the string literal the target is inside of (if any, invalid otherwise). + CharSourceRange StringLiteralRange; public: explicit FormatWalker(SourceFile &SF, SourceManager &SM, CodeFormatOptions &Options) @@ -1224,7 +1241,8 @@ class FormatWalker : public ASTWalker { CtxOverride.clear(); TargetLocation = Loc; TargetLineLoc = Lexer::getLocForStartOfLine(SM, TargetLocation); - InDocCommentBlock = InCommentLine = InStringLiteral = false; + InDocCommentBlock = InCommentLine = false; + StringLiteralRange = CharSourceRange(); NodesToSkip.clear(); CurrentTokIt = TokenList.begin(); @@ -1234,14 +1252,99 @@ class FormatWalker : public ASTWalker { if (InnermostCtx) CtxOverride.applyIfNeeded(SM, *InnermostCtx); + if (StringLiteralRange.isValid()) { + assert(!InDocCommentBlock && !InCommentLine && + "Target is in both a string and comment"); + InnermostCtx = indentWithinStringLiteral(); + } else { + assert(!InDocCommentBlock || !InCommentLine && + "Target is in both a doc comment block and comment line"); + } + return FormatContext(SM, InnermostCtx, InDocCommentBlock, - InCommentLine, InStringLiteral); + InCommentLine); } +private: + + Optional indentWithinStringLiteral() { + assert(StringLiteralRange.isValid() && "Target is not within a string literal"); + + // This isn't ideal since if the user types """""" and then an enter + // inside after, we won't indent the end quotes. But indenting the end + // quotes could lead to an error in the rest of the string, so best to + // avoid it entirely for now. + if (isOnSameLine(SM, TargetLineLoc, StringLiteralRange.getEnd())) + return IndentContext {TargetLocation, false, IndentContext::Exact}; + + // If there's contents before the end quotes then it's likely the quotes + // are actually the start quotes of the next string in the file. Pretend + // they don't exist so their indent doesn't affect the indenting. + SourceLoc EndLineContentLoc = + getLocForContentStartOnSameLine(SM, StringLiteralRange.getEnd()); + bool HaveEndQuotes = CharSourceRange(SM, EndLineContentLoc, + StringLiteralRange.getEnd()) + .str().equals(StringRef("\"\"\"")); + + if (!HaveEndQuotes) { + // Indent to the same indentation level as the first non-empty line + // before the target. If that line is the start line then either use + // the same indentation of the start quotes if they are on their own + // line, or an extra indentation otherwise. + // + // This will indent lines with content on it as well, which should be + // fine since it is quite unlikely anyone would format a range that + // includes an unterminated string. + + SourceLoc AlignLoc = TargetLineLoc; + while (SM.isBeforeInBuffer(StringLiteralRange.getStart(), AlignLoc)) { + AlignLoc = Lexer::getLocForStartOfLine(SM, AlignLoc.getAdvancedLoc(-1)); + if (!isLineAtLocEmpty(SM, AlignLoc)) { + AlignLoc = getLocForContentStartOnSameLine(SM, AlignLoc); + break; + } + } + + if (isOnSameLine(SM, AlignLoc, StringLiteralRange.getStart())) { + SourceLoc StartLineContentLoc = + getLocForContentStartOnSameLine(SM, StringLiteralRange.getStart()); + bool StartLineOnlyQuotes = CharSourceRange(SM, StartLineContentLoc, + StringLiteralRange.getEnd()) + .str().startswith(StringRef("\"\"\"")); + if (!StartLineOnlyQuotes) + return IndentContext {StringLiteralRange.getStart(), true}; + + AlignLoc = StringLiteralRange.getStart(); + } + + return IndentContext {AlignLoc, false, IndentContext::Exact}; + } + + // If there are end quotes, only enforce a minimum indentation. We don't + // want to add any other indentation since that could add unintended + // whitespace to existing strings. Could change this if the full range + // was passed rather than a single line - in that case we *would* indent + // if the range was a single empty line. + + CharSourceRange TargetIndentRange = + CharSourceRange(SM, Lexer::getLocForStartOfLine(SM, TargetLocation), + TargetLocation); + CharSourceRange EndIndentRange = + CharSourceRange(SM, Lexer::getLocForStartOfLine(SM, EndLineContentLoc), + EndLineContentLoc); + + size_t TargetIndent = + calcVisibleWhitespacePrefix(TargetIndentRange.str(), FmtOptions); + size_t EndIndent = + calcVisibleWhitespacePrefix(EndIndentRange.str(), FmtOptions); + if (TargetIndent >= EndIndent) + return IndentContext {TargetLocation, false, IndentContext::Exact}; + + return IndentContext {EndLineContentLoc, false, IndentContext::Exact}; + } #pragma mark ASTWalker overrides and helpers -private: bool walkCustomAttributes(Decl *D) { // CustomAttrs of non-param VarDecls are handled when this method is called // on their containing PatternBindingDecls (below). @@ -1330,7 +1433,7 @@ class FormatWalker : public ASTWalker { SM.isBeforeInBuffer(E->getStartLoc(), TargetLocation) && SM.isBeforeInBuffer(TargetLocation, Lexer::getLocForEndOfToken(SM, E->getEndLoc()))) { - InStringLiteral = true; + StringLiteralRange = Lexer::getCharSourceRangeFromSourceRange(SM, E->getSourceRange()); } // Create a default indent context for all top-level expressions @@ -1352,7 +1455,7 @@ class FormatWalker : public ASTWalker { // Don't visit the child expressions of interpolated strings directly - // visit only the argument of each appendInterpolation call instead, and - // update InStringLiteral for each segment. + // set StringLiteralRange if needed for each segment. if (auto *ISL = dyn_cast(E)) { if (Action.shouldVisitChildren()) { llvm::SaveAndRestore(Parent, ISL); @@ -1364,7 +1467,8 @@ class FormatWalker : public ASTWalker { // Handle the preceeding string segment. CharSourceRange StringRange(SM, PrevStringStart, CE->getStartLoc()); if (StringRange.contains(TargetLocation)) { - InStringLiteral = true; + StringLiteralRange = + Lexer::getCharSourceRangeFromSourceRange(SM, E->getSourceRange()); return; } // Walk into the interpolation segment. @@ -1378,7 +1482,8 @@ class FormatWalker : public ASTWalker { SourceLoc End = Lexer::getLocForEndOfToken(SM, ISL->getStartLoc()); CharSourceRange StringRange(SM, PrevStringStart, End); if (StringRange.contains(TargetLocation)) - InStringLiteral = true; + StringLiteralRange = + Lexer::getCharSourceRangeFromSourceRange(SM, E->getSourceRange()); return {false, E}; } @@ -1467,7 +1572,7 @@ class FormatWalker : public ASTWalker { } void scanTokensUntil(SourceLoc Loc) { - if (InDocCommentBlock || InCommentLine) + if (InDocCommentBlock || InCommentLine || StringLiteralRange.isValid()) return; for (auto Invalid = Loc.isInvalid(); CurrentTokIt != TokenList.end() && (Invalid || SM.isBeforeInBuffer(CurrentTokIt->getLoc(), Loc)); @@ -1477,16 +1582,16 @@ class FormatWalker : public ASTWalker { SourceLoc StartLineLoc = Lexer::getLocForStartOfLine( SM, CommentRange.getStart()); - // The -1 is needed in case the past-the-end position is a newline - // character. In that case getLocForStartOfLine returns the start of - // the next line. SourceLoc EndLineLoc = Lexer::getLocForStartOfLine( - SM, CommentRange.getEnd().getAdvancedLoc(-1)); + SM, CommentRange.getEnd()); auto TokenStr = CurrentTokIt->getRange().str(); InDocCommentBlock |= SM.isBeforeInBuffer(StartLineLoc, TargetLineLoc) && !SM.isBeforeInBuffer(EndLineLoc, TargetLineLoc) && TokenStr.startswith("/*"); InCommentLine |= StartLineLoc == TargetLineLoc && TokenStr.startswith("//"); + } else if (CurrentTokIt->getKind() == tok::unknown && + CurrentTokIt->getRange().str().startswith("\"\"\"")) { + StringLiteralRange = CurrentTokIt->getRange(); } } } @@ -2797,12 +2902,6 @@ class CodeFormatter { std::pair indent(unsigned LineIndex, FormatContext &FC, StringRef Text) { - if (FC.IsInStringLiteral()) { - return std::make_pair( - LineRange(LineIndex, 1), - swift::ide::getTextForLine(LineIndex, Text, /*Trim*/ false).str()); - } - if (FC.isExact()) { StringRef Line = swift::ide::getTextForLine(LineIndex, Text, /*Trim*/true); StringBuilder Builder; diff --git a/tools/SourceKit/lib/Support/FuzzyStringMatcher.cpp b/lib/IDE/FuzzyStringMatcher.cpp similarity index 99% rename from tools/SourceKit/lib/Support/FuzzyStringMatcher.cpp rename to lib/IDE/FuzzyStringMatcher.cpp index 463d541d0d850..d016464691f19 100644 --- a/tools/SourceKit/lib/Support/FuzzyStringMatcher.cpp +++ b/lib/IDE/FuzzyStringMatcher.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,12 +10,13 @@ // //===----------------------------------------------------------------------===// -#include "SourceKit/Support/FuzzyStringMatcher.h" +#include "swift/IDE/FuzzyStringMatcher.h" #include "clang/Basic/CharInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" -using namespace SourceKit; +using namespace swift; +using namespace swift::ide; using clang::toUppercase; using clang::toLowercase; using clang::isUppercase; diff --git a/lib/IDE/Refactoring.cpp b/lib/IDE/Refactoring.cpp index 8c6bdcc01143e..e7838a606ce3e 100644 --- a/lib/IDE/Refactoring.cpp +++ b/lib/IDE/Refactoring.cpp @@ -1711,7 +1711,7 @@ class FindAllSubDecls : public SourceEntityWalker { FindAllSubDecls(llvm::SmallPtrSetImpl &found) : Found(found) {} - bool walkToDeclPre(Decl *D, CharSourceRange range) { + bool walkToDeclPre(Decl *D, CharSourceRange range) override { // Record this Decl, and skip its contents if we've already touched it. if (!Found.insert(D).second) return false; @@ -1876,7 +1876,7 @@ findConcatenatedExpressions(ResolvedRangeInfo Info, ASTContext &Ctx) { return true; } - bool walkToExprPre(Expr *E) { + bool walkToExprPre(Expr *E) override { if (E->isImplicit()) return true; // FIXME: we should have ErrorType instead of null. @@ -2001,13 +2001,13 @@ class ExpandableAssignTernaryExprInfo: public ExpandableTernaryExprInfo { public: ExpandableAssignTernaryExprInfo(AssignExpr *Assign): Assign(Assign) {} - IfExpr *getIf() { + IfExpr *getIf() override { if (!Assign) return nullptr; return dyn_cast_or_null(Assign->getSrc()); } - SourceRange getNameRange() { + SourceRange getNameRange() override { auto Invalid = SourceRange(); if (!Assign) @@ -2019,7 +2019,7 @@ class ExpandableAssignTernaryExprInfo: public ExpandableTernaryExprInfo { return Invalid; } - Type getType() { + Type getType() override { return nullptr; } @@ -2035,7 +2035,7 @@ class ExpandableBindingTernaryExprInfo: public ExpandableTernaryExprInfo { ExpandableBindingTernaryExprInfo(PatternBindingDecl *Binding): Binding(Binding) {} - IfExpr *getIf() { + IfExpr *getIf() override { if (Binding && Binding->getNumPatternEntries() == 1) { if (auto *Init = Binding->getInit(0)) { return dyn_cast(Init); @@ -2045,14 +2045,14 @@ class ExpandableBindingTernaryExprInfo: public ExpandableTernaryExprInfo { return nullptr; } - SourceRange getNameRange() { + SourceRange getNameRange() override { if (auto Pattern = getNamePattern()) return Pattern->getSourceRange(); return SourceRange(); } - Type getType() { + Type getType() override { if (auto Pattern = getNamePattern()) return Pattern->getType(); @@ -2347,7 +2347,7 @@ isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) { bool ConditionUseOnlyAllowedFunctions = false; StringRef ExpectName; - Expr *walkToExprPost(Expr *E) { + Expr *walkToExprPost(Expr *E) override { if (E->getKind() != ExprKind::DeclRef) return E; auto D = dyn_cast(E)->getDecl(); @@ -2446,7 +2446,7 @@ bool RefactoringActionConvertToSwitchStmt::performChange() { public: std::string VarName; - Expr *walkToExprPost(Expr *E) { + Expr *walkToExprPost(Expr *E) override { if (E->getKind() != ExprKind::DeclRef) return E; auto D = dyn_cast(E)->getDecl(); @@ -2463,7 +2463,7 @@ bool RefactoringActionConvertToSwitchStmt::performChange() { SmallString<64> ConditionalPattern = SmallString<64>(); - Expr *walkToExprPost(Expr *E) { + Expr *walkToExprPost(Expr *E) override { if (E->getKind() != ExprKind::Binary) return E; auto BE = dyn_cast(E); @@ -2472,7 +2472,7 @@ bool RefactoringActionConvertToSwitchStmt::performChange() { return E; } - std::pair walkToPatternPre(Pattern *P) { + std::pair walkToPatternPre(Pattern *P) override { ConditionalPattern.append(Lexer::getCharSourceRangeFromSourceRange(SM, P->getSourceRange()).str()); if (P->getKind() == PatternKind::OptionalSome) ConditionalPattern.append("?"); @@ -2705,7 +2705,7 @@ findConvertToTernaryExpression(ResolvedRangeInfo Info) { walk(S); } - virtual bool walkToExprPre(Expr *E) { + virtual bool walkToExprPre(Expr *E) override { Assign = dyn_cast(E); return false; } @@ -3086,7 +3086,7 @@ static Expr *findLocalizeTarget(ResolvedCursorInfo CursorInfo) { SourceLoc StartLoc; Expr *Target; StringLiteralFinder(SourceLoc StartLoc): StartLoc(StartLoc), Target(nullptr) {} - bool walkToExprPre(Expr *E) { + bool walkToExprPre(Expr *E) override { if (E->getStartLoc() != StartLoc) return false; if (E->getKind() == ExprKind::InterpolatedStringLiteral) diff --git a/lib/IDE/SourceEntityWalker.cpp b/lib/IDE/SourceEntityWalker.cpp index 6f6f08e9daf27..dd494e03cad25 100644 --- a/lib/IDE/SourceEntityWalker.cpp +++ b/lib/IDE/SourceEntityWalker.cpp @@ -715,6 +715,12 @@ passReference(ValueDecl *D, Type Ty, SourceLoc BaseNameLoc, SourceRange Range, } } + if (D == nullptr) { + // FIXME: When does this happen? + assert(false && "unhandled reference"); + return true; + } + CharSourceRange CharRange = Lexer::getCharSourceRangeFromSourceRange(D->getASTContext().SourceMgr, Range); diff --git a/lib/IDE/SwiftSourceDocInfo.cpp b/lib/IDE/SwiftSourceDocInfo.cpp index b372b1cba3e39..bd3edf9137b4e 100644 --- a/lib/IDE/SwiftSourceDocInfo.cpp +++ b/lib/IDE/SwiftSourceDocInfo.cpp @@ -24,6 +24,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/Module.h" +#include "clang/Basic/SourceManager.h" #include "clang/Index/USRGeneration.h" #include "clang/Lex/Lexer.h" #include "clang/Basic/CharInfo.h" @@ -282,10 +283,6 @@ Stmt *NameMatcher::walkToStmtPost(Stmt *S) { } Expr *NameMatcher::getApplicableArgFor(Expr *E) { - if (auto *UME = dyn_cast(E)) { - if (auto *Arg = UME->getArgument()) - return Arg; - } if (ParentCalls.empty()) return nullptr; auto &Last = ParentCalls.back(); diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 0d06879c184a7..7504a1b6bf183 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -905,7 +905,7 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) { AFD->getSignatureSourceRange()); if (FD) { SN.TypeRange = charSourceRangeFromSourceRange(SM, - FD->getBodyResultTypeLoc().getSourceRange()); + FD->getResultTypeSourceRange()); } pushStructureNode(SN, AFD); } else if (auto *NTD = dyn_cast(D)) { @@ -1096,7 +1096,7 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) { SN.NameRange = charSourceRangeFromSourceRange(SM, SubscriptD->getSignatureSourceRange()); SN.TypeRange = charSourceRangeFromSourceRange(SM, - SubscriptD->getElementTypeLoc().getSourceRange()); + SubscriptD->getElementTypeSourceRange()); pushStructureNode(SN, SubscriptD); } else if (auto *AssociatedTypeD = dyn_cast(D)) { SyntaxStructureNode SN; diff --git a/lib/IDE/TypeContextInfo.cpp b/lib/IDE/TypeContextInfo.cpp index aacaa875d96b3..0ab8242b7aa34 100644 --- a/lib/IDE/TypeContextInfo.cpp +++ b/lib/IDE/TypeContextInfo.cpp @@ -158,7 +158,7 @@ void ContextInfoCallbacks::getImplicitMembers( : DC(DC), CurModule(DC->getParentModule()), T(T), Result(Result) {} void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason, - DynamicLookupInfo) { + DynamicLookupInfo) override { if (canBeImplictMember(VD) && !VD->shouldHideFromEditor()) Result.push_back(VD); } diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index 616a0e6e0678f..0ee903e76caea 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -13,7 +13,9 @@ #include "swift/IDE/Utils.h" #include "swift/Basic/Edit.h" #include "swift/Basic/SourceManager.h" +#include "swift/Basic/Platform.h" #include "swift/ClangImporter/ClangModule.h" +#include "swift/Driver/FrontendUtil.h" #include "swift/Frontend/Frontend.h" #include "swift/Parse/Parser.h" #include "swift/Subsystems.h" @@ -24,8 +26,8 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Lex/PreprocessorOptions.h" -#include "clang/Serialization/ASTReader.h" #include "clang/Rewrite/Core/RewriteBuffer.h" +#include "clang/Serialization/ASTReader.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" @@ -188,6 +190,190 @@ ide::isSourceInputComplete(StringRef Text,SourceFileKind SFKind) { SFKind); } +static FrontendInputsAndOutputs resolveSymbolicLinksInInputs( + FrontendInputsAndOutputs &inputsAndOutputs, StringRef UnresolvedPrimaryFile, + llvm::IntrusiveRefCntPtr FileSystem, + std::string &Error) { + assert(FileSystem); + + llvm::SmallString<128> PrimaryFile; + if (auto err = FileSystem->getRealPath(UnresolvedPrimaryFile, PrimaryFile)) + PrimaryFile = UnresolvedPrimaryFile; + + unsigned primaryCount = 0; + // FIXME: The frontend should be dealing with symlinks, maybe similar to + // clang's FileManager ? + FrontendInputsAndOutputs replacementInputsAndOutputs; + for (const InputFile &input : inputsAndOutputs.getAllInputs()) { + llvm::SmallString<128> newFilename; + if (auto err = FileSystem->getRealPath(input.file(), newFilename)) + newFilename = input.file(); + llvm::sys::path::native(newFilename); + bool newIsPrimary = input.isPrimary() || + (!PrimaryFile.empty() && PrimaryFile == newFilename); + if (newIsPrimary) { + ++primaryCount; + } + assert(primaryCount < 2 && "cannot handle multiple primaries"); + replacementInputsAndOutputs.addInput( + InputFile(newFilename.str(), newIsPrimary, input.buffer())); + } + + if (PrimaryFile.empty() || primaryCount == 1) { + return replacementInputsAndOutputs; + } + + llvm::SmallString<64> Err; + llvm::raw_svector_ostream OS(Err); + OS << "'" << PrimaryFile << "' is not part of the input files"; + Error = std::string(OS.str()); + return replacementInputsAndOutputs; +} + +static void disableExpensiveSILOptions(SILOptions &Opts) { + // Disable the sanitizers. + Opts.Sanitizers = {}; + + // Disable PGO and code coverage. + Opts.GenerateProfile = false; + Opts.EmitProfileCoverageMapping = false; + Opts.UseProfile = ""; +} + +namespace { +class StreamDiagConsumer : public DiagnosticConsumer { + llvm::raw_ostream &OS; + +public: + StreamDiagConsumer(llvm::raw_ostream &OS) : OS(OS) {} + + void handleDiagnostic(SourceManager &SM, + const DiagnosticInfo &Info) override { + // FIXME: Print location info if available. + switch (Info.Kind) { + case DiagnosticKind::Error: + OS << "error: "; + break; + case DiagnosticKind::Warning: + OS << "warning: "; + break; + case DiagnosticKind::Note: + OS << "note: "; + break; + case DiagnosticKind::Remark: + OS << "remark: "; + break; + } + DiagnosticEngine::formatDiagnosticText(OS, Info.FormatString, + Info.FormatArgs); + } +}; +} // end anonymous namespace + +bool ide::initCompilerInvocation( + CompilerInvocation &Invocation, ArrayRef OrigArgs, + DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, + llvm::IntrusiveRefCntPtr FileSystem, + const std::string &runtimeResourcePath, + const std::string &diagnosticDocumentationPath, + bool shouldOptimizeForIDE, time_t sessionTimestamp, std::string &Error) { + SmallVector Args; + // Make sure to put '-resource-dir' and '-diagnostic-documentation-path' at + // the top to allow overriding them with the passed in arguments. + Args.push_back("-resource-dir"); + Args.push_back(runtimeResourcePath.c_str()); + Args.push_back("-Xfrontend"); + Args.push_back("-diagnostic-documentation-path"); + Args.push_back("-Xfrontend"); + Args.push_back(diagnosticDocumentationPath.c_str()); + Args.append(OrigArgs.begin(), OrigArgs.end()); + + SmallString<32> ErrStr; + llvm::raw_svector_ostream ErrOS(ErrStr); + StreamDiagConsumer DiagConsumer(ErrOS); + Diags.addConsumer(DiagConsumer); + + bool HadError = driver::getSingleFrontendInvocationFromDriverArguments( + Args, Diags, [&](ArrayRef FrontendArgs) { + return Invocation.parseArgs(FrontendArgs, Diags); + }, /*ForceNoOutputs=*/true); + + // Remove the StreamDiagConsumer as it's no longer needed. + Diags.removeConsumer(DiagConsumer); + + if (HadError) { + Error = std::string(ErrOS.str()); + return true; + } + + Invocation.getFrontendOptions().InputsAndOutputs = + resolveSymbolicLinksInInputs( + Invocation.getFrontendOptions().InputsAndOutputs, + UnresolvedPrimaryFile, FileSystem, Error); + if (!Error.empty()) + return true; + + ClangImporterOptions &ImporterOpts = Invocation.getClangImporterOptions(); + ImporterOpts.DetailedPreprocessingRecord = true; + + assert(!Invocation.getModuleName().empty()); + + auto &LangOpts = Invocation.getLangOptions(); + LangOpts.AttachCommentsToDecls = true; + LangOpts.DiagnosticsEditorMode = true; + LangOpts.CollectParsedToken = true; + if (LangOpts.PlaygroundTransform) { + // The playground instrumenter changes the AST in ways that disrupt the + // SourceKit functionality. Since we don't need the instrumenter, and all we + // actually need is the playground semantics visible to the user, like + // silencing the "expression resolves to an unused l-value" error, disable it. + LangOpts.PlaygroundTransform = false; + } + + // Disable the index-store functionality for the sourcekitd requests. + auto &FrontendOpts = Invocation.getFrontendOptions(); + FrontendOpts.IndexStorePath.clear(); + ImporterOpts.IndexStorePath.clear(); + + // Force the action type to be -typecheck. This affects importing the + // SwiftONoneSupport module. + FrontendOpts.RequestedAction = FrontendOptions::ActionType::Typecheck; + + // We don't care about LLVMArgs + FrontendOpts.LLVMArgs.clear(); + + // SwiftSourceInfo files provide source location information for decls coming + // from loaded modules. For most IDE use cases it either has an undesirable + // impact on performance with no benefit (code completion), results in stale + // locations being used instead of more up-to-date indexer locations (cursor + // info), or has no observable effect (diagnostics, which are filtered to just + // those with a location in the primary file, and everything else). + if (shouldOptimizeForIDE) + FrontendOpts.IgnoreSwiftSourceInfo = true; + + // To save the time for module validation, consider the lifetime of ASTManager + // as a single build session. + // NOTE: Do this only if '-disable-modules-validate-system-headers' is *not* + // explicitly enabled. + auto &SearchPathOpts = Invocation.getSearchPathOptions(); + if (!SearchPathOpts.DisableModulesValidateSystemDependencies) { + // NOTE: 'SessionTimestamp - 1' because clang compares it with '<=' that may + // cause unnecessary validations if they happens within one second + // from the SourceKit startup. + ImporterOpts.ExtraArgs.push_back("-fbuild-session-timestamp=" + + std::to_string(sessionTimestamp - 1)); + ImporterOpts.ExtraArgs.push_back( + "-fmodules-validate-once-per-build-session"); + + SearchPathOpts.DisableModulesValidateSystemDependencies = true; + } + + // Disable expensive SIL options to reduce time spent in SILGen. + disableExpensiveSILOptions(Invocation.getSILOptions()); + + return false; +} + // Adjust the cc1 triple string we got from clang, to make sure it will be // accepted when it goes through the swift clang importer. static std::string adjustClangTriple(StringRef TripleStr) { @@ -479,46 +665,6 @@ ide::replacePlaceholders(std::unique_ptr InputBuf, }); } -static std::string getPlistEntry(const llvm::Twine &Path, StringRef KeyName) { - auto BufOrErr = llvm::MemoryBuffer::getFile(Path); - if (!BufOrErr) { - llvm::errs() << "could not open '" << Path << "': " << BufOrErr.getError().message() << '\n'; - return {}; - } - - std::string Key = ""; - Key += KeyName; - Key += ""; - - StringRef Lines = BufOrErr.get()->getBuffer(); - while (!Lines.empty()) { - StringRef CurLine; - std::tie(CurLine, Lines) = Lines.split('\n'); - if (CurLine.find(Key) != StringRef::npos) { - std::tie(CurLine, Lines) = Lines.split('\n'); - unsigned Begin = CurLine.find("") + strlen(""); - unsigned End = CurLine.find(""); - return CurLine.substr(Begin, End - Begin).str(); - } - } - - return {}; -} - -std::string ide::getSDKName(StringRef Path) { - std::string Name = getPlistEntry(llvm::Twine(Path)+"/SDKSettings.plist", - "CanonicalName"); - if (Name.empty() && Path.endswith(".sdk")) { - Name = llvm::sys::path::filename(Path).drop_back(strlen(".sdk")).str(); - } - return Name; -} - -std::string ide::getSDKVersion(StringRef Path) { - return getPlistEntry(llvm::Twine(Path)+"/System/Library/CoreServices/" - "SystemVersion.plist", "ProductBuildVersion"); -} - // Modules failing to load are commented-out. static const char *OSXModuleList[] = { "AGL", diff --git a/lib/IRGen/GenArchetype.cpp b/lib/IRGen/GenArchetype.cpp index 84f9c98b2e55e..c81255520af49 100644 --- a/lib/IRGen/GenArchetype.cpp +++ b/lib/IRGen/GenArchetype.cpp @@ -284,8 +284,7 @@ const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) { // If the archetype is class-constrained, use a class pointer // representation. - if (archetype->requiresClass() || - (layout && layout->isRefCounted())) { + if (layout && layout->isRefCounted()) { auto refcount = archetype->getReferenceCounting(); llvm::PointerType *reprTy; diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 292c36e5ff718..bd530aac23ac9 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -727,6 +727,13 @@ namespace { case clang::Type::Pipe: llvm_unreachable("OpenCL type in ABI lowering?"); + case clang::Type::ExtInt: + llvm_unreachable("ExtInt type in ABI lowering?"); + + case clang::Type::ConstantMatrix: { + llvm_unreachable("ConstantMatrix type in ABI lowering?"); + } + case clang::Type::ConstantArray: { auto array = Ctx.getAsConstantArrayType(type); auto elt = Ctx.getCanonicalType(array->getElementType()); @@ -875,18 +882,9 @@ namespace { llvm_unreachable("OpenCL type in ABI lowering"); // We should never see the SVE types at all. - case clang::BuiltinType::SveInt8: - case clang::BuiltinType::SveInt16: - case clang::BuiltinType::SveInt32: - case clang::BuiltinType::SveInt64: - case clang::BuiltinType::SveUint8: - case clang::BuiltinType::SveUint16: - case clang::BuiltinType::SveUint32: - case clang::BuiltinType::SveUint64: - case clang::BuiltinType::SveFloat16: - case clang::BuiltinType::SveFloat32: - case clang::BuiltinType::SveFloat64: - case clang::BuiltinType::SveBool: +#define SVE_TYPE(Name, Id, ...) \ + case clang::BuiltinType::Id: +#include "clang/Basic/AArch64SVEACLETypes.def" llvm_unreachable("SVE type in ABI lowering"); // Handle all the integer types as opaque values. @@ -910,6 +908,8 @@ namespace { case clang::BuiltinType::Float16: llvm_unreachable("When upstream support is added for Float16 in " "clang::TargetInfo, use the implementation here"); + case clang::BuiltinType::BFloat16: + return convertFloatingType(Ctx.getTargetInfo().getBFloat16Format()); case clang::BuiltinType::Float128: return convertFloatingType(Ctx.getTargetInfo().getFloat128Format()); @@ -2110,7 +2110,8 @@ static void emitCoerceAndExpand(IRGenFunction &IGF, Explosion &in, Alignment(coercionTyLayout->getAlignment().value()); auto alloca = cast(temporary.getAddress()); if (alloca->getAlignment() < coercionTyAlignment.getValue()) { - alloca->setAlignment(llvm::MaybeAlign(coercionTyAlignment.getValue())); + alloca->setAlignment( + llvm::MaybeAlign(coercionTyAlignment.getValue()).valueOrOne()); temporary = Address(temporary.getAddress(), coercionTyAlignment); } @@ -2388,7 +2389,8 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee, auto ABIAlign = AI.getIndirectAlign(); if (ABIAlign > addr.getAlignment()) { auto *AS = cast(addr.getAddress()); - AS->setAlignment(llvm::MaybeAlign(ABIAlign.getQuantity())); + AS->setAlignment( + llvm::MaybeAlign(ABIAlign.getQuantity()).valueOrOne()); addr = Address(addr.getAddress(), Alignment(ABIAlign.getQuantity())); } } @@ -3080,7 +3082,8 @@ static void adjustAllocaAlignment(const llvm::DataLayout &DL, Alignment layoutAlignment = Alignment(layout->getAlignment().value()); auto alloca = cast(allocaAddr.getAddress()); if (alloca->getAlignment() < layoutAlignment.getValue()) { - alloca->setAlignment(llvm::MaybeAlign(layoutAlignment.getValue())); + alloca->setAlignment( + llvm::MaybeAlign(layoutAlignment.getValue()).valueOrOne()); allocaAddr = Address(allocaAddr.getAddress(), layoutAlignment); } } diff --git a/lib/IRGen/GenClangDecl.cpp b/lib/IRGen/GenClangDecl.cpp index 577307ce502d9..7679773935bf4 100644 --- a/lib/IRGen/GenClangDecl.cpp +++ b/lib/IRGen/GenClangDecl.cpp @@ -98,6 +98,11 @@ void IRGenModule::emitClangDecl(const clang::Decl *decl) { refFinder.TraverseDecl(executableDecl); next = executableDecl; } + + if (auto var = dyn_cast(next)) + if (!var->isFileVarDecl()) + continue; + ClangCodeGen->HandleTopLevelDecl(clang::DeclGroupRef(next)); } } diff --git a/lib/IRGen/GenClangType.cpp b/lib/IRGen/GenClangType.cpp index bc788fab6904a..8bc35dd99c134 100644 --- a/lib/IRGen/GenClangType.cpp +++ b/lib/IRGen/GenClangType.cpp @@ -132,10 +132,10 @@ namespace { /// ABI. class GenClangType : public CanTypeVisitor { IRGenModule &IGM; - ClangTypeConverter &Converter; + irgen::ClangTypeConverter &Converter; public: - GenClangType(IRGenModule &IGM, ClangTypeConverter &converter) + GenClangType(IRGenModule &IGM, irgen::ClangTypeConverter &converter) : IGM(IGM), Converter(converter) {} const clang::ASTContext &getClangASTContext() const { @@ -264,8 +264,8 @@ static clang::CanQualType getClangBuiltinTypeFromTypedef( } clang::CanQualType -ClangTypeConverter::reverseBuiltinTypeMapping(IRGenModule &IGM, - CanStructType type) { +irgen::ClangTypeConverter::reverseBuiltinTypeMapping(IRGenModule &IGM, + CanStructType type) { // Handle builtin types by adding entries to the cache that reverse // the mapping done by the importer. We could try to look at the // members of the struct instead, but even if that's ABI-equivalent @@ -748,7 +748,7 @@ clang::CanQualType GenClangType::visitType(CanType type) { llvm_unreachable("Unexpected type in Clang type generation."); } -clang::CanQualType ClangTypeConverter::convert(IRGenModule &IGM, CanType type) { +clang::CanQualType irgen::ClangTypeConverter::convert(IRGenModule &IGM, CanType type) { // Look in the cache. auto it = Cache.find(type); if (it != Cache.end()) { diff --git a/lib/IRGen/GenConstant.cpp b/lib/IRGen/GenConstant.cpp index 0d6e021e8327f..9f00592ab1d65 100644 --- a/lib/IRGen/GenConstant.cpp +++ b/lib/IRGen/GenConstant.cpp @@ -85,7 +85,8 @@ llvm::Constant *irgen::emitConstantZero(IRGenModule &IGM, BuiltinInst *BI) { if (auto vector = BI->getType().getAs()) { auto zero = helper(vector.getElementType()); - return llvm::ConstantVector::getSplat(vector->getNumElements(), zero); + return llvm::ConstantVector::getSplat( + llvm::ElementCount(vector->getNumElements(), /*scalable*/ false), zero); } return helper(BI->getType().getASTType()); diff --git a/lib/IRGen/GenCoverage.cpp b/lib/IRGen/GenCoverage.cpp index a5d2e6d512f6e..bdedf23c75619 100644 --- a/lib/IRGen/GenCoverage.cpp +++ b/lib/IRGen/GenCoverage.cpp @@ -23,19 +23,23 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" -#include "llvm/ProfileData/InstrProf.h" #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/FileSystem.h" +// This selects the coverage mapping format defined when `InstrProfData.inc` +// is textually included. +#define COVMAP_V3 + using namespace swift; using namespace irgen; -using llvm::coverage::CovMapVersion; using llvm::coverage::CounterMappingRegion; +using llvm::coverage::CovMapVersion; -static std::string getCoverageSection(IRGenModule &IGM) { - return llvm::getInstrProfSectionName(llvm::IPSK_covmap, - IGM.Triple.getObjectFormat()); +static std::string getInstrProfSection(IRGenModule &IGM, + llvm::InstrProfSectKind SK) { + return llvm::getInstrProfSectionName(SK, IGM.Triple.getObjectFormat()); } void IRGenModule::emitCoverageMapping() { @@ -63,8 +67,6 @@ void IRGenModule::emitCoverageMapping() { auto remapper = getOptions().CoveragePrefixMap; // Awkwardly munge absolute filenames into a vector of StringRefs. - // TODO: This is heinous - the same thing is happening in clang, but the API - // really needs to be cleaned up for both. llvm::SmallVector FilenameStrs; llvm::SmallVector FilenameRefs; for (StringRef Name : Files) { @@ -74,33 +76,31 @@ void IRGenModule::emitCoverageMapping() { FilenameRefs.push_back(FilenameStrs.back()); } - // Encode the filenames first. - std::string FilenamesAndCoverageMappings; - llvm::raw_string_ostream OS(FilenamesAndCoverageMappings); - llvm::coverage::CoverageFilenamesSectionWriter(FilenameRefs).write(OS); - size_t FilenamesSize = OS.str().size(); - size_t CurrentSize, PrevSize = FilenamesSize; - - // Now we need to build up the list of function records. + // Encode the filenames. + std::string Filenames; llvm::LLVMContext &Ctx = getLLVMContext(); - auto *Int32Ty = llvm::Type::getInt32Ty(Ctx); + { + llvm::raw_string_ostream OS(Filenames); + llvm::coverage::CoverageFilenamesSectionWriter(FilenameRefs).write(OS); + } + auto *FilenamesVal = + llvm::ConstantDataArray::getString(Ctx, Filenames, false); + const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames); + const size_t FilenamesSize = Filenames.size(); - llvm::Type *FunctionRecordTypes[] = { -#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType, -#include "llvm/ProfileData/InstrProfData.inc" -#undef COVMAP_FUNC_RECORD - }; + // Emit the function records. + auto *Int32Ty = llvm::Type::getInt32Ty(Ctx); + for (const auto &M : Mappings) { + StringRef NameValue = M->getPGOFuncName(); + assert(!NameValue.empty() && "Expected a named record"); + uint64_t FuncHash = M->getHash(); - auto FunctionRecordTy = - llvm::StructType::get(Ctx, llvm::makeArrayRef(FunctionRecordTypes), - /*isPacked=*/true); + const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue); + std::string FuncRecordName = "__covrec_" + llvm::utohexstr(NameHash); - std::vector FunctionRecords; - std::vector Regions; - for (const auto &M : Mappings) { unsigned FileID = std::find(Files.begin(), Files.end(), M->getFile()) - Files.begin(); - Regions.clear(); + std::vector Regions; for (const auto &MR : M->getMappedRegions()) Regions.emplace_back(CounterMappingRegion::makeRegion( MR.Counter, /*FileID=*/0, MR.StartLine, MR.StartCol, MR.EndLine, @@ -109,73 +109,70 @@ void IRGenModule::emitCoverageMapping() { ArrayRef VirtualFileMapping(FileID); llvm::coverage::CoverageMappingWriter W(VirtualFileMapping, M->getExpressions(), Regions); - W.write(OS); - - CurrentSize = OS.str().size(); - unsigned MappingLen = CurrentSize - PrevSize; - StringRef CoverageMapping(OS.str().c_str() + PrevSize, MappingLen); + std::string CoverageMapping; + { + llvm::raw_string_ostream OS(CoverageMapping); + W.write(OS); + } - StringRef NameValue = M->getPGOFuncName(); - assert(!NameValue.empty() && "Expected a named record"); - uint64_t FuncHash = M->getHash(); +#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType, + llvm::Type *FunctionRecordTypes[] = { +#include "llvm/ProfileData/InstrProfData.inc" + }; + auto *FunctionRecordTy = + llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes), + /*isPacked=*/true); - // Create a record for this function. - llvm::Constant *FunctionRecordVals[] = { + // Create the function record constant. #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init, + llvm::Constant *FunctionRecordVals[] = { #include "llvm/ProfileData/InstrProfData.inc" -#undef COVMAP_FUNC_RECORD }; - - FunctionRecords.push_back(llvm::ConstantStruct::get( - FunctionRecordTy, makeArrayRef(FunctionRecordVals))); - PrevSize = CurrentSize; - } - size_t CoverageMappingSize = PrevSize - FilenamesSize; - - // Append extra zeroes if necessary to ensure that the size of the filenames - // and coverage mappings is a multiple of 8. - if (size_t Rem = OS.str().size() % 8) { - CoverageMappingSize += 8 - Rem; - for (size_t I = 0, S = 8 - Rem; I < S; ++I) - OS << '\0'; + auto *FuncRecordConstant = llvm::ConstantStruct::get( + FunctionRecordTy, makeArrayRef(FunctionRecordVals)); + + // Create the function record global. + auto *FuncRecord = new llvm::GlobalVariable( + *getModule(), FunctionRecordTy, /*isConstant=*/true, + llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant, + FuncRecordName); + FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility); + FuncRecord->setSection(getInstrProfSection(*this, llvm::IPSK_covfun)); + FuncRecord->setAlignment(llvm::Align(8)); + if (Triple.supportsCOMDAT()) + FuncRecord->setComdat(getModule()->getOrInsertComdat(FuncRecordName)); + + // Make sure the data doesn't get deleted. + addUsedGlobal(FuncRecord); } - auto *FilenamesAndMappingsVal = - llvm::ConstantDataArray::getString(Ctx, OS.str(), false); - - auto *RecordsTy = - llvm::ArrayType::get(FunctionRecordTy, FunctionRecords.size()); - auto *RecordsVal = llvm::ConstantArray::get(RecordsTy, FunctionRecords); // Create the coverage data header. + const unsigned NRecords = 0; + const unsigned CoverageMappingSize = 0; llvm::Type *CovDataHeaderTypes[] = { #define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType, #include "llvm/ProfileData/InstrProfData.inc" -#undef COVMAP_HEADER }; - auto *CovDataHeaderTy = + auto CovDataHeaderTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes)); llvm::Constant *CovDataHeaderVals[] = { #define COVMAP_HEADER(Type, LLVMType, Name, Init) Init, #include "llvm/ProfileData/InstrProfData.inc" -#undef COVMAP_HEADER }; - auto *CovDataHeaderVal = llvm::ConstantStruct::get( + auto CovDataHeaderVal = llvm::ConstantStruct::get( CovDataHeaderTy, makeArrayRef(CovDataHeaderVals)); - // Combine the header, function records, and mappings together. - llvm::Type *CovDataTypes[] = {CovDataHeaderTy, RecordsTy, - FilenamesAndMappingsVal->getType()}; - auto *CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes)); - llvm::Constant *TUDataVals[] = {CovDataHeaderVal, RecordsVal, - FilenamesAndMappingsVal}; - auto *CovDataVal = + // Create the coverage data record + llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()}; + auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes)); + llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal}; + auto CovDataVal = llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals)); - auto CovData = new llvm::GlobalVariable( - *getModule(), CovDataTy, true, llvm::GlobalValue::InternalLinkage, + *getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage, CovDataVal, llvm::getCoverageMappingVarName()); - std::string CovSection = getCoverageSection(*this); - CovData->setSection(CovSection); - CovData->setAlignment(llvm::MaybeAlign(8)); + + CovData->setSection(getInstrProfSection(*this, llvm::IPSK_covmap)); + CovData->setAlignment(llvm::Align(8)); addUsedGlobal(CovData); } diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 5029660d88834..09a8c9d5166bb 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -449,13 +449,15 @@ void IRGenModule::emitSourceFile(SourceFile &SF) { // Emit types and other global decls. for (auto *decl : SF.getTopLevelDecls()) emitGlobalDecl(decl); + for (auto *decl : SF.getHoistedDecls()) + emitGlobalDecl(decl); for (auto *localDecl : SF.LocalTypeDecls) emitGlobalDecl(localDecl); for (auto *opaqueDecl : SF.getOpaqueReturnTypeDecls()) maybeEmitOpaqueTypeDecl(opaqueDecl); SF.collectLinkLibraries([this](LinkLibrary linkLib) { - this->addLinkLibrary(linkLib); + this->addLinkLibrary(linkLib); }); if (ObjCInterop) @@ -1164,18 +1166,32 @@ void IRGenerator::emitTypeMetadataRecords() { } } +static void +deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( + IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization, + NominalTypeDecl &decl) { + IGM.IRGen.noteLazyReemissionOfNominalTypeDescriptor(&decl); + // The type context descriptor depends on canonical metadata records because + // pointers to them are attached as trailing objects to it. + // + // Don't call + // + // noteUseOfTypeContextDescriptor + // + // here because we don't want to reemit metadata. + emitLazyTypeContextDescriptor(IGM, &decl, RequireMetadata); +} + /// Emit any lazy definitions (of globals or functions or whatever /// else) that we require. void IRGenerator::emitLazyDefinitions() { while (!LazyTypeMetadata.empty() || !LazySpecializedTypeMetadataRecords.empty() || !LazyTypeContextDescriptors.empty() || - !LazyOpaqueTypeDescriptors.empty() || - !LazyFieldDescriptors.empty() || - !LazyFunctionDefinitions.empty() || - !LazyWitnessTables.empty() || - !LazyCanonicalSpecializedMetadataAccessors.empty()) { - + !LazyOpaqueTypeDescriptors.empty() || !LazyFieldDescriptors.empty() || + !LazyFunctionDefinitions.empty() || !LazyWitnessTables.empty() || + !LazyCanonicalSpecializedMetadataAccessors.empty() || + !LazyMetadataAccessors.empty()) { // Emit any lazy type metadata we require. while (!LazyTypeMetadata.empty()) { NominalTypeDecl *type = LazyTypeMetadata.pop_back_val(); @@ -1187,10 +1203,23 @@ void IRGenerator::emitLazyDefinitions() { emitLazyTypeMetadata(*IGM.get(), type); } while (!LazySpecializedTypeMetadataRecords.empty()) { - CanType type = LazySpecializedTypeMetadataRecords.pop_back_val(); - auto *nominal = type->getNominalOrBoundGenericNominal(); - CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext()); - emitLazySpecializedGenericTypeMetadata(*IGM.get(), type); + CanType theType; + TypeMetadataCanonicality canonicality; + std::tie(theType, canonicality) = + LazySpecializedTypeMetadataRecords.pop_back_val(); + auto *nominal = theType->getNominalOrBoundGenericNominal(); + CurrentIGMPtr IGMPtr = getGenModule(nominal->getDeclContext()); + auto &IGM = *IGMPtr.get(); + // A new canonical prespecialized metadata changes both the type + // descriptor (adding a new entry to the trailing list of metadata) and + // the metadata accessor (adding a new list of generic arguments against + // which to compare the arguments to the function). Consequently, it is + // necessary to force these to be reemitted. + if (canonicality == TypeMetadataCanonicality::Canonical) { + deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( + IGM, theType, *nominal); + } + emitLazySpecializedGenericTypeMetadata(IGM, theType); } while (!LazyTypeContextDescriptors.empty()) { NominalTypeDecl *type = LazyTypeContextDescriptors.pop_back_val(); @@ -1236,17 +1265,25 @@ void IRGenerator::emitLazyDefinitions() { LazyCanonicalSpecializedMetadataAccessors.pop_back_val(); auto *nominal = theType->getAnyNominal(); assert(nominal); + CurrentIGMPtr IGMPtr = getGenModule(nominal->getDeclContext()); + auto &IGM = *IGMPtr.get(); + // TODO: Once non-canonical accessors are available, this variable should + // reflect the canonicality of the accessor rather than always being + // canonical. + auto canonicality = TypeMetadataCanonicality::Canonical; + if (canonicality == TypeMetadataCanonicality::Canonical) { + deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( + IGM, theType, *nominal); + } + emitLazyCanonicalSpecializedMetadataAccessor(IGM, theType); + } + while (!LazyMetadataAccessors.empty()) { + NominalTypeDecl *nominal = LazyMetadataAccessors.pop_back_val(); CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext()); - emitLazyCanonicalSpecializedMetadataAccessor(*IGM.get(), theType); + emitLazyMetadataAccessor(*IGM.get(), nominal); } } - while (!LazyMetadataAccessors.empty()) { - NominalTypeDecl *nominal = LazyMetadataAccessors.pop_back_val(); - CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext()); - emitLazyMetadataAccessor(*IGM.get(), nominal); - } - FinishedEmittingLazyDefinitions = true; } @@ -1442,17 +1479,19 @@ static bool typeKindCanBePrespecialized(TypeKind theKind) { } } -void IRGenerator::noteUseOfSpecializedGenericTypeMetadata(CanType type) { - assert(typeKindCanBePrespecialized(type->getKind())); - auto key = type->getAnyNominal(); +void IRGenerator::noteUseOfSpecializedGenericTypeMetadata( + IRGenModule &IGM, CanType theType, TypeMetadataCanonicality canonicality) { + assert(typeKindCanBePrespecialized(theType->getKind())); + auto key = theType->getAnyNominal(); assert(key); assert(key->isGenericContext()); - auto &enqueuedSpecializedTypes = CanonicalSpecializationsForGenericTypes[key]; + auto &enqueuedSpecializedTypes = + MetadataPrespecializationsForGenericTypes[key]; if (llvm::all_of(enqueuedSpecializedTypes, - [&](CanType enqueued) { return enqueued != type; })) { + [&](auto enqueued) { return enqueued.first != theType; })) { assert(!FinishedEmittingLazyDefinitions); - LazySpecializedTypeMetadataRecords.push_back(type); - enqueuedSpecializedTypes.push_back(type); + LazySpecializedTypeMetadataRecords.push_back({theType, canonicality}); + enqueuedSpecializedTypes.push_back({theType, canonicality}); } } @@ -2024,8 +2063,10 @@ llvm::Function *irgen::createFunction(IRGenModule &IGM, IGM.Module.getFunctionList().push_back(fn); } - ApplyIRLinkage({linkInfo.getLinkage(), linkInfo.getVisibility(), linkInfo.getDLLStorage()}) - .to(fn); + ApplyIRLinkage({linkInfo.getLinkage(), + linkInfo.getVisibility(), + linkInfo.getDLLStorage()}) + .to(fn, linkInfo.isForDefinition()); llvm::AttrBuilder initialAttrs; IGM.constructInitialFnAttributes(initialAttrs, FuncOptMode); @@ -2082,7 +2123,7 @@ llvm::GlobalVariable *swift::irgen::createVariable( ApplyIRLinkage({linkInfo.getLinkage(), linkInfo.getVisibility(), linkInfo.getDLLStorage()}) - .to(var); + .to(var, linkInfo.isForDefinition()); var->setAlignment(llvm::MaybeAlign(alignment.getValue())); // Everything externally visible is considered used in Swift. @@ -3864,6 +3905,19 @@ llvm::GlobalValue *IRGenModule::defineAlias(LinkEntity entity, if (entry) { auto existingVal = cast(entry); + for (auto iterator = std::begin(LLVMUsed); iterator < std::end(LLVMUsed); ++iterator) { + llvm::Value *thisValue = *iterator; + if (thisValue == existingVal) { + LLVMUsed.erase(iterator); + } + } + for (auto iterator = std::begin(LLVMCompilerUsed); iterator < std::end(LLVMCompilerUsed); ++iterator) { + llvm::Value *thisValue = *iterator; + if (thisValue == existingVal) { + LLVMCompilerUsed.erase(iterator); + } + } + // FIXME: MC breaks when emitting alias references on some platforms // (rdar://problem/22450593 ). Work around this by referring to the aliasee // instead. @@ -3902,32 +3956,14 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType, return cast(addr); } - /// For concrete metadata, we want to use the initializer on the - /// "full metadata", and define the "direct" address point as an alias. - TypeMetadataAddress addrKind; - unsigned adjustmentIndex; - - auto nominal = concreteType->getAnyNominal(); - - // Native Swift class metadata has a destructor before the address point. - // Foreign class metadata candidates do not, and neither does value type - // metadata. - if (nominal && isa(nominal) && - !requiresForeignTypeMetadata(nominal)) { - addrKind = TypeMetadataAddress::FullMetadata; - adjustmentIndex = MetadataAdjustmentIndex::Class; - } else { - addrKind = TypeMetadataAddress::FullMetadata; - adjustmentIndex = MetadataAdjustmentIndex::ValueType; - } - auto entity = (isPrespecialized && !irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable( *this, concreteType)) ? LinkEntity::forNoncanonicalSpecializedGenericTypeMetadata( concreteType) - : LinkEntity::forTypeMetadata(concreteType, addrKind); + : LinkEntity::forTypeMetadata(concreteType, + TypeMetadataAddress::FullMetadata); auto DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType), entity.getDefaultDeclarationType(*this)->getPointerTo(), @@ -3945,30 +3981,35 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType, if (link.isUsed()) addUsedGlobal(var); - // Keep type metadata around for all types. - if (nominal) + /// For concrete metadata, we want to use the initializer on the + /// "full metadata", and define the "direct" address point as an alias. + unsigned adjustmentIndex = MetadataAdjustmentIndex::ValueType; + + if (auto nominal = concreteType->getAnyNominal()) { + // Keep type metadata around for all types. addRuntimeResolvableType(nominal); - // Don't define the alias for foreign type metadata or prespecialized generic - // metadata, since neither is ABI. - if ((nominal && requiresForeignTypeMetadata(nominal)) || isPrespecialized) - return var; + // Don't define the alias for foreign type metadata or prespecialized + // generic metadata, since neither is ABI. + if (requiresForeignTypeMetadata(nominal) || isPrespecialized) + return var; - // For concrete metadata, declare the alias to its address point. - auto directEntity = LinkEntity::forTypeMetadata(concreteType, - TypeMetadataAddress::AddressPoint); + // Native Swift class metadata has a destructor before the address point. + if (isa(nominal)) { + adjustmentIndex = MetadataAdjustmentIndex::Class; + } + } - llvm::Constant *addr = var; - // Do an adjustment if necessary. - if (adjustmentIndex) { - llvm::Constant *indices[] = { + llvm::Constant *indices[] = { llvm::ConstantInt::get(Int32Ty, 0), - llvm::ConstantInt::get(Int32Ty, adjustmentIndex) - }; - addr = llvm::ConstantExpr::getInBoundsGetElementPtr(/*Ty=*/nullptr, - addr, indices); - } + llvm::ConstantInt::get(Int32Ty, adjustmentIndex)}; + auto addr = llvm::ConstantExpr::getInBoundsGetElementPtr(/*Ty=*/nullptr, var, + indices); addr = llvm::ConstantExpr::getBitCast(addr, TypeMetadataPtrTy); + + // For concrete metadata, declare the alias to its address point. + auto directEntity = LinkEntity::forTypeMetadata( + concreteType, TypeMetadataAddress::AddressPoint); return defineAlias(directEntity, addr); } @@ -3989,15 +4030,17 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, auto nominal = concreteType->getAnyNominal(); - llvm::Type *defaultVarTy; - unsigned adjustmentIndex; - bool foreign = nominal && requiresForeignTypeMetadata(nominal); + + // Foreign classes and prespecialized generic types do not use an alias into + // the full metadata and therefore require a GEP. bool fullMetadata = foreign || (concreteType->getAnyGeneric() && concreteType->getAnyGeneric()->isGenericContext()); - // Foreign classes reference the full metadata with a GEP. + llvm::Type *defaultVarTy; + unsigned adjustmentIndex; + if (fullMetadata) { defaultVarTy = FullTypeMetadataStructTy; if (concreteType->getClassOrBoundGenericClass() && !foreign) { @@ -4005,9 +4048,9 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, } else { adjustmentIndex = MetadataAdjustmentIndex::ValueType; } - // The symbol for other nominal type metadata is generated at the address - // point. } else if (nominal) { + // The symbol for native non-generic nominal type metadata is generated at + // the aliased address point (see defineTypeMetadata() above). assert(!nominal->hasClangNode()); defaultVarTy = TypeMetadataStructTy; @@ -4030,7 +4073,8 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, if (shouldPrespecializeGenericMetadata()) { if (auto nominal = concreteType->getAnyNominal()) { if (nominal->isGenericContext()) { - IRGen.noteUseOfSpecializedGenericTypeMetadata(concreteType); + IRGen.noteUseOfSpecializedGenericTypeMetadata(*this, concreteType, + canonicality); } } } @@ -4040,13 +4084,9 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, switch (canonicality) { case TypeMetadataCanonicality::Canonical: - if (fullMetadata) { - entity = LinkEntity::forTypeMetadata(concreteType, - TypeMetadataAddress::FullMetadata); - } else { - entity = LinkEntity::forTypeMetadata(concreteType, - TypeMetadataAddress::AddressPoint); - } + entity = LinkEntity::forTypeMetadata( + concreteType, fullMetadata ? TypeMetadataAddress::FullMetadata + : TypeMetadataAddress::AddressPoint); break; case TypeMetadataCanonicality::Noncanonical: entity = @@ -4403,7 +4443,7 @@ static Address getAddrOfSimpleVariable(IRGenModule &IGM, // Check whether it's already cached. llvm::Constant *&entry = cache[entity]; if (entry) { - auto existing = cast(entry); + auto existing = cast(entry); assert(alignment == Alignment(existing->getAlignment())); if (forDefinition) updateLinkageForDefinition(IGM, existing, entity); return Address(entry, alignment); @@ -4562,7 +4602,7 @@ Address IRGenFunction::createAlloca(llvm::Type *type, llvm::AllocaInst *alloca = new llvm::AllocaInst(type, IGM.DataLayout.getAllocaAddrSpace(), name, AllocaIP); - alloca->setAlignment(llvm::MaybeAlign(alignment.getValue())); + alloca->setAlignment(llvm::MaybeAlign(alignment.getValue()).valueOrOne()); return Address(alloca, alignment); } @@ -4573,7 +4613,7 @@ Address IRGenFunction::createAlloca(llvm::Type *type, const llvm::Twine &name) { llvm::AllocaInst *alloca = new llvm::AllocaInst( type, IGM.DataLayout.getAllocaAddrSpace(), ArraySize, - llvm::MaybeAlign(alignment.getValue()), name, AllocaIP); + llvm::MaybeAlign(alignment.getValue()).valueOrOne(), name, AllocaIP); return Address(alloca, alignment); } @@ -4753,7 +4793,7 @@ IRGenModule::getAddrOfWitnessTableLazyAccessFunction( LinkInfo link = LinkInfo::get(*this, entity, forDefinition); entry = createFunction(*this, link, signature); ApplyIRLinkage({link.getLinkage(), link.getVisibility(), link.getDLLStorage()}) - .to(entry); + .to(entry, link.isForDefinition()); return entry; } diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index dad7aaf4a0381..a2666b7fad980 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -110,6 +110,7 @@ #include "swift/AST/LazyResolver.h" #include "swift/IRGen/Linking.h" #include "swift/SIL/SILModule.h" +#include "llvm/IR/CFG.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/Analysis/CFG.h" diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index d0577f975b1fc..19af4890b3bc0 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -1334,7 +1334,7 @@ void IRGenModule::emitSILProperty(SILProperty *prop) { ApplyIRLinkage({linkInfo.getLinkage(), linkInfo.getVisibility(), llvm::GlobalValue::DLLExportStorageClass}) - .to(GA); + .to(GA, linkInfo.isForDefinition()); } return; } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 9d28264fec78f..076cc1bea41a1 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -300,7 +300,13 @@ static void buildMethodDescriptorFields(IRGenModule &IGM, void IRGenModule::emitNonoverriddenMethodDescriptor(const SILVTable *VTable, SILDeclRef declRef) { - + auto entity = LinkEntity::forMethodDescriptor(declRef); + auto *var = cast(getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo())); + if (!var->isDeclaration()) { + assert(IRGen.isLazilyReemittingNominalTypeDescriptor(VTable->getClass())); + return; + } + ConstantInitBuilder ib(*this); ConstantStructBuilder sb(ib.beginStruct(MethodDescriptorStructTy)); @@ -308,7 +314,6 @@ void IRGenModule::emitNonoverriddenMethodDescriptor(const SILVTable *VTable, auto init = sb.finishAndCreateFuture(); - auto entity = LinkEntity::forMethodDescriptor(declRef); getAddrOfLLVMVariable(entity, init, DebugTypeInfo()); } @@ -1215,6 +1220,7 @@ namespace { void setCommonFlags(TypeContextDescriptorFlags &flags) { setClangImportedFlags(flags); setMetadataInitializationKind(flags); + setHasCanonicalMetadataPrespecializations(flags); } void setClangImportedFlags(TypeContextDescriptorFlags &flags) { @@ -1248,6 +1254,19 @@ namespace { flags.setMetadataInitialization(MetadataInitialization); } + void setHasCanonicalMetadataPrespecializations(TypeContextDescriptorFlags &flags) { + flags.setHasCanonicalMetadataPrespecializations(hasCanonicalMetadataPrespecializations()); + } + + bool hasCanonicalMetadataPrespecializations() { + return IGM.shouldPrespecializeGenericMetadata() && + llvm::any_of(IGM.IRGen.metadataPrespecializationsForType(Type), + [](auto pair) { + return pair.second == + TypeMetadataCanonicality::Canonical; + }); + } + void maybeAddMetadataInitialization() { switch (MetadataInitialization) { case TypeContextDescriptorFlags::NoMetadataInitialization: @@ -1307,6 +1326,28 @@ namespace { addIncompleteMetadata(); } + void maybeAddCanonicalMetadataPrespecializations() { + if (Type->isGenericContext() && hasCanonicalMetadataPrespecializations()) { + asImpl().addCanonicalMetadataPrespecializations(); + } + } + + void addCanonicalMetadataPrespecializations() { + auto specializations = IGM.IRGen.metadataPrespecializationsForType(Type); + auto count = llvm::count_if(specializations, [](auto pair) { + return pair.second == TypeMetadataCanonicality::Canonical; + }); + B.addInt32(count); + for (auto pair : specializations) { + if (pair.second != TypeMetadataCanonicality::Canonical) { + continue; + } + auto specialization = pair.first; + auto *metadata = IGM.getAddrOfTypeMetadata(specialization); + B.addRelativeAddress(metadata); + } + } + // Subclasses should provide: // ContextDescriptorKind getContextKind(); // void addLayoutInfo(); @@ -1334,6 +1375,11 @@ namespace { FieldVectorOffset = layout.getFieldOffsetVectorOffset().getStatic(); } + void layout() { + super::layout(); + maybeAddCanonicalMetadataPrespecializations(); + } + ContextDescriptorKind getContextKind() { return ContextDescriptorKind::Struct; } @@ -1394,6 +1440,11 @@ namespace { if (layout.hasPayloadSizeOffset()) PayloadSizeOffset = layout.getPayloadSizeOffset().getStatic(); } + + void layout() { + super::layout(); + maybeAddCanonicalMetadataPrespecializations(); + } ContextDescriptorKind getContextKind() { return ContextDescriptorKind::Enum; @@ -1508,6 +1559,7 @@ namespace { addVTable(); addOverrideTable(); addObjCResilientClassStubInfo(); + maybeAddCanonicalMetadataPrespecializations(); } void addIncompleteMetadataOrRelocationFunction() { @@ -1780,6 +1832,19 @@ namespace { getType(), NotForDefinition, TypeMetadataAddress::AddressPoint)); } + + void addCanonicalMetadataPrespecializations() { + super::addCanonicalMetadataPrespecializations(); + auto specializations = IGM.IRGen.metadataPrespecializationsForType(Type); + for (auto pair : specializations) { + if (pair.second != TypeMetadataCanonicality::Canonical) { + continue; + } + auto specialization = pair.first; + auto *function = IGM.getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction(specialization, NotForDefinition); + B.addRelativeAddress(function); + } + } }; class OpaqueTypeDescriptorBuilder @@ -3635,7 +3700,7 @@ static void emitObjCClassSymbol(IRGenModule &IGM, ptrTy->getElementType(), ptrTy->getAddressSpace(), link.getLinkage(), link.getName(), metadata, &IGM.Module); ApplyIRLinkage({link.getLinkage(), link.getVisibility(), link.getDLLStorage()}) - .to(alias); + .to(alias, link.isForDefinition()); } /// Emit the type metadata or metadata template for a class. diff --git a/lib/IRGen/GenOpaque.cpp b/lib/IRGen/GenOpaque.cpp index a01ff1ad59adc..96f09d622a47b 100644 --- a/lib/IRGen/GenOpaque.cpp +++ b/lib/IRGen/GenOpaque.cpp @@ -575,7 +575,7 @@ StackAddress IRGenFunction::emitDynamicAlloca(llvm::Type *eltTy, // Emit the dynamic alloca. auto *alloca = Builder.IRBuilderBase::CreateAlloca(eltTy, arraySize, name); - alloca->setAlignment(llvm::MaybeAlign(align.getValue())); + alloca->setAlignment(llvm::MaybeAlign(align.getValue()).valueOrOne()); assert(!isInEntryBlock || getActiveDominancePoint().isUniversal() && diff --git a/lib/IRGen/GenThunk.cpp b/lib/IRGen/GenThunk.cpp index 74d862df8d567..c3bc0844433ce 100644 --- a/lib/IRGen/GenThunk.cpp +++ b/lib/IRGen/GenThunk.cpp @@ -102,6 +102,9 @@ static FunctionPointer lookupMethod(IRGenFunction &IGF, SILDeclRef declRef) { void IRGenModule::emitDispatchThunk(SILDeclRef declRef) { auto *f = getAddrOfDispatchThunk(declRef, ForDefinition); + if (!f->isDeclaration()) { + return; + } IRGenFunction IGF(*this, f); @@ -163,6 +166,10 @@ IRGenModule::getAddrOfMethodLookupFunction(ClassDecl *classDecl, void IRGenModule::emitMethodLookupFunction(ClassDecl *classDecl) { auto *f = getAddrOfMethodLookupFunction(classDecl, ForDefinition); + if (!f->isDeclaration()) { + assert(IRGen.isLazilyReemittingNominalTypeDescriptor(classDecl)); + return; + } IRGenFunction IGF(*this, f); diff --git a/lib/IRGen/IRBuilder.h b/lib/IRGen/IRBuilder.h index 69ecb3de278bb..4eaa167b26f49 100644 --- a/lib/IRGen/IRBuilder.h +++ b/lib/IRGen/IRBuilder.h @@ -125,7 +125,7 @@ class IRBuilder : public IRBuilderBase { llvm::LoadInst *CreateLoad(llvm::Value *addr, Alignment align, const llvm::Twine &name = "") { llvm::LoadInst *load = IRBuilderBase::CreateLoad(addr, name); - load->setAlignment(llvm::MaybeAlign(align.getValue())); + load->setAlignment(llvm::MaybeAlign(align.getValue()).valueOrOne()); return load; } llvm::LoadInst *CreateLoad(Address addr, const llvm::Twine &name = "") { @@ -135,7 +135,7 @@ class IRBuilder : public IRBuilderBase { llvm::StoreInst *CreateStore(llvm::Value *value, llvm::Value *addr, Alignment align) { llvm::StoreInst *store = IRBuilderBase::CreateStore(value, addr); - store->setAlignment(llvm::MaybeAlign(align.getValue())); + store->setAlignment(llvm::MaybeAlign(align.getValue()).valueOrOne()); return store; } llvm::StoreInst *CreateStore(llvm::Value *value, Address addr) { diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index e1cd39d903dde..e93c525ca0008 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -672,7 +672,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { return M; } - using ASTSourceDescriptor = clang::ExternalASTSource::ASTSourceDescriptor; + using ASTSourceDescriptor = clang::ASTSourceDescriptor; /// Create a DIModule from a clang module or PCH. /// The clang::Module pointer is passed separately because the recursive case /// needs to fudge the AST descriptor. @@ -1020,7 +1020,8 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { SmallVector TemplateParams; for (auto Param : BGT->getGenericArgs()) { TemplateParams.push_back(DBuilder.createTemplateTypeParameter( - TheCU, "", getOrCreateType(DebugTypeInfo::getForwardDecl(Param)))); + TheCU, "", getOrCreateType(DebugTypeInfo::getForwardDecl(Param)), + false)); } return DBuilder.getOrCreateArray(TemplateParams); } @@ -1571,6 +1572,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { case TypeKind::Unresolved: case TypeKind::LValue: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::Module: case TypeKind::SILBlockStorage: case TypeKind::SILBox: diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 772301bd07e97..79d6a1cce609c 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -192,6 +192,11 @@ enum RequireMetadata_t : bool { RequireMetadata = true }; +enum class TypeMetadataCanonicality : bool { + Noncanonical, + Canonical, +}; + /// The principal singleton which manages all of IR generation. /// /// The IRGenerator delegates the emission of different top-level entities @@ -259,17 +264,22 @@ class IRGenerator { /// queued up. llvm::SmallPtrSet LazilyEmittedFieldMetadata; - /// Maps every generic type that is specialized within the module to its - /// specializations. - llvm::DenseMap> - CanonicalSpecializationsForGenericTypes; + /// Maps every generic type whose metadata is specialized within the module + /// to its specializations. + llvm::DenseMap< + NominalTypeDecl *, + llvm::SmallVector, 4>> + MetadataPrespecializationsForGenericTypes; llvm::DenseMap> CanonicalSpecializedAccessorsForGenericTypes; /// The queue of specialized generic types whose prespecialized metadata to /// emit. - llvm::SmallVector LazySpecializedTypeMetadataRecords; + llvm::SmallVector, 4> + LazySpecializedTypeMetadataRecords; + + llvm::SmallPtrSet LazilyReemittedTypeContextDescriptors; /// The queue of metadata accessors to emit. /// @@ -423,9 +433,18 @@ class IRGenerator { void ensureRelativeSymbolCollocation(SILDefaultWitnessTable &wt); - llvm::SmallVector - canonicalSpecializationsForType(NominalTypeDecl *type) { - return CanonicalSpecializationsForGenericTypes.lookup(type); + llvm::SmallVector, 4> + metadataPrespecializationsForType(NominalTypeDecl *type) { + return MetadataPrespecializationsForGenericTypes.lookup(type); + } + + void noteLazyReemissionOfNominalTypeDescriptor(NominalTypeDecl *decl) { + LazilyReemittedTypeContextDescriptors.insert(decl); + } + + bool isLazilyReemittingNominalTypeDescriptor(NominalTypeDecl *decl) { + return LazilyReemittedTypeContextDescriptors.find(decl) != + std::end(LazilyReemittedTypeContextDescriptors); } void noteUseOfMetadataAccessor(NominalTypeDecl *decl) { @@ -438,7 +457,8 @@ class IRGenerator { noteUseOfTypeGlobals(type, true, RequireMetadata); } - void noteUseOfSpecializedGenericTypeMetadata(CanType type); + void noteUseOfSpecializedGenericTypeMetadata( + IRGenModule &IGM, CanType theType, TypeMetadataCanonicality canonicality); void noteUseOfCanonicalSpecializedMetadataAccessor(CanType forType); void noteUseOfTypeMetadata(CanType type) { @@ -547,11 +567,6 @@ enum class MangledTypeRefRole { DefaultAssociatedTypeWitness, }; -enum class TypeMetadataCanonicality : bool { - Noncanonical, - Canonical, -}; - /// IRGenModule - Primary class for emitting IR for global declarations. /// class IRGenModule { @@ -1005,10 +1020,12 @@ class IRGenModule { bool setIsNoInline = false); llvm::Constant *getOrCreateRetainFunction(const TypeInfo &objectTI, SILType t, - llvm::Type *llvmType); + llvm::Type *llvmType, + irgen::Atomicity atomicity); llvm::Constant *getOrCreateReleaseFunction(const TypeInfo &objectTI, SILType t, - llvm::Type *llvmType); + llvm::Type *llvmType, + irgen::Atomicity atomicity); llvm::Constant *getOrCreateOutlinedInitializeWithTakeFunction( SILType objectType, const TypeInfo &objectTI, diff --git a/lib/IRGen/IRGenRequests.cpp b/lib/IRGen/IRGenRequests.cpp index 7cff6f7782837..85f9daae3058a 100644 --- a/lib/IRGen/IRGenRequests.cpp +++ b/lib/IRGen/IRGenRequests.cpp @@ -16,8 +16,8 @@ #include "swift/AST/Module.h" #include "swift/AST/SourceFile.h" #include "swift/SIL/SILModule.h" +#include "swift/AST/TBDGenRequests.h" #include "swift/Subsystems.h" -#include "swift/TBDGen/TBDGen.h" #include "llvm/IR/Module.h" #include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h" diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index cd6a850512f27..a08c2f95ffe11 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -1937,12 +1937,12 @@ void IRGenSILFunction:: visitLinearFunctionExtractInst(LinearFunctionExtractInst *i) { unsigned structFieldOffset = i->getExtractee().rawValue; unsigned fieldSize = 1; - auto fnRepr = i->getFunctionOperand()->getType().getFunctionRepresentation(); + auto fnRepr = i->getOperand()->getType().getFunctionRepresentation(); if (fnRepr == SILFunctionTypeRepresentation::Thick) { structFieldOffset *= 2; fieldSize = 2; } - auto diffFnExp = getLoweredExplosion(i->getFunctionOperand()); + auto diffFnExp = getLoweredExplosion(i->getOperand()); assert(diffFnExp.size() == fieldSize * 2); Explosion e; e.add(diffFnExp.getRange(structFieldOffset, structFieldOffset + fieldSize)); @@ -3629,15 +3629,15 @@ void IRGenSILFunction::visitRetainValueInst(swift::RetainValueInst *i) { } void IRGenSILFunction::visitRetainValueAddrInst(swift::RetainValueAddrInst *i) { - assert(i->getAtomicity() == RefCountingInst::Atomicity::Atomic && - "Non atomic retains are not supported"); SILValue operandValue = i->getOperand(); Address addr = getLoweredAddress(operandValue); SILType addrTy = operandValue->getType(); SILType objectT = addrTy.getObjectType(); llvm::Type *llvmType = addr.getAddress()->getType(); const TypeInfo &addrTI = getTypeInfo(addrTy); - auto *outlinedF = IGM.getOrCreateRetainFunction(addrTI, objectT, llvmType); + auto *outlinedF = IGM.getOrCreateRetainFunction( + addrTI, objectT, llvmType, i->isAtomic() ? irgen::Atomicity::Atomic + : irgen::Atomicity::NonAtomic); llvm::Value *args[] = {addr.getAddress()}; llvm::CallInst *call = Builder.CreateCall(outlinedF, args); call->setCallingConv(IGM.DefaultCC); @@ -3704,8 +3704,6 @@ void IRGenSILFunction::visitReleaseValueInst(swift::ReleaseValueInst *i) { void IRGenSILFunction::visitReleaseValueAddrInst( swift::ReleaseValueAddrInst *i) { - assert(i->getAtomicity() == RefCountingInst::Atomicity::Atomic && - "Non atomic retains are not supported"); SILValue operandValue = i->getOperand(); Address addr = getLoweredAddress(operandValue); SILType addrTy = operandValue->getType(); @@ -3713,7 +3711,8 @@ void IRGenSILFunction::visitReleaseValueAddrInst( llvm::Type *llvmType = addr.getAddress()->getType(); const TypeInfo &addrTI = getTypeInfo(addrTy); auto *outlinedF = IGM.getOrCreateReleaseFunction( - addrTI, objectT, llvmType); + addrTI, objectT, llvmType, i->isAtomic() ? irgen::Atomicity::Atomic + : irgen::Atomicity::NonAtomic); llvm::Value *args[] = {addr.getAddress()}; llvm::CallInst *call = Builder.CreateCall(outlinedF, args); call->setCallingConv(IGM.DefaultCC); diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index 8ec81868638ce..2a509cbfeeb89 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -2862,7 +2862,7 @@ bool LoadableByAddress::recreateConvInstr(SILInstruction &I, case SILInstructionKind::LinearFunctionExtractInst: { auto instr = cast(convInstr); newInstr = convBuilder.createLinearFunctionExtract( - instr->getLoc(), instr->getExtractee(), instr->getFunctionOperand()); + instr->getLoc(), instr->getExtractee(), instr->getOperand()); break; } default: diff --git a/lib/IRGen/LocalTypeDataKind.h b/lib/IRGen/LocalTypeDataKind.h index f45aa30cb1755..1f8215f60eab5 100644 --- a/lib/IRGen/LocalTypeDataKind.h +++ b/lib/IRGen/LocalTypeDataKind.h @@ -211,8 +211,8 @@ template <> struct DenseMapInfo { swift::irgen::LocalTypeDataKind::forFormalTypeMetadata() }; } static unsigned getHashValue(const LocalTypeDataKey &key) { - return combineHashValue(CanTypeInfo::getHashValue(key.Type), - key.Kind.getRawValue()); + return detail::combineHashValue(CanTypeInfo::getHashValue(key.Type), + key.Kind.getRawValue()); } static bool isEqual(const LocalTypeDataKey &a, const LocalTypeDataKey &b) { return a == b; diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 87a40476b5912..1efb72618069f 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -45,6 +45,7 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Constant.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormatVariadic.h" #include @@ -845,57 +846,7 @@ bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable( return !isGenericWithoutPrespecializedConformance() && metadataAccessIsTrivial() && witnessTablesAreReferenceable(); }); - auto anyArgumentIsFromCurrentModule = - llvm::any_of(environment->getGenericParams(), [&](auto parameter) { - auto signature = environment->getGenericSignature(); - const auto protocols = signature->getRequiredProtocols(parameter); - auto argument = ((Type *)parameter)->subst(substitutions); - auto canonicalType = argument->getCanonicalType(); - - auto argumentIsFromCurrentModule = [&]() { - if (auto *argumentNominal = argument->getAnyNominal()) { - return IGM.getSwiftModule() == argumentNominal->getModuleContext(); - } - return false; - }; - auto anyConformanceIsFromCurrentModule = [&]() { - return llvm::any_of(protocols, [&](ProtocolDecl *protocol) { - auto conformance = - signature->lookupConformance(canonicalType, protocol); - if (!conformance.isConcrete()) { - return false; - } - auto rootConformance = - conformance.getConcrete()->getRootConformance(); - return IGM.getSwiftModule() == - rootConformance->getDeclContext()->getParentModule(); - }); - }; - - return argumentIsFromCurrentModule() || - anyConformanceIsFromCurrentModule(); - }); return allArgumentsAreStaticallyAddressable && - // A type's metadata cannot be prespecialized non-canonically if it - // could be specialized canonically. The reasons for that: - // (1) Canonically prespecialized metadata is not registered with the - // runtime; at runtime, whether canonically prespecialized - // metadata exists can only be determined by calling the metadata - // accessor. - // (2) At compile time, there is no way to determine whether the - // defining module has prespecialized metadata at a particular - // argument list. - // (3) Subsequent versions of the defining module may add or remove - // prespecialized metadata. - // - // To account for that, we only allow non-canonical prespecialization - // when at least one of the arguments is from the current module - // where non-canonical prespecialization might occur. Consequently, - // some prespecialization opportunities may be missed (such as when - // an argument comes from a module which it is known the defining - // module does not depend on). - !((canonicality == NoncanonicalSpecializedMetadata) && - !anyArgumentIsFromCurrentModule) && IGM.getTypeInfoForUnlowered(type).isFixedSize( ResilienceExpansion::Maximal); } @@ -2035,168 +1986,6 @@ IRGenFunction::emitGenericTypeMetadataAccessFunctionCall( return MetadataResponse::handle(*this, request, call); } -static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( - IRGenFunction &IGF, llvm::Value *request, NominalTypeDecl *nominal, - GenericArguments &genericArgs, - std::function valueAtIndex) { - auto &IGM = IGF.IGM; - auto specializations = IGF.IGM.IRGen.canonicalSpecializationsForType(nominal); - if (specializations.size() > 0) { - SmallVector conditionBlocks; - for (size_t index = 0; index < specializations.size(); ++index) { - conditionBlocks.push_back(llvm::BasicBlock::Create(IGM.getLLVMContext())); - } - - IGF.Builder.CreateBr(conditionBlocks[0]); - - SmallVector>, - 4> - specializationBlocks; - auto switchDestination = llvm::BasicBlock::Create(IGM.getLLVMContext()); - unsigned long blockIndex = 0; - for (auto specialization : specializations) { - auto conditionBlock = conditionBlocks[blockIndex]; - IGF.Builder.emitBlock(conditionBlock); - auto successorBlock = blockIndex < conditionBlocks.size() - 1 - ? conditionBlocks[blockIndex + 1] - : switchDestination; - auto specializationBlock = llvm::BasicBlock::Create(IGM.getLLVMContext()); - auto substitutions = specialization->getContextSubstitutionMap( - IGM.getSwiftModule(), nominal); - - llvm::Value *condition = llvm::ConstantInt::get(IGM.Int1Ty, 1); - auto nominal = specialization->getAnyNominal(); - auto requirements = GenericTypeRequirements(IGF.IGM, nominal); - int requirementIndex = 0; - for (auto requirement : requirements.getRequirements()) { - auto parameter = requirement.TypeParameter; - auto argument = parameter.subst(substitutions); - if (requirement.Protocol) { - auto conformance = substitutions.lookupConformance( - requirement.TypeParameter->getCanonicalType(), - requirement.Protocol); - ProtocolConformance *concreteConformance = conformance.getConcrete(); - auto argumentNominal = argument->getAnyNominal(); - if (argumentNominal && argumentNominal->isGenericContext()) { - // TODO: Statically specialize the witness table pattern for t's - // conformance. - llvm_unreachable( - "Statically specializing metadata at generic types is " - "not supported."); - } else { - RootProtocolConformance *rootConformance = - concreteConformance->getRootConformance(); - llvm::Value *expectedDescriptor = - IGF.IGM.getAddrOfProtocolConformanceDescriptor(rootConformance); - auto *witnessTable = valueAtIndex(requirementIndex); - auto *witnessBuffer = - IGF.Builder.CreateBitCast(witnessTable, IGM.Int8PtrPtrTy); - auto *uncastProvidedDescriptor = - IGF.Builder.CreateLoad(witnessBuffer, Alignment()); - auto *providedDescriptor = IGF.Builder.CreateBitCast( - uncastProvidedDescriptor, - IGM.ProtocolConformanceDescriptorPtrTy); - - // Auth the stored descriptor. - auto storedScheme = - IGF.IGM.getOptions().PointerAuth.ProtocolConformanceDescriptors; - if (storedScheme) { - auto authInfo = PointerAuthInfo::emit( - IGF, storedScheme, witnessTable, - PointerAuthEntity::Special::ProtocolConformanceDescriptor); - providedDescriptor = - emitPointerAuthAuth(IGF, providedDescriptor, authInfo); - } - - // Sign the descriptors. - auto argScheme = - IGF.IGM.getOptions() - .PointerAuth.ProtocolConformanceDescriptorsAsArguments; - if (argScheme) { - auto authInfo = PointerAuthInfo::emit( - IGF, argScheme, nullptr, - PointerAuthEntity::Special:: - ProtocolConformanceDescriptorAsArgument); - expectedDescriptor = - emitPointerAuthSign(IGF, expectedDescriptor, authInfo); - providedDescriptor = - emitPointerAuthSign(IGF, providedDescriptor, authInfo); - } - - auto *call = IGF.Builder.CreateCall( - IGF.IGM.getCompareProtocolConformanceDescriptorsFn(), - {providedDescriptor, expectedDescriptor}); - call->setDoesNotThrow(); - call->setCallingConv(IGF.IGM.SwiftCC); - call->addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::ReadNone); - condition = IGF.Builder.CreateAnd(condition, call); - } - } else { - llvm::Constant *addr = - IGM.getAddrOfTypeMetadata(argument->getCanonicalType()); - auto addrInt = IGF.Builder.CreateBitCast(addr, IGM.Int8PtrTy); - condition = IGF.Builder.CreateAnd( - condition, IGF.Builder.CreateICmpEQ( - addrInt, valueAtIndex(requirementIndex))); - } - ++requirementIndex; - } - IGF.Builder.CreateCondBr(condition, specializationBlock, successorBlock); - - auto responseBuilder = [](llvm::Value *request, CanType specialization, - IRGenFunction &IGF, IRGenModule &IGM) { - auto nominal = specialization->getAnyNominal(); - llvm::Value *specializedMetadata; - if (isa(nominal)) { - llvm::Function *accessor = - IGF.IGM - .getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction( - specialization, NotForDefinition); - - specializedMetadata = - IGF.emitGenericTypeMetadataAccessFunctionCall( - accessor, {}, DynamicMetadataRequest(request)) - .getMetadata(); - } else { - specializedMetadata = IGM.getAddrOfTypeMetadata(specialization); - } - // Construct a MetadataResponse. It has three fields in the following - // order: - // - const Metadata *Metadata; - // - MetadataState (i32) StaticState; - llvm::Value *response = - llvm::UndefValue::get(IGM.TypeMetadataResponseTy); - response = IGF.Builder.CreateInsertValue( - response, specializedMetadata, 0, - "insert metadata address into response"); - auto state = MetadataResponse::getCompletedState(IGM); - response = IGF.Builder.CreateInsertValue( - response, state, 1, "insert metadata state into response"); - return response; - }; - specializationBlocks.push_back(std::make_tuple( - specializationBlock, specialization, responseBuilder)); - ++blockIndex; - } - - for (auto tuple : specializationBlocks) { - llvm::BasicBlock *block; - CanType type; - std::function - builder; - std::tie(block, type, builder) = tuple; - IGF.Builder.emitBlock(block); - IGF.Builder.CreateRet(builder(request, type, IGF, IGM)); - } - IGF.Builder.emitBlock(switchDestination); - } -} - MetadataResponse irgen::emitGenericTypeMetadataAccessFunction( IRGenFunction &IGF, Explosion ¶ms, NominalTypeDecl *nominal, GenericArguments &genericArgs) { @@ -2227,20 +2016,6 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction( llvm::Value *arguments = IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGM.Int8PtrTy); - llvm::Value *argumentsBuffer = - IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGM.Int8PtrPtrTy); - - emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( - IGF, request, nominal, genericArgs, [&](int index) { - llvm::Value *indexValue = llvm::ConstantInt::get(IGM.Int64Ty, index); - llvm::Value *elementPointer = - IGF.Builder.CreateGEP(argumentsBuffer, indexValue); - llvm::LoadInst *retval = IGF.Builder.CreateLoad( - elementPointer, Alignment(), - llvm::formatv("load argument at index {0} from buffer", index)); - return retval; - }); - // Make the call. auto call = IGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(), {request, arguments, descriptor}); @@ -2319,12 +2094,6 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction( ? IGF.Builder.CreateBitCast(params.claimNext(), IGM.Int8PtrTy) : llvm::UndefValue::get(IGM.Int8PtrTy); - std::array argValues = {arg0, arg1, arg2}; - - emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( - IGF, request, nominal, genericArgs, - [&](int index) { return argValues[index]; }); - auto call = IGF.Builder.CreateCall(thunkFn, {request, arg0, arg1, arg2, descriptor}); call->setDoesNotAccessMemory(); diff --git a/lib/IRGen/Outlining.cpp b/lib/IRGen/Outlining.cpp index 68f2d171732b2..81f669bff78d0 100644 --- a/lib/IRGen/Outlining.cpp +++ b/lib/IRGen/Outlining.cpp @@ -39,7 +39,6 @@ void OutliningMetadataCollector::collectTypeMetadataForLayout(SILType type) { } // Substitute opaque types if allowed. - auto origType = type; type = IGF.IGM.substOpaqueTypesWithUnderlyingTypes(type, CanGenericSignature()); @@ -49,9 +48,7 @@ void OutliningMetadataCollector::collectTypeMetadataForLayout(SILType type) { // We don't need the metadata for fixed size types or types that are not ABI // accessible. Outlining will call the value witness of the enclosing type of // non ABI accessible field/element types. - if ((!origType.getASTType()->hasOpaqueArchetype() && - isa(ti)) || - !ti.isABIAccessible()) { + if (isa(ti) || !ti.isABIAccessible()) { return; } @@ -399,7 +396,8 @@ llvm::Constant *IRGenModule::getOrCreateOutlinedDestroyFunction( llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti, SILType t, - llvm::Type *llvmType) { + llvm::Type *llvmType, + irgen::Atomicity atomicity) { auto *loadableTI = cast(&ti); IRGenMangler mangler; auto manglingBits = @@ -415,7 +413,7 @@ llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti, Explosion loaded; loadableTI->loadAsTake(IGF, addr, loaded); Explosion out; - loadableTI->copy(IGF, loaded, out, irgen::Atomicity::Atomic); + loadableTI->copy(IGF, loaded, out, atomicity); (void)out.claimAll(); IGF.Builder.CreateRet(addr.getAddress()); }, @@ -425,7 +423,8 @@ llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti, llvm::Constant * IRGenModule::getOrCreateReleaseFunction(const TypeInfo &ti, SILType t, - llvm::Type *llvmType) { + llvm::Type *llvmType, + irgen::Atomicity atomicity) { auto *loadableTI = cast(&ti); IRGenMangler mangler; auto manglingBits = @@ -440,7 +439,7 @@ IRGenModule::getOrCreateReleaseFunction(const TypeInfo &ti, Address addr(&*it++, loadableTI->getFixedAlignment()); Explosion loaded; loadableTI->loadAsTake(IGF, addr, loaded); - loadableTI->consume(IGF, loaded, irgen::Atomicity::Atomic); + loadableTI->consume(IGF, loaded, atomicity); IGF.Builder.CreateRet(addr.getAddress()); }, true /*setIsNoInline*/); diff --git a/lib/IRGen/ScalarTypeInfo.h b/lib/IRGen/ScalarTypeInfo.h index e3b0f3d03405b..4f9b843575580 100644 --- a/lib/IRGen/ScalarTypeInfo.h +++ b/lib/IRGen/ScalarTypeInfo.h @@ -117,10 +117,33 @@ class SingleScalarTypeInfo : public ScalarTypeInfo { schema.add(ExplosionSchema::Element::forScalar(ty)); } + void storeAsBytes(IRGenFunction &IGF, Explosion &src, Address addr) const { + auto &IGM = IGF.IGM; + + // Store in multiples of bytes to avoid undefined bits. + auto storageTy = addr.getAddress()->getType()->getPointerElementType(); + if (storageTy->isIntegerTy() && (storageTy->getIntegerBitWidth() % 8)) { + auto &Builder = IGF.Builder; + auto nextByteSize = (storageTy->getIntegerBitWidth() + 7) & ~7UL; + auto nextByteSizedIntTy = + llvm::IntegerType::get(IGM.getLLVMContext(), nextByteSize); + auto newAddr = + Address(Builder.CreatePointerCast(addr.getAddress(), + nextByteSizedIntTy->getPointerTo()), + addr.getAlignment()); + auto newValue = Builder.CreateZExt(src.claimNext(), nextByteSizedIntTy); + Builder.CreateStore(newValue, newAddr); + return; + } + + IGF.Builder.CreateStore(src.claimNext(), addr); + } + void initialize(IRGenFunction &IGF, Explosion &src, Address addr, bool isOutlined) const override { addr = asDerived().projectScalar(IGF, addr); - IGF.Builder.CreateStore(src.claimNext(), addr); + + storeAsBytes(IGF, src, addr); } void loadAsCopy(IRGenFunction &IGF, Address addr, @@ -149,8 +172,7 @@ class SingleScalarTypeInfo : public ScalarTypeInfo { } // Store. - llvm::Value *newValue = src.claimNext(); - IGF.Builder.CreateStore(newValue, dest); + storeAsBytes(IGF, src, dest); // Release the old value if we need to. if (!Derived::IsScalarPOD) { diff --git a/lib/IRGen/TypeLayout.h b/lib/IRGen/TypeLayout.h index a6fa9d7858527..2f6a163011a55 100644 --- a/lib/IRGen/TypeLayout.h +++ b/lib/IRGen/TypeLayout.h @@ -16,6 +16,7 @@ #include "TypeInfo.h" #include "swift/SIL/SILType.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Debug.h" namespace swift { namespace irgen { diff --git a/lib/Immediate/Immediate.cpp b/lib/Immediate/Immediate.cpp index b49156177b8f1..fe6053148bec7 100644 --- a/lib/Immediate/Immediate.cpp +++ b/lib/Immediate/Immediate.cpp @@ -339,7 +339,7 @@ int swift::RunImmediately(CompilerInstance &CI, using MainFnTy = int(*)(int, char*[]); LLVM_DEBUG(llvm::dbgs() << "Running static constructors\n"); - if (auto Err = JIT->runConstructors()) { + if (auto Err = JIT->initialize(JIT->getMainJITDylib())) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), ""); return -1; } @@ -356,7 +356,7 @@ int swift::RunImmediately(CompilerInstance &CI, int Result = llvm::orc::runAsMain(JITMain, CmdLine); LLVM_DEBUG(llvm::dbgs() << "Running static destructors\n"); - if (auto Err = JIT->runDestructors()) { + if (auto Err = JIT->deinitialize(JIT->getMainJITDylib())) { logAllUnhandledErrors(std::move(Err), llvm::errs(), ""); return -1; } diff --git a/lib/Localization/CMakeLists.txt b/lib/Localization/CMakeLists.txt new file mode 100644 index 0000000000000..5de7c352be6c5 --- /dev/null +++ b/lib/Localization/CMakeLists.txt @@ -0,0 +1,6 @@ + +add_swift_host_library(swiftLocalization STATIC + LocalizationFormat.cpp + + LLVM_LINK_COMPONENTS + support) diff --git a/lib/AST/LocalizationFormat.cpp b/lib/Localization/LocalizationFormat.cpp similarity index 91% rename from lib/AST/LocalizationFormat.cpp rename to lib/Localization/LocalizationFormat.cpp index 5bc4f46cf5e64..94f73b159acaa 100644 --- a/lib/AST/LocalizationFormat.cpp +++ b/lib/Localization/LocalizationFormat.cpp @@ -14,7 +14,8 @@ // //===----------------------------------------------------------------------===// -#include "swift/AST/LocalizationFormat.h" +#include "swift/Basic/Range.h" +#include "swift/Localization/LocalizationFormat.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" @@ -190,5 +191,28 @@ operator>>(LocalizationInput &yin, T &diagnostics) { return yin; } +void DefToYAMLConverter::convert(llvm::raw_ostream &out) { + for (auto i : swift::indices(IDs)) { + out << "- id: " << IDs[i] << "\n"; + + const std::string &msg = Messages[i]; + + out << " msg: \""; + // Add an escape character before a double quote `"` or a backslash `\`. + for (unsigned j = 0; j < msg.length(); ++j) { + if (msg[j] == '"') { + out << '\\'; + out << '"'; + } else if (msg[j] == '\\') { + out << '\\'; + out << '\\'; + } else { + out << msg[j]; + } + } + out << "\"\r\n"; + } +} + } // namespace diag } // namespace swift diff --git a/lib/Migrator/APIDiffMigratorPass.cpp b/lib/Migrator/APIDiffMigratorPass.cpp index f99b28e07dc37..55d0948de6ad4 100644 --- a/lib/Migrator/APIDiffMigratorPass.cpp +++ b/lib/Migrator/APIDiffMigratorPass.cpp @@ -58,9 +58,10 @@ class ChildIndexFinder : public TypeReprVisitor { FoundResult findChild(AbstractFunctionDecl *Parent) { auto NextIndex = consumeNext(); if (!NextIndex) { - if (auto Func = dyn_cast(Parent)) - return findChild(Func->getBodyResultTypeLoc()); - if (auto Init = dyn_cast(Parent)) { + if (auto Func = dyn_cast(Parent)) { + if (auto *const TyRepr = Func->getResultTypeRepr()) + return visit(TyRepr); + } else if (auto Init = dyn_cast(Parent)) { SourceLoc End = Init->getFailabilityLoc(); bool Optional = End.isValid(); if (!Optional) @@ -73,7 +74,7 @@ class ChildIndexFinder : public TypeReprVisitor { for (auto *Param: *Parent->getParameters()) { if (!--NextIndex) { - return findChild(Param->getTypeRepr()); + return visit(Param->getTypeRepr()); } } llvm_unreachable("child index out of bounds"); @@ -100,12 +101,6 @@ class ChildIndexFinder : public TypeReprVisitor { return false; } - FoundResult findChild(TypeLoc Loc) { - if (!Loc.hasLocation()) - return {SourceRange(), false, false, false}; - return visit(Loc.getTypeRepr()); - } - public: template @@ -1257,7 +1252,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { switch (DiffItem->DiffKind) { case NodeAnnotation::GetterToProperty: { auto FuncLoc = FD->getFuncLoc(); - auto ReturnTyLoc = FD->getBodyResultTypeLoc().getSourceRange().Start; + auto ReturnTyLoc = FD->getResultTypeSourceRange().Start; auto NameLoc = FD->getNameLoc(); if (FuncLoc.isInvalid() || ReturnTyLoc.isInvalid() || NameLoc.isInvalid()) break; diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp index 976b3b2aeee92..fef46453c959e 100644 --- a/lib/Parse/Lexer.cpp +++ b/lib/Parse/Lexer.cpp @@ -2706,12 +2706,12 @@ static SourceLoc getLocForStartOfTokenInBuf(SourceManager &SM, // Find the start of the given line. static const char *findStartOfLine(const char *bufStart, const char *current) { while (current != bufStart) { - if (current[0] == '\n' || current[0] == '\r') { + --current; + + if (current[0] == '\n') { ++current; break; } - - --current; } return current; @@ -2779,19 +2779,16 @@ SourceLoc Lexer::getLocForEndOfLine(SourceManager &SM, SourceLoc Loc) { if (BufferID < 0) return SourceLoc(); - // Use fake language options; language options only affect validity - // and the exact token produced. - LangOptions FakeLangOpts; + CharSourceRange entireRange = SM.getRangeForBuffer(BufferID); + StringRef Buffer = SM.extractText(entireRange); - // Here we return comments as tokens because either the caller skipped - // comments and normally we won't be at the beginning of a comment token - // (making this option irrelevant), or the caller lexed comments and - // we need to lex just the comment token. - Lexer L(FakeLangOpts, SM, BufferID, nullptr, LexerMode::Swift, - HashbangMode::Allowed, CommentRetentionMode::ReturnAsTokens); - L.restoreState(State(Loc)); - L.skipToEndOfLine(/*EatNewline=*/true); - return getSourceLoc(L.CurPtr); + // Windows line endings are \r\n. Since we want the start of the next + // line, just look for \n so the \r is skipped through. + size_t Offset = SM.getLocOffsetInBuffer(Loc, BufferID); + Offset = Buffer.find('\n', Offset); + if (Offset == StringRef::npos) + return SourceLoc(); + return getSourceLoc(Buffer.data() + Offset + 1); } StringRef Lexer::getIndentationForLine(SourceManager &SM, SourceLoc Loc, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 28f5e4c2989a9..94f0d5825ff33 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -60,15 +60,9 @@ namespace { /// file scope level so it will be set up correctly for this purpose. /// /// Creating an instance of this object will cause it to figure out - /// whether we are in the debugger function, whether it needs to swap + /// whether we are in the debugger function, and whether it needs to swap /// the Decl that is currently being parsed. - /// If you have created the object, instead of returning the result - /// with makeParserResult, use the object's fixupParserResult. If - /// no swap has occurred, these methods will work the same. - /// If the decl has been moved, then Parser::markWasHandled will be - /// called on the Decl, and you should call declWasHandledAlready - /// before you consume the Decl to see if you actually need to - /// consume it. + /// /// If you are making one of these objects to address issue 1, call /// the constructor that only takes a DeclKind, and it will be moved /// unconditionally. Otherwise pass in the Name and DeclKind and the @@ -76,32 +70,24 @@ namespace { class DebuggerContextChange { protected: Parser &P; - Identifier Name; - SourceFile *SF; Optional CC; + SourceFile *SF; public: - DebuggerContextChange (Parser &P) - : P(P), SF(nullptr) { + DebuggerContextChange(Parser &P) : P(P), SF(nullptr) { if (!inDebuggerContext()) return; - else - switchContext(); + + switchContext(); } - DebuggerContextChange (Parser &P, Identifier &Name, DeclKind Kind) - : P(P), Name(Name), SF(nullptr) { + DebuggerContextChange(Parser &P, Identifier Name, DeclKind Kind) + : P(P), SF(nullptr) { if (!inDebuggerContext()) return; - bool globalize = false; - - DebuggerClient *debug_client = getDebuggerClient(); - if (!debug_client) - return; - - globalize = debug_client->shouldGlobalize(Name, Kind); - - if (globalize) - switchContext(); + + if (auto *client = getDebuggerClient()) + if (client->shouldGlobalize(Name, Kind)) + switchContext(); } bool movedToTopLevel() { @@ -118,35 +104,27 @@ namespace { template ParserResult fixupParserResult(T *D) { - if (CC.hasValue()) { - swapDecl(D); - } + if (movedToTopLevel()) + hoistDecl(D); return ParserResult(D); } template ParserResult fixupParserResult(ParserStatus Status, T *D) { - if (CC.hasValue() && !Status.isError()) { - // If there is an error, don't do our splicing trick, - // just return the Decl and the status for reporting. - swapDecl(D); - } + if (movedToTopLevel()) + hoistDecl(D); return makeParserResult(Status, D); } // The destructor doesn't need to do anything, the CC's destructor will // pop the context if we set it. ~DebuggerContextChange () {} - protected: - - DebuggerClient *getDebuggerClient() - { - ModuleDecl *PM = P.CurDeclContext->getParentModule(); - if (!PM) - return nullptr; - else - return PM->getDebugClient(); + + private: + DebuggerClient *getDebuggerClient() { + ModuleDecl *M = P.CurDeclContext->getParentModule(); + return M->getDebugClient(); } bool inDebuggerContext() { @@ -154,29 +132,26 @@ namespace { return false; if (!P.CurDeclContext) return false; - auto *func_decl = dyn_cast(P.CurDeclContext); - if (!func_decl) + auto *func = dyn_cast(P.CurDeclContext); + if (!func) return false; - - if (!func_decl->getAttrs().hasAttribute()) + + if (!func->getAttrs().hasAttribute()) return false; - + return true; } - void switchContext () { + void switchContext() { SF = P.CurDeclContext->getParentSourceFile(); - CC.emplace (P, SF); + CC.emplace(P, SF); } - - void swapDecl (Decl *D) - { - assert (SF); - DebuggerClient *debug_client = getDebuggerClient(); - assert (debug_client); - debug_client->didGlobalize(D); - P.ContextSwitchedTopLevelDecls.push_back(D); - P.markWasHandled(D); + + template + void hoistDecl(T *D) { + D->setHoisted(); + SF->addHoistedDecl(D); + getDebuggerClient()->didGlobalize(D); } }; } // end anonymous namespace @@ -225,10 +200,6 @@ void Parser::parseTopLevel(SmallVectorImpl &decls) { } } - // First append any decls that LLDB requires be inserted at the top-level. - decls.append(ContextSwitchedTopLevelDecls.begin(), - ContextSwitchedTopLevelDecls.end()); - // Then append the top-level decls we parsed. for (auto item : items) { auto *decl = item.get(); @@ -5234,9 +5205,6 @@ static AccessorDecl *createAccessorFunc(SourceLoc DeclLoc, EndLoc); } - // The typechecker will always fill this in. - TypeLoc ReturnType; - // Start the function. auto *D = AccessorDecl::create(P->Context, /*FIXME FuncLoc=*/DeclLoc, @@ -5247,7 +5215,7 @@ static AccessorDecl *createAccessorFunc(SourceLoc DeclLoc, (GenericParams ? GenericParams->clone(P->CurDeclContext) : nullptr), - ValueArg, ReturnType, + ValueArg, Type(), P->CurDeclContext); return D; @@ -6248,15 +6216,12 @@ void Parser::consumeAbstractFunctionBody(AbstractFunctionDecl *AFD, AFD->setBodyDelayed(BodyRange); - if (isCodeCompletionFirstPass()) { - if (SourceMgr.rangeContainsCodeCompletionLoc(BodyRange)) { - State->setCodeCompletionDelayedDeclState( - SourceMgr, L->getBufferID(), - CodeCompletionDelayedDeclKind::FunctionBody, - PD_Default, AFD, BodyRange, BeginParserPosition.PreviousLoc); - } else { - AFD->setBodySkipped(BodyRange); - } + if (isCodeCompletionFirstPass() && + SourceMgr.rangeContainsCodeCompletionLoc(BodyRange)) { + State->setCodeCompletionDelayedDeclState( + SourceMgr, L->getBufferID(), + CodeCompletionDelayedDeclKind::FunctionBody, + PD_Default, AFD, BodyRange, BeginParserPosition.PreviousLoc); } } @@ -6448,10 +6413,9 @@ ParserResult Parser::parseDeclFunc(SourceLoc StaticLoc, return DCC.fixupParserResult(FD); } -/// Parse a function body for \p AFD and returns it without setting the body -/// to \p AFD . -ParserResult -Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) { +/// Parse a function body for \p AFD, setting the body to \p AFD before +/// returning it. +BraceStmt *Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) { assert(Tok.is(tok::l_brace)); // Enter the arguments for the function into a new function-body scope. We @@ -6479,13 +6443,70 @@ Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) { CodeCompletion->completeAccessorBeginning(CCE); RBraceLoc = Tok.getLoc(); consumeToken(tok::code_complete); - return makeParserCodeCompletionResult( - BraceStmt::create(Context, LBraceLoc, ASTNode(CCE), RBraceLoc, - /*implicit*/ true)); + auto *BS = BraceStmt::create(Context, LBraceLoc, ASTNode(CCE), RBraceLoc, + /*implicit*/ true); + AFD->setBodyParsed(BS); + return BS; } } - return parseBraceItemList(diag::invalid_diagnostic); + ParserResult Body = parseBraceItemList(diag::invalid_diagnostic); + if (Body.isNull()) + return nullptr; + + BraceStmt *BS = Body.get(); + AFD->setBodyParsed(BS); + + // If the body consists of a single expression, turn it into a return + // statement. + // + // But don't do this transformation during code completion, as the source + // may be incomplete and the type mismatch in return statement will just + // confuse the type checker. + if (BS->getNumElements() != 1 || Body.hasCodeCompletion()) + return BS; + + auto Element = BS->getFirstElement(); + if (auto *stmt = Element.dyn_cast()) { + if (isa(AFD)) { + if (auto *returnStmt = dyn_cast(stmt)) { + if (!returnStmt->hasResult()) { + auto returnExpr = TupleExpr::createEmpty(Context, + SourceLoc(), + SourceLoc(), + /*implicit*/true); + returnStmt->setResult(returnExpr); + AFD->setHasSingleExpressionBody(); + AFD->setSingleExpressionBody(returnExpr); + } + } + } + } else if (auto *E = Element.dyn_cast()) { + if (auto SE = dyn_cast(E->getSemanticsProvidingExpr())) { + if (SE->getNumElements() > 1 && isa(SE->getElement(1))) { + // This is an assignment. We don't want to implicitly return + // it. + return BS; + } + } + if (isa(AFD)) { + auto RS = new (Context) ReturnStmt(SourceLoc(), E); + BS->setFirstElement(RS); + AFD->setHasSingleExpressionBody(); + AFD->setSingleExpressionBody(E); + } else if (auto *F = dyn_cast(AFD)) { + if (F->isFailable() && isa(E)) { + // If it's a nil literal, just insert return. This is the only + // legal thing to return. + auto RS = new (Context) ReturnStmt(E->getStartLoc(), E); + BS->setFirstElement(RS); + AFD->setHasSingleExpressionBody(); + AFD->setSingleExpressionBody(E); + } + } + } + + return BS; } /// Parse function body into \p AFD or skip it for delayed parsing. @@ -6510,60 +6531,7 @@ void Parser::parseAbstractFunctionBody(AbstractFunctionDecl *AFD) { } Scope S(this, ScopeKind::FunctionBody); - - ParserResult Body = parseAbstractFunctionBodyImpl(AFD); - if (!Body.isNull()) { - BraceStmt * BS = Body.get(); - AFD->setBodyParsed(BS); - - // If the body consists of a single expression, turn it into a return - // statement. - // - // But don't do this transformation during code completion, as the source - // may be incomplete and the type mismatch in return statement will just - // confuse the type checker. - if (!Body.hasCodeCompletion() && BS->getNumElements() == 1) { - auto Element = BS->getFirstElement(); - if (auto *stmt = Element.dyn_cast()) { - if (isa(AFD)) { - if (auto *returnStmt = dyn_cast(stmt)) { - if (!returnStmt->hasResult()) { - auto returnExpr = TupleExpr::createEmpty(Context, - SourceLoc(), - SourceLoc(), - /*implicit*/true); - returnStmt->setResult(returnExpr); - AFD->setHasSingleExpressionBody(); - AFD->setSingleExpressionBody(returnExpr); - } - } - } - } else if (auto *E = Element.dyn_cast()) { - if (auto SE = dyn_cast(E->getSemanticsProvidingExpr())) { - if (SE->getNumElements() > 1 && isa(SE->getElement(1))) { - // This is an assignment. We don't want to implicitly return - // it. - return; - } - } - if (isa(AFD)) { - auto RS = new (Context) ReturnStmt(SourceLoc(), E); - BS->setFirstElement(RS); - AFD->setHasSingleExpressionBody(); - AFD->setSingleExpressionBody(E); - } else if (auto *F = dyn_cast(AFD)) { - if (F->isFailable() && isa(E)) { - // If it's a nil literal, just insert return. This is the only - // legal thing to return. - auto RS = new (Context) ReturnStmt(E->getStartLoc(), E); - BS->setFirstElement(RS); - AFD->setHasSingleExpressionBody(); - AFD->setSingleExpressionBody(E); - } - } - } - } - } + (void)parseAbstractFunctionBodyImpl(AFD); } BraceStmt *Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) { @@ -6595,7 +6563,7 @@ BraceStmt *Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) { Scope TopLevelScope(this, ScopeKind::TopLevel); Scope S(this, ScopeKind::FunctionBody); - return parseAbstractFunctionBodyImpl(AFD).getPtrOrNull(); + return parseAbstractFunctionBodyImpl(AFD); } /// Parse a 'enum' declaration, returning true (and doing no token @@ -7269,12 +7237,9 @@ Parser::parseDeclSubscript(SourceLoc StaticLoc, // Build an AST for the subscript declaration. DeclName name = DeclName(Context, DeclBaseName::createSubscript(), argumentNames); - auto *Subscript = new (Context) SubscriptDecl(name, - StaticLoc, StaticSpelling, - SubscriptLoc, Indices.get(), - ArrowLoc, ElementTy.get(), - CurDeclContext, - GenericParams); + auto *const Subscript = SubscriptDecl::create( + Context, name, StaticLoc, StaticSpelling, SubscriptLoc, Indices.get(), + ArrowLoc, ElementTy.get(), CurDeclContext, GenericParams); Subscript->getAttrs() = Attributes; // Let the source file track the opaque return type mapping, if any. @@ -7732,8 +7697,9 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags, SourceLoc precedenceGroupLoc = consumeToken(tok::kw_precedencegroup); DebuggerContextChange DCC (*this); - if (!CodeCompletion && !DCC.movedToTopLevel() && !(flags & PD_AllowTopLevel)) - { + if (!CodeCompletion && + !DCC.movedToTopLevel() && + !(flags & PD_AllowTopLevel)) { diagnose(precedenceGroupLoc, diag::decl_inner_scope); return nullptr; } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index d7f77869d6723..accdc19250e49 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -330,7 +330,7 @@ ParserResult Parser::parseExprSequence(Diag<> Message, case tok::identifier: { // 'async' followed by 'throws' or '->' implies that we have an arrow // expression. - if (!(Context.LangOpts.EnableExperimentalConcurrency && + if (!(shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async") && peekToken().isAny(tok::arrow, tok::kw_throws))) goto done; @@ -379,7 +379,7 @@ ParserResult Parser::parseExprSequence(Diag<> Message, /// parseExprSequenceElement /// /// expr-sequence-element(Mode): -/// '__await' expr-sequence-element(Mode) +/// 'await' expr-sequence-element(Mode) /// 'try' expr-sequence-element(Mode) /// 'try' '?' expr-sequence-element(Mode) /// 'try' '!' expr-sequence-element(Mode) @@ -392,10 +392,10 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, SyntaxParsingContext ElementContext(SyntaxContext, SyntaxContextKind::Expr); - if (Context.LangOpts.EnableExperimentalConcurrency && - Tok.is(tok::kw___await)) { - SourceLoc awaitLoc = consumeToken(tok::kw___await); - ParserResult sub = parseExprUnary(message, isExprBasic); + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("await")) { + SourceLoc awaitLoc = consumeToken(); + ParserResult sub = + parseExprSequenceElement(diag::expected_expr_after_await, isExprBasic); if (!sub.hasCodeCompletion() && !sub.isNull()) { ElementContext.setCreateSyntax(SyntaxKind::AwaitExpr); sub = makeParserResult(new (Context) AwaitExpr(awaitLoc, sub.get())); @@ -429,7 +429,9 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, } } - ParserResult sub = parseExprUnary(message, isExprBasic); + ParserResult sub = hadTry + ? parseExprSequenceElement(message, isExprBasic) + : parseExprUnary(message, isExprBasic); if (hadTry && !sub.hasCodeCompletion() && !sub.isNull()) { ElementContext.setCreateSyntax(SyntaxKind::TryExpr); @@ -803,8 +805,6 @@ ParserResult Parser::parseExprSelector() { parseExpr(selectorKind == ObjCSelectorExpr::Method ? diag::expr_selector_expected_method_expr : diag::expr_selector_expected_property_expr); - if (subExpr.hasCodeCompletion()) - return makeParserCodeCompletionResult(); // Parse the closing ')'. SourceLoc rParenLoc; @@ -820,7 +820,7 @@ ParserResult Parser::parseExprSelector() { } // If the subexpression was in error, just propagate the error. - if (subExpr.isParseError()) + if (subExpr.isParseError() && !subExpr.hasCodeCompletion()) return makeParserResult( new (Context) ErrorExpr(SourceRange(keywordLoc, rParenLoc))); @@ -1613,60 +1613,8 @@ ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { return makeParserErrorResult(new (Context) ErrorExpr(DotLoc)); SyntaxContext->createNodeInPlace(SyntaxKind::MemberAccessExpr); - // Check for a () suffix, which indicates a call when constructing - // this member. Note that this cannot be the start of a new line. - if (Tok.isFollowingLParen()) { - SourceLoc lParenLoc, rParenLoc; - SmallVector args; - SmallVector argLabels; - SmallVector argLabelLocs; - SmallVector trailingClosures; - - ParserStatus status = parseExprList(tok::l_paren, tok::r_paren, - /*isPostfix=*/true, isExprBasic, - lParenLoc, args, argLabels, - argLabelLocs, - rParenLoc, - trailingClosures, - SyntaxKind::TupleExprElementList); - SyntaxContext->createNodeInPlace(SyntaxKind::FunctionCallExpr); - return makeParserResult( - status, - UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name, - lParenLoc, args, argLabels, - argLabelLocs, rParenLoc, - trailingClosures, - /*implicit=*/false)); - } - - // Check for a trailing closure, if allowed. - if (Tok.is(tok::l_brace) && isValidTrailingClosure(isExprBasic, *this)) { - if (SyntaxContext->isEnabled()) { - // Add dummy blank argument list to the call expression syntax. - SyntaxContext->addSyntax( - ParsedSyntaxRecorder::makeBlankTupleExprElementList( - leadingTriviaLoc(), *SyntaxContext)); - } - - SmallVector trailingClosures; - auto result = parseTrailingClosures(isExprBasic, NameLoc.getSourceRange(), - trailingClosures); - if (trailingClosures.empty()) - return nullptr; - - SyntaxContext->createNodeInPlace(SyntaxKind::FunctionCallExpr); - // Handle .foo by just making an AST node. - return makeParserResult( - result, UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name, - SourceLoc(), {}, {}, {}, - SourceLoc(), trailingClosures, - /*implicit=*/false)); - } - - // Handle .foo by just making an AST node. - return makeParserResult( - UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name, - /*implicit=*/false)); + return makeParserResult(new (Context) UnresolvedMemberExpr( + DotLoc, NameLoc, Name, /*implicit=*/false)); } case tok::kw_super: // 'super' @@ -2432,7 +2380,8 @@ bool Parser:: parseClosureSignatureIfPresent(SourceRange &bracketRange, SmallVectorImpl &captureList, VarDecl *&capturedSelfDecl, - ParameterList *¶ms, SourceLoc &throwsLoc, + ParameterList *¶ms, + SourceLoc &asyncLoc, SourceLoc &throwsLoc, SourceLoc &arrowLoc, TypeExpr *&explicitResultType, SourceLoc &inLoc){ // Clear out result parameters. @@ -2444,6 +2393,24 @@ parseClosureSignatureIfPresent(SourceRange &bracketRange, explicitResultType = nullptr; inLoc = SourceLoc(); + // Consume 'async', 'throws', and 'rethrows', but in any order. + auto consumeAsyncThrows = [&] { + bool hadAsync = false; + if (shouldParseExperimentalConcurrency() && + Tok.isContextualKeyword("async")) { + consumeToken(); + hadAsync = true; + } + + if (!consumeIf(tok::kw_throws) && !consumeIf(tok::kw_rethrows)) + return; + + if (shouldParseExperimentalConcurrency() && !hadAsync && + Tok.isContextualKeyword("async")) { + consumeToken(); + } + }; + // If we have a leading token that may be part of the closure signature, do a // speculative parse to validate it and look for 'in'. if (Tok.isAny(tok::l_paren, tok::l_square, tok::identifier, tok::kw__)) { @@ -2465,7 +2432,8 @@ parseClosureSignatureIfPresent(SourceRange &bracketRange, // Consume the ')', if it's there. if (consumeIf(tok::r_paren)) { - consumeIf(tok::kw_throws) || consumeIf(tok::kw_rethrows); + consumeAsyncThrows(); + // Parse the func-signature-result, if present. if (consumeIf(tok::arrow)) { if (!canParseType()) @@ -2485,8 +2453,8 @@ parseClosureSignatureIfPresent(SourceRange &bracketRange, return false; } - - consumeIf(tok::kw_throws) || consumeIf(tok::kw_rethrows); + + consumeAsyncThrows(); // Parse the func-signature-result, if present. if (consumeIf(tok::arrow)) { @@ -2682,11 +2650,10 @@ parseClosureSignatureIfPresent(SourceRange &bracketRange, params = ParameterList::create(Context, elements); } - - if (Tok.is(tok::kw_throws)) { - throwsLoc = consumeToken(); - } else if (Tok.is(tok::kw_rethrows)) { - throwsLoc = consumeToken(); + + bool rethrows = false; + parseAsyncThrows(SourceLoc(), asyncLoc, throwsLoc, &rethrows); + if (rethrows) { diagnose(throwsLoc, diag::rethrowing_function_type) .fixItReplace(throwsLoc, "throws"); } @@ -2803,13 +2770,14 @@ ParserResult Parser::parseExprClosure() { SmallVector captureList; VarDecl *capturedSelfDecl; ParameterList *params = nullptr; + SourceLoc asyncLoc; SourceLoc throwsLoc; SourceLoc arrowLoc; TypeExpr *explicitResultType; SourceLoc inLoc; - parseClosureSignatureIfPresent(bracketRange, captureList, - capturedSelfDecl, params, throwsLoc, - arrowLoc, explicitResultType, inLoc); + parseClosureSignatureIfPresent( + bracketRange, captureList, capturedSelfDecl, params, asyncLoc, throwsLoc, + arrowLoc, explicitResultType, inLoc); // If the closure was created in the context of an array type signature's // size expression, there will not be a local context. A parse error will @@ -2824,10 +2792,9 @@ ParserResult Parser::parseExprClosure() { unsigned discriminator = CurLocalContext->claimNextClosureDiscriminator(); // Create the closure expression and enter its context. - auto *closure = new (Context) ClosureExpr(bracketRange, capturedSelfDecl, - params, throwsLoc, arrowLoc, inLoc, - explicitResultType, discriminator, - CurDeclContext); + auto *closure = new (Context) ClosureExpr( + bracketRange, capturedSelfDecl, params, asyncLoc, throwsLoc, arrowLoc, + inLoc, explicitResultType, discriminator, CurDeclContext); // The arguments to the func are defined in their own scope. Scope S(this, ScopeKind::ClosureParams); ParseFunctionBody cc(*this, closure); diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp index a1c260f1e38bd..4dd005cb9cef9 100644 --- a/lib/Parse/ParseIfConfig.cpp +++ b/lib/Parse/ParseIfConfig.cpp @@ -603,17 +603,42 @@ static Expr *findAnyLikelySimulatorEnvironmentTest(Expr *Condition) { /// Delegate callback function to parse elements in the blocks. ParserResult Parser::parseIfConfig( llvm::function_ref &, bool)> parseElements) { + assert(Tok.is(tok::pound_if)); SyntaxParsingContext IfConfigCtx(SyntaxContext, SyntaxKind::IfConfigDecl); SmallVector Clauses; Parser::StructureMarkerRAII ParsingDecl( *this, Tok.getLoc(), Parser::StructureMarkerKind::IfConfig); + // Find the region containing code completion token. + SourceLoc codeCompletionClauseLoc; + if (SourceMgr.hasCodeCompletionBuffer() && + SourceMgr.getCodeCompletionBufferID() == L->getBufferID() && + SourceMgr.isBeforeInBuffer(Tok.getLoc(), + SourceMgr.getCodeCompletionLoc())) { + llvm::SaveAndRestore> H(CurrentTokenHash, None); + BacktrackingScope backtrack(*this); + do { + auto startLoc = Tok.getLoc(); + consumeToken(); + skipUntilConditionalBlockClose(); + auto endLoc = PreviousLoc; + if (SourceMgr.rangeContainsTokenLoc(SourceRange(startLoc, endLoc), + SourceMgr.getCodeCompletionLoc())){ + codeCompletionClauseLoc = startLoc; + break; + } + } while (Tok.isNot(tok::pound_endif, tok::eof)); + } + bool shouldEvaluate = // Don't evaluate if it's in '-parse' mode, etc. shouldEvaluatePoundIfDecls() && // If it's in inactive #if ... #endif block, there's no point to do it. - !getScopeInfo().isInactiveConfigBlock(); + !getScopeInfo().isInactiveConfigBlock() && + // If this directive contains code completion location, 'isActive' is + // determined solely by which block has the completion token. + !codeCompletionClauseLoc.isValid(); bool foundActive = false; bool isVersionCondition = false; @@ -658,6 +683,10 @@ ParserResult Parser::parseIfConfig( } } + // Treat the region containing code completion token as "active". + if (codeCompletionClauseLoc.isValid() && !foundActive) + isActive = (ClauseLoc == codeCompletionClauseLoc); + foundActive |= isActive; if (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) { diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 06b75b7c2df5f..9f45a7757a7e8 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -130,8 +130,10 @@ static ParserStatus parseDefaultArgument( defaultArgs->HasDefaultArgument = true; - if (initR.hasCodeCompletion()) + if (initR.hasCodeCompletion()) { + init = initR.get(); return makeParserCodeCompletionStatus(); + } if (initR.isNull()) return makeParserError(); @@ -572,7 +574,6 @@ mapParsedParameters(Parser &parser, // Collect the elements of the tuple patterns for argument and body // parameters. SmallVector elements; - SourceLoc ellipsisLoc; for (auto ¶m : params) { // Whether the provided name is API by default depends on the parameter @@ -623,27 +624,26 @@ mapParsedParameters(Parser &parser, } // Warn when an unlabeled parameter follows a variadic parameter - if (ellipsisLoc.isValid() && elements.back()->isVariadic() && - param.FirstName.empty()) { - parser.diagnose(param.FirstNameLoc, - diag::unlabeled_parameter_following_variadic_parameter); + if (!elements.empty() && elements.back()->isVariadic() && argName.empty()) { + // Closure parameters can't have external labels, so use a more specific + // diagnostic. + if (paramContext == Parser::ParameterContextKind::Closure) + parser.diagnose( + param.FirstNameLoc, + diag::closure_unlabeled_parameter_following_variadic_parameter); + else + parser.diagnose(param.FirstNameLoc, + diag::unlabeled_parameter_following_variadic_parameter); } - - // If this parameter had an ellipsis, check whether it's the last parameter. - if (param.EllipsisLoc.isValid()) { - if (ellipsisLoc.isValid()) { - parser.diagnose(param.EllipsisLoc, diag::multiple_parameter_ellipsis) - .highlight(ellipsisLoc) - .fixItRemove(param.EllipsisLoc); - param.EllipsisLoc = SourceLoc(); - } else if (!result->getTypeRepr()) { + // If this parameter had an ellipsis, check it has a TypeRepr. + if (param.EllipsisLoc.isValid()) { + if (!result->getTypeRepr()) { parser.diagnose(param.EllipsisLoc, diag::untyped_pattern_ellipsis) .highlight(result->getSourceRange()); param.EllipsisLoc = SourceLoc(); } else { - ellipsisLoc = param.EllipsisLoc; result->setVariadic(); } } @@ -824,7 +824,7 @@ Parser::parseFunctionSignature(Identifier SimpleName, void Parser::parseAsyncThrows( SourceLoc existingArrowLoc, SourceLoc &asyncLoc, SourceLoc &throwsLoc, bool *rethrows) { - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) { asyncLoc = consumeToken(); @@ -857,7 +857,7 @@ void Parser::parseAsyncThrows( .fixItInsert(existingArrowLoc, (keyword + " ").str()); } - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) { asyncLoc = consumeToken(); diff --git a/lib/Parse/ParseRequests.cpp b/lib/Parse/ParseRequests.cpp index e0399897c1baa..99a4b3a3c5d1f 100644 --- a/lib/Parse/ParseRequests.cpp +++ b/lib/Parse/ParseRequests.cpp @@ -49,15 +49,29 @@ void swift::simple_display(llvm::raw_ostream &out, FingerprintAndMembers ParseMembersRequest::evaluate(Evaluator &evaluator, IterableDeclContext *idc) const { - SourceFile &sf = *idc->getAsGenericContext()->getParentSourceFile(); - unsigned bufferID = *sf.getBufferID(); + SourceFile *sf = idc->getAsGenericContext()->getParentSourceFile(); + ASTContext &ctx = idc->getDecl()->getASTContext(); + if (!sf) { + // If there is no parent source file, this is a deserialized or synthesized + // declaration context, in which case `getMembers()` has all of the members. + // Filter out the implicitly-generated ones. + SmallVector members; + for (auto decl : idc->getMembers()) { + if (!decl->isImplicit()) { + members.push_back(decl); + } + } + + return FingerprintAndMembers{None, ctx.AllocateCopy(members)}; + } + + unsigned bufferID = *sf->getBufferID(); // Lexer diaganostics have been emitted during skipping, so we disable lexer's // diagnostic engine here. - Parser parser(bufferID, sf, /*No Lexer Diags*/nullptr, nullptr, nullptr); + Parser parser(bufferID, *sf, /*No Lexer Diags*/nullptr, nullptr, nullptr); // Disable libSyntax creation in the delayed parsing. parser.SyntaxContext->disable(); - ASTContext &ctx = idc->getDecl()->getASTContext(); auto declsAndHash = parser.parseDeclListDelayed(idc); FingerprintAndMembers fingerprintAndMembers = {declsAndHash.second, declsAndHash.first}; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index a58f435d8dc1f..c4a64ca54973e 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -898,9 +898,7 @@ ParserResult Parser::parseStmtThrow(SourceLoc tryLoc) { exprLoc = Tok.getLoc(); ParserResult Result = parseExpr(diag::expected_expr_throw); - - if (Result.hasCodeCompletion()) - return makeParserCodeCompletionResult(); + bool hasCodeCompletion = Result.hasCodeCompletion(); if (Result.isNull()) Result = makeParserErrorResult(new (Context) ErrorExpr(throwLoc)); @@ -916,6 +914,9 @@ ParserResult Parser::parseStmtThrow(SourceLoc tryLoc) { Result = makeParserResult(new (Context) TryExpr(exprLoc, Result.get())); } + if (hasCodeCompletion) + Result.setHasCodeCompletion(); + return makeParserResult(Result, new (Context) ThrowStmt(throwLoc, Result.get())); } @@ -943,20 +944,12 @@ ParserResult Parser::parseStmtDefer() { // closure's DeclContext. auto params = ParameterList::createEmpty(Context); DeclName name(Context, Context.getIdentifier("$defer"), params); - auto tempDecl - = FuncDecl::create(Context, - /*StaticLoc=*/ SourceLoc(), - StaticSpellingKind::None, - /*FuncLoc=*/ SourceLoc(), - name, - /*NameLoc=*/ PreviousLoc, - /*Async=*/ false, /*AsyncLoc=*/ SourceLoc(), - /*Throws=*/ false, /*ThrowsLoc=*/ SourceLoc(), - /*generic params*/ nullptr, - params, - TypeLoc(), - CurDeclContext); - tempDecl->setImplicit(); + auto *const tempDecl = FuncDecl::createImplicit( + Context, StaticSpellingKind::None, name, /*NameLoc=*/PreviousLoc, + /*Async=*/false, + /*Throws=*/false, + /*GenericParams*/ nullptr, params, TupleType::getEmpty(Context), + CurDeclContext); setLocalDiscriminator(tempDecl); ParserStatus Status; { @@ -2020,9 +2013,6 @@ ParserResult Parser::parseStmtCatch() { GuardedPattern PatternResult; parseGuardedPattern(*this, PatternResult, status, boundDecls, GuardedPatternContext::Catch, isFirst); - if (status.hasCodeCompletion()) { - return makeParserCodeCompletionResult(); - } caseLabelItems.emplace_back(PatternResult.ThePattern, PatternResult.WhereLoc, PatternResult.Guard); isFirst = false; diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index aefea2401c15a..8dc5795905458 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -412,7 +412,7 @@ ParserResult Parser::parseType(Diag<> MessageID, // Parse an async specifier. SourceLoc asyncLoc; - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) { asyncLoc = consumeToken(); } @@ -423,7 +423,7 @@ ParserResult Parser::parseType(Diag<> MessageID, SourceLoc throwsLoc; if (Tok.isAny(tok::kw_throws, tok::kw_rethrows, tok::kw_throw, tok::kw_try) && (peekToken().is(tok::arrow) || - (Context.LangOpts.EnableExperimentalConcurrency && + (shouldParseExperimentalConcurrency() && peekToken().isContextualKeyword("async")))) { if (Tok.isAny(tok::kw_rethrows, tok::kw_throw, tok::kw_try)) { // 'rethrows' is only allowed on function declarations for now. @@ -436,7 +436,7 @@ ParserResult Parser::parseType(Diag<> MessageID, throwsLoc = consumeToken(); // 'async' must preceed 'throws'; accept this but complain. - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) { asyncLoc = consumeToken(); @@ -1589,7 +1589,7 @@ bool Parser::canParseType() { } // Handle type-function if we have an 'async'. - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) { consumeToken(); @@ -1605,7 +1605,7 @@ bool Parser::canParseType() { // Allow 'async' here even though it is ill-formed, so we can provide // a better error. - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) consumeToken(); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 601527fa7ba19..00282363d56c8 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -203,7 +203,7 @@ void Parser::performCodeCompletionSecondPassImpl( case CodeCompletionDelayedDeclKind::FunctionBody: { auto *AFD = cast(DC); - AFD->setBodyParsed(parseAbstractFunctionBodyImpl(AFD).getPtrOrNull()); + (void)parseAbstractFunctionBodyImpl(AFD); break; } } @@ -695,8 +695,9 @@ void Parser::skipSingle() { void Parser::skipUntil(tok T1, tok T2) { // tok::NUM_TOKENS is a sentinel that means "don't skip". if (T1 == tok::NUM_TOKENS && T2 == tok::NUM_TOKENS) return; - - while (Tok.isNot(T1, T2, tok::eof, tok::pound_endif, tok::code_complete)) + + while (Tok.isNot(T1, T2, tok::eof, tok::pound_endif, tok::pound_else, + tok::pound_elseif)) skipSingle(); } @@ -1189,6 +1190,7 @@ struct ParserUnit::Implementation { LangOptions LangOpts; TypeCheckerOptions TypeCheckerOpts; SearchPathOptions SearchPathOpts; + ClangImporterOptions clangImporterOpts; DiagnosticEngine Diags; ASTContext &Ctx; SourceFile *SF; @@ -1200,8 +1202,8 @@ struct ParserUnit::Implementation { std::shared_ptr spActions) : SPActions(std::move(spActions)), LangOpts(Opts), TypeCheckerOpts(TyOpts), Diags(SM), - Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SearchPathOpts, SM, - Diags)) { + Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SearchPathOpts, + clangImporterOpts, SM, Diags)) { auto parsingOpts = SourceFile::getDefaultParsingOptions(LangOpts); parsingOpts |= ParsingFlags::DisableDelayedBodies; parsingOpts |= ParsingFlags::DisablePoundIfEvaluation; diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index b848f04627854..d380fec22edf5 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -18,6 +18,7 @@ #include "swift/AST/Comment.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/PrettyStackTrace.h" @@ -32,6 +33,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/SourceManager.h" using namespace swift; using namespace swift::objc_translation; @@ -463,6 +465,7 @@ class DeclAndTypePrinter::Implementation Type getForeignResultType(AbstractFunctionDecl *AFD, FunctionType *methodTy, + Optional asyncConvention, Optional errorConvention) { // A foreign error convention can affect the result type as seen in // Objective-C. @@ -483,6 +486,11 @@ class DeclAndTypePrinter::Implementation } } + // Asynchronous methods return their results via completion handler. + if (asyncConvention) { + return getASTContext().TheEmptyTupleType; + } + auto result = methodTy->getResult(); if (result->isUninhabited()) return getASTContext().TheEmptyTupleType; @@ -512,16 +520,20 @@ class DeclAndTypePrinter::Implementation } } + Optional asyncConvention + = AFD->getForeignAsyncConvention(); Optional errorConvention = AFD->getForeignErrorConvention(); Type rawMethodTy = AFD->getMethodInterfaceType(); auto methodTy = rawMethodTy->castTo(); - auto resultTy = getForeignResultType(AFD, methodTy, errorConvention); + auto resultTy = getForeignResultType( + AFD, methodTy, asyncConvention, errorConvention); // Constructors and methods returning DynamicSelf return // instancetype. if (isa(AFD) || - (isa(AFD) && cast(AFD)->hasDynamicSelfResult())) { + (isa(AFD) && cast(AFD)->hasDynamicSelfResult() && + !AFD->hasAsync())) { if (errorConvention && errorConvention->stripsResultOptionality()) { printNullability(OTK_Optional, NullabilityPrintKind::ContextSensitive); } else if (auto ctor = dyn_cast(AFD)) { @@ -577,6 +589,16 @@ class DeclAndTypePrinter::Implementation StringRef piece = selectorPieces[i].empty() ? StringRef("") : selectorPieces[i].str(); + // If we have an async convention and this is the completion handler + // parameter, print it. + if (asyncConvention && + i == asyncConvention->completionHandlerParamIndex()) { + os << piece << ":("; + print(asyncConvention->completionHandlerType(), None); + os << ")completionHandler"; + continue; + } + // If we have an error convention and this is the error // parameter, print it. if (errorConvention && i == errorConvention->getErrorParameterIndex()) { @@ -659,7 +681,9 @@ class DeclAndTypePrinter::Implementation if (looksLikeInitMethod(AFD->getObjCSelector())) { os << " SWIFT_METHOD_FAMILY(none)"; } - if (methodTy->getResult()->isUninhabited()) { + if (asyncConvention) { + // Async methods don't have result types to annotate. + } else if (methodTy->getResult()->isUninhabited()) { os << " SWIFT_NORETURN"; } else if (!methodTy->getResult()->isVoid() && !AFD->getAttrs().hasAttribute()) { @@ -696,12 +720,15 @@ class DeclAndTypePrinter::Implementation void printAbstractFunctionAsFunction(FuncDecl *FD) { printDocumentationComment(FD); + Optional asyncConvention + = FD->getForeignAsyncConvention(); Optional errorConvention = FD->getForeignErrorConvention(); assert(!FD->getGenericSignature() && "top-level generic functions not supported here"); auto funcTy = FD->getInterfaceType()->castTo(); - auto resultTy = getForeignResultType(FD, funcTy, errorConvention); + auto resultTy = getForeignResultType( + FD, funcTy, asyncConvention, errorConvention); // The result type may be a partial function type we need to close // up later. @@ -1339,6 +1366,7 @@ class DeclAndTypePrinter::Implementation return true; } +public: /// If \p nominal is bridged to an Objective-C class (via a conformance to /// _ObjectiveCBridgeable), return that class. /// @@ -1369,6 +1397,7 @@ class DeclAndTypePrinter::Implementation return objcType->getClassOrBoundGenericClass(); } +private: /// If the nominal type is bridged to Objective-C (via a conformance /// to _ObjectiveCBridgeable), print the bridged type. void printObjCBridgeableType(const NominalTypeDecl *swiftNominal, @@ -1570,12 +1599,16 @@ class DeclAndTypePrinter::Implementation } bool printImportedAlias(const TypeAliasDecl *alias, + ArrayRef genericArgs, Optional optionalKind) { if (!alias->hasClangNode()) return false; if (auto *clangTypeDecl = dyn_cast(alias->getClangDecl())) { + assert(!alias->isGeneric() + && "generic typealias backed by clang typedecl?"); + maybePrintTagKeyword(alias); os << getNameForObjC(alias); @@ -1583,12 +1616,19 @@ class DeclAndTypePrinter::Implementation printNullability(optionalKind); } else if (auto *clangObjCClass = dyn_cast(alias->getClangDecl())){ + assert(!alias->isGeneric() + && "generic typealias backed by clang interface?"); + os << clangObjCClass->getName() << " *"; printNullability(optionalKind); } else { auto *clangCompatAlias = cast(alias->getClangDecl()); - os << clangCompatAlias->getName() << " *"; + + os << clangCompatAlias->getName(); + if (!genericArgs.empty()) + printGenericArgs(genericArgs); + os << " *"; printNullability(optionalKind); } @@ -1598,10 +1638,12 @@ class DeclAndTypePrinter::Implementation void visitTypeAliasType(TypeAliasType *aliasTy, Optional optionalKind) { const TypeAliasDecl *alias = aliasTy->getDecl(); + auto genericArgs = aliasTy->getDirectGenericArgs(); + if (printIfKnownSimpleType(alias, optionalKind)) return; - if (printImportedAlias(alias, optionalKind)) + if (printImportedAlias(alias, genericArgs, optionalKind)) return; visitPart(aliasTy->getSinglyDesugaredType(), optionalKind); @@ -1735,8 +1777,12 @@ class DeclAndTypePrinter::Implementation } void printGenericArgs(BoundGenericType *BGT) { + printGenericArgs(BGT->getGenericArgs()); + } + + void printGenericArgs(ArrayRef genericArgs) { os << '<'; - interleave(BGT->getGenericArgs(), + interleave(genericArgs, [this](Type t) { print(t, None); }, [this] { os << ", "; }); os << '>'; @@ -1890,7 +1936,7 @@ class DeclAndTypePrinter::Implementation assert(extension->getGenericSignature().getCanonicalSignature() == extendedClass->getGenericSignature().getCanonicalSignature() && "constrained extensions or custom generic parameters?"); - type = extendedClass->getGenericEnvironment()->getSugaredType(type); + type = extendedClass->getGenericSignature()->getSugaredType(type); decl = type->getDecl(); } @@ -2067,6 +2113,14 @@ bool DeclAndTypePrinter::isEmptyExtensionDecl(const ExtensionDecl *ED) { return getImpl().isEmptyExtensionDecl(ED); } +const TypeDecl *DeclAndTypePrinter::getObjCTypeDecl(const TypeDecl* TD) { + if (auto *nominal = dyn_cast(TD)) + if (auto *bridged = getImpl().getObjCBridgedClass(nominal)) + return bridged; + + return TD; +} + StringRef DeclAndTypePrinter::maybeGetOSObjectBaseName(const clang::NamedDecl *decl) { StringRef name = decl->getName(); diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.h b/lib/PrintAsObjC/DeclAndTypePrinter.h index 933f2ea16a859..c7718faac3e6b 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.h +++ b/lib/PrintAsObjC/DeclAndTypePrinter.h @@ -73,6 +73,14 @@ class DeclAndTypePrinter { /// Is \p ED empty of members and protocol conformances to include? bool isEmptyExtensionDecl(const ExtensionDecl *ED); + /// Returns the type that will be printed by PrintAsObjC for a parameter or + /// result type resolved to this declaration. + /// + /// \warning This handles \c _ObjectiveCBridgeable types, but it doesn't + /// currently know about other aspects of PrintAsObjC behavior, like known + /// types. + const TypeDecl *getObjCTypeDecl(const TypeDecl* TD); + /// Prints a category declaring the given members. /// /// All members must have the same parent type. The list must not be empty. diff --git a/lib/PrintAsObjC/ModuleContentsWriter.cpp b/lib/PrintAsObjC/ModuleContentsWriter.cpp index ba703f28937cc..6d4d53b966ff8 100644 --- a/lib/PrintAsObjC/ModuleContentsWriter.cpp +++ b/lib/PrintAsObjC/ModuleContentsWriter.cpp @@ -16,12 +16,14 @@ #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Module.h" +#include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SwiftNameTranslation.h" #include "swift/AST/TypeDeclFinder.h" #include "swift/ClangImporter/ClangImporter.h" #include "clang/AST/Decl.h" +#include "clang/Basic/Module.h" #include "llvm/Support/raw_ostream.h" @@ -56,7 +58,6 @@ class ReferencedTypeFinder : public TypeDeclFinder { Action visitTypeAliasType(TypeAliasType *aliasTy) override { if (aliasTy->getDecl()->hasClangNode() && !aliasTy->getDecl()->isCompatibilityAlias()) { - assert(!aliasTy->getDecl()->isGeneric()); Callback(*this, aliasTy->getDecl()); } else { Type(aliasTy->getSinglyDesugaredType()).walk(*this); @@ -235,6 +236,8 @@ class ModuleWriter { } bool forwardDeclareMemberTypes(DeclRange members, const Decl *container) { + PrettyStackTraceDecl + entry("printing forward declarations needed by members of", container); switch (container->getKind()) { case DeclKind::Class: case DeclKind::Protocol: @@ -247,6 +250,7 @@ class ModuleWriter { bool hadAnyDelayedMembers = false; SmallVector nestedTypes; for (auto member : members) { + PrettyStackTraceDecl loopEntry("printing for member", member); auto VD = dyn_cast(member); if (!VD || !printer.shouldInclude(VD)) continue; @@ -269,9 +273,14 @@ class ModuleWriter { ReferencedTypeFinder::walk(VD->getInterfaceType(), [&](ReferencedTypeFinder &finder, const TypeDecl *TD) { + PrettyStackTraceDecl + entry("walking its interface type, currently at", TD); if (TD == container) return; + // Bridge, if necessary. + TD = printer.getObjCTypeDecl(TD); + if (finder.needsDefinition() && isa(TD)) { // We can delay individual members of classes; do so if necessary. if (isa(container)) { @@ -310,8 +319,10 @@ class ModuleWriter { } else if (auto PD = dyn_cast(TD)) { forwardDeclare(PD); } else if (auto TAD = dyn_cast(TD)) { + bool imported = false; if (TAD->hasClangNode()) - (void)addImport(TD); + imported = addImport(TD); + assert((imported || !TAD->isGeneric()) && "referencing non-imported generic typealias?"); } else if (addImport(TD)) { return; } else if (auto ED = dyn_cast(TD)) { diff --git a/lib/RemoteAST/RemoteAST.cpp b/lib/RemoteAST/RemoteAST.cpp index 686a8421f642d..0f937e95cec77 100644 --- a/lib/RemoteAST/RemoteAST.cpp +++ b/lib/RemoteAST/RemoteAST.cpp @@ -632,9 +632,10 @@ class RemoteASTContextConcreteImpl final : public RemoteASTContextImpl { SubstitutionMap substitutions, unsigned ordinal) override { auto underlyingType = Reader - .readUnderlyingTypeForOpaqueTypeDescriptor(opaqueDescriptor.getAddressData(), - ordinal); - + .readUnderlyingTypeForOpaqueTypeDescriptor( + opaqueDescriptor.getAddressData(), ordinal) + .getType(); + if (!underlyingType) return getFailure(); diff --git a/lib/SIL/IR/AbstractionPattern.cpp b/lib/SIL/IR/AbstractionPattern.cpp index 98b35f470a549..5592dd1d3bef4 100644 --- a/lib/SIL/IR/AbstractionPattern.cpp +++ b/lib/SIL/IR/AbstractionPattern.cpp @@ -236,7 +236,7 @@ bool AbstractionPattern::requiresClass() const { // ObjC generics are always class constrained. return true; } - + assert(GenericSig && "Dependent type in pattern without generic signature?"); return GenericSig->requiresClass(type); @@ -250,30 +250,23 @@ bool AbstractionPattern::requiresClass() const { } LayoutConstraint AbstractionPattern::getLayoutConstraint() const { - // TODO: `ArchetypeType::getLayoutConstraint` and - // `GenericSignature::getLayoutConstraint` don't always propagate implied - // layout constraints from protocol/class constraints. `requiresClass` - // is, for the time being, the only one we really care about, though, and - // it behaves correctly. - if (requiresClass()) { - return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Class); - } - return LayoutConstraint(); - -#if GET_LAYOUT_CONSTRAINT_WORKED_THE_WAY_I_WANT switch (getKind()) { case Kind::Opaque: return LayoutConstraint(); case Kind::Type: - case Kind::Discard: { + case Kind::Discard: + case Kind::ClangType: { auto type = getType(); if (auto archetype = dyn_cast(type)) { - auto archetypeSig = archetype->getGenericEnvironment() - ->getGenericSignature(); - return archetypeSig->getLayoutConstraint(archetype->getInterfaceType()); - } - else if (isa(type) || - isa(type)) { + return archetype->getLayoutConstraint(); + } else if (isa(type) || + isa(type)) { + if (getKind() == Kind::ClangType) { + // ObjC generics are always class constrained. + return LayoutConstraint::getLayoutConstraint( + LayoutConstraintKind::Class); + } + assert(GenericSig && "Dependent type in pattern without generic signature?"); return GenericSig->getLayoutConstraint(type); @@ -283,7 +276,6 @@ LayoutConstraint AbstractionPattern::getLayoutConstraint() const { default: return LayoutConstraint(); } -#endif } bool AbstractionPattern::matchesTuple(CanTupleType substType) { diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp index 42c19adb7b30e..1b6f2ce79950f 100644 --- a/lib/SIL/IR/SILDeclRef.cpp +++ b/lib/SIL/IR/SILDeclRef.cpp @@ -233,13 +233,11 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { return forDefinition ? linkage : addExternalToLinkage(linkage); }; - // Native function-local declarations have shared linkage. - // FIXME: @objc declarations should be too, but we currently have no way - // of marking them "used" other than making them external. + // Function-local declarations have private linkage, unless serialized. ValueDecl *d = getDecl(); DeclContext *moduleContext = d->getDeclContext(); while (!moduleContext->isModuleScopeContext()) { - if (!isForeign && moduleContext->isLocalContext()) { + if (moduleContext->isLocalContext()) { return isSerialized() ? SILLinkage::Shared : SILLinkage::Private; } moduleContext = moduleContext->getParent(); @@ -249,11 +247,6 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { if (isForeignToNativeThunk()) return SILLinkage::Shared; - // If a function declares a @_cdecl name, its native-to-foreign thunk - // is exported with the visibility of the function. - if (isNativeToForeignThunk() && !d->getAttrs().hasAttribute()) - return SILLinkage::Shared; - // Declarations imported from Clang modules have shared linkage. if (isClangImported()) return SILLinkage::Shared; @@ -329,12 +322,20 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { } } - // Forced-static-dispatch functions are created on-demand and have - // at best shared linkage. if (auto fn = dyn_cast(d)) { + // Forced-static-dispatch functions are created on-demand and have + // at best shared linkage. if (fn->hasForcedStaticDispatch()) { limit = Limit::OnDemand; } + + // Native-to-foreign thunks for top-level decls are created on-demand, + // unless they are marked @_cdecl, in which case they expose a dedicated + // entry-point with the visibility of the function. + if (isNativeToForeignThunk() && !fn->getAttrs().hasAttribute()) { + if (fn->getDeclContext()->isModuleScopeContext()) + limit = Limit::OnDemand; + } } if (isEnumElement()) { @@ -613,34 +614,42 @@ EffectsKind SILDeclRef::getEffectsAttribute() const { } bool SILDeclRef::isForeignToNativeThunk() const { + // If this isn't a native entry-point, it's not a foreign-to-native thunk. + if (isForeign) + return false; + // Non-decl entry points are never natively foreign, so they would never // have a foreign-to-native thunk. if (!hasDecl()) return false; if (requiresForeignToNativeThunk(getDecl())) - return !isForeign; + return true; // ObjC initializing constructors and factories are foreign. // We emit a special native allocating constructor though. if (isa(getDecl()) && (kind == Kind::Initializer || cast(getDecl())->isFactoryInit()) && getDecl()->hasClangNode()) - return !isForeign; + return true; return false; } bool SILDeclRef::isNativeToForeignThunk() const { + // If this isn't a foreign entry-point, it's not a native-to-foreign thunk. + if (!isForeign) + return false; + // We can have native-to-foreign thunks over closures. if (!hasDecl()) - return isForeign; - // We can have native-to-foreign thunks over global or local native functions. - // TODO: Static functions too. - if (auto func = dyn_cast(getDecl())) { - if (!func->getDeclContext()->isTypeContext() - && !func->hasClangNode()) - return isForeign; - } - return false; + return true; + + // A decl with a clang node doesn't have a native entry-point to forward onto. + if (getDecl()->hasClangNode()) + return false; + + // Only certain kinds of SILDeclRef can expose native-to-foreign thunks. + return kind == Kind::Func || kind == Kind::Initializer || + kind == Kind::Deallocator; } /// Use the Clang importer to mangle a Clang declaration. diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp index f5e27bbd56c1b..dd118be43c2ae 100644 --- a/lib/SIL/IR/SILFunction.cpp +++ b/lib/SIL/IR/SILFunction.cpp @@ -107,7 +107,7 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, StringRef Name, ExactSelfClass(isExactSelfClass), Inlined(false), Zombie(false), HasOwnership(true), WasDeserializedCanonical(false), IsWithoutActuallyEscapingThunk(false), - IsAsync(false), OptMode(unsigned(OptimizationMode::NotSet)), + OptMode(unsigned(OptimizationMode::NotSet)), EffectsKindAttr(unsigned(E)) { assert(!Transparent || !IsDynamicReplaceable); validateSubclassScope(classSubclassScope, isThunk, nullptr); @@ -629,7 +629,7 @@ void SILFunction::setObjCReplacement(Identifier replacedFunc) { // linkage dependency. struct SILFunctionTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const SILFunction *F = static_cast(Entity); @@ -637,7 +637,7 @@ struct SILFunctionTraceFormatter : public UnifiedStatsReporter::TraceFormatter { } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const SILFunction *F = static_cast(Entity); diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index c28ba05090b1b..0ec7e74dbb4d2 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -54,7 +54,7 @@ void SILFunctionBuilder::addFunctionAttributes( ? SILSpecializeAttr::SpecializationKind::Full : SILSpecializeAttr::SpecializationKind::Partial; F->addSpecializeAttr( - SILSpecializeAttr::create(M, SA->getSpecializedSgnature(), + SILSpecializeAttr::create(M, SA->getSpecializedSignature(), SA->isExported(), kind)); } @@ -217,10 +217,6 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction( } addFunctionAttributes(F, decl->getAttrs(), mod, getOrCreateDeclaration, constant); - - if (auto *funcDecl = dyn_cast(decl)) { - F->setAsync(funcDecl->hasAsync()); - } } return F; diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 60f7584418787..2fc920638e98f 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -407,6 +407,7 @@ static CanSILFunctionType getAutoDiffDifferentialType( // result's convention is indirect. if (tl.isAddressOnly() && !isIndirectFormalResult(origResConv)) { switch (origResConv) { + case ResultConvention::Unowned: case ResultConvention::Owned: return ResultConvention::Indirect; default: @@ -536,6 +537,8 @@ static CanSILFunctionType getAutoDiffPullbackType( TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); ParameterConvention conv; switch (origResConv) { + case ResultConvention::Unowned: + case ResultConvention::UnownedInnerPointer: case ResultConvention::Owned: case ResultConvention::Autoreleased: if (tl.isAddressOnly()) { @@ -545,10 +548,6 @@ static CanSILFunctionType getAutoDiffPullbackType( : ParameterConvention::Direct_Guaranteed; } break; - case ResultConvention::Unowned: - case ResultConvention::UnownedInnerPointer: - conv = ParameterConvention::Direct_Unowned; - break; case ResultConvention::Indirect: conv = ParameterConvention::Indirect_In_Guaranteed; break; @@ -1214,8 +1213,6 @@ class SubstFunctionTypeCollector { substRequirements.push_back( Requirement(RequirementKind::Layout, param, layout)); } - } else { - (void)0; } for (unsigned i : indices(upperBoundConformances)) { @@ -1304,7 +1301,7 @@ class SubstFunctionTypeCollector { if (origContextType->hasTypeParameter()) { origContextType = origSig->getGenericEnvironment() ->mapTypeIntoContext(origContextType) - ->getCanonicalType(origSig); + ->getCanonicalType(); } auto result = origContextType @@ -1313,12 +1310,7 @@ class SubstFunctionTypeCollector { CanType binding, ArchetypeType *upperBound, ArrayRef bindingConformances) -> CanType { - // TODO: ArchetypeType::getLayoutConstraint sometimes misses out on - // implied layout constraints. For now AnyObject is the only one we - // care about. - return addSubstitution(archetype->requiresClass() - ? LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Class) - : LayoutConstraint(), + return addSubstitution(archetype->getLayoutConstraint(), binding, upperBound, bindingConformances); @@ -2400,6 +2392,12 @@ static CanSILFunctionType getNativeSILFunctionType( Optional reqtSubs, ProtocolConformanceRef witnessMethodConformance) { assert(bool(origConstant) == bool(constant)); + auto getSILFunctionTypeForConventions = + [&](const Conventions &convs) -> CanSILFunctionType { + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, convs, ForeignInfo(), origConstant, + constant, reqtSubs, witnessMethodConformance); + }; switch (extInfo.getSILRepresentation()) { case SILFunctionType::Representation::Block: case SILFunctionType::Representation::CFunctionPointer: @@ -2416,42 +2414,29 @@ static CanSILFunctionType getNativeSILFunctionType( switch (constant ? constant->kind : SILDeclRef::Kind::Func) { case SILDeclRef::Kind::Initializer: case SILDeclRef::Kind::EnumElement: - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DefaultInitializerConventions(), - ForeignInfo(), origConstant, constant, reqtSubs, - witnessMethodConformance); + return getSILFunctionTypeForConventions(DefaultInitializerConventions()); case SILDeclRef::Kind::Allocator: - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DefaultAllocatorConventions(), - ForeignInfo(), origConstant, constant, reqtSubs, - witnessMethodConformance); - case SILDeclRef::Kind::Func: + return getSILFunctionTypeForConventions(DefaultAllocatorConventions()); + case SILDeclRef::Kind::Func: { // If we have a setter, use the special setter convention. This ensures // that we take normal parameters at +1. if (constant && constant->isSetter()) { - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DefaultSetterConventions(), - ForeignInfo(), origConstant, constant, - reqtSubs, witnessMethodConformance); + return getSILFunctionTypeForConventions(DefaultSetterConventions()); } - LLVM_FALLTHROUGH; + return getSILFunctionTypeForConventions( + DefaultConventions(NormalParameterConvention::Guaranteed)); + } case SILDeclRef::Kind::Destroyer: case SILDeclRef::Kind::GlobalAccessor: case SILDeclRef::Kind::DefaultArgGenerator: case SILDeclRef::Kind::StoredPropertyInitializer: case SILDeclRef::Kind::PropertyWrapperBackingInitializer: case SILDeclRef::Kind::IVarInitializer: - case SILDeclRef::Kind::IVarDestroyer: { - auto conv = DefaultConventions(NormalParameterConvention::Guaranteed); - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, conv, ForeignInfo(), origConstant, - constant, reqtSubs, witnessMethodConformance); - } + case SILDeclRef::Kind::IVarDestroyer: + return getSILFunctionTypeForConventions( + DefaultConventions(NormalParameterConvention::Guaranteed)); case SILDeclRef::Kind::Deallocator: - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DeallocatorConventions(), - ForeignInfo(), origConstant, constant, reqtSubs, - witnessMethodConformance); + return getSILFunctionTypeForConventions(DeallocatorConventions()); } } } @@ -3997,27 +3982,17 @@ SILFunctionType::substituteOpaqueArchetypes(TypeConverter &TC, CanAnyFunctionType TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, CanAnyFunctionType t, - AnyFunctionType::ExtInfo extInfo, Bridgeability bridging) { // Pull out the generic signature. CanGenericSignature genericSig = t.getOptGenericSignature(); - switch (auto rep = t->getExtInfo().getSILRepresentation()) { - case SILFunctionTypeRepresentation::Thick: - case SILFunctionTypeRepresentation::Thin: - case SILFunctionTypeRepresentation::Method: - case SILFunctionTypeRepresentation::Closure: - case SILFunctionTypeRepresentation::WitnessMethod: { + auto rep = t->getExtInfo().getSILRepresentation(); + switch (getSILFunctionLanguage(rep)) { + case SILFunctionLanguage::Swift: { // No bridging needed for native functions. - if (t->getExtInfo().isEqualTo(extInfo, useClangTypes(t))) - return t; - return CanAnyFunctionType::get(genericSig, t.getParams(), t.getResult(), - extInfo); + return t; } - - case SILFunctionTypeRepresentation::CFunctionPointer: - case SILFunctionTypeRepresentation::Block: - case SILFunctionTypeRepresentation::ObjCMethod: { + case SILFunctionLanguage::C: { SmallVector params; getBridgedParams(rep, pattern, t->getParams(), params, bridging); @@ -4029,7 +4004,7 @@ TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, suppressOptional); return CanAnyFunctionType::get(genericSig, llvm::makeArrayRef(params), - result, extInfo); + result, t->getExtInfo()); } } llvm_unreachable("bad calling convention"); @@ -4111,7 +4086,6 @@ TypeConverter::getLoweredFormalTypes(SILDeclRef constant, auto bridging = Bridgeability::Full; unsigned numParameterLists = constant.getParameterListCount(); - auto extInfo = fnType->getExtInfo(); // Form an abstraction pattern for bridging purposes. AbstractionPattern bridgingFnPattern = @@ -4121,12 +4095,13 @@ TypeConverter::getLoweredFormalTypes(SILDeclRef constant, // Fast path: no uncurrying required. if (numParameterLists == 1) { auto bridgedFnType = - getBridgedFunctionType(bridgingFnPattern, fnType, extInfo, bridging); + getBridgedFunctionType(bridgingFnPattern, fnType, bridging); bridgingFnPattern.rewriteType(bridgingFnPattern.getGenericSignature(), bridgedFnType); return { bridgingFnPattern, bridgedFnType }; } + auto extInfo = fnType->getExtInfo(); SILFunctionTypeRepresentation rep = extInfo.getSILRepresentation(); assert(rep != SILFunctionType::Representation::Block && "objc blocks cannot be curried"); @@ -4477,19 +4452,9 @@ StringRef SILFunctionType::ABICompatibilityCheckResult::getMessage() const { llvm_unreachable("Covered switch isn't completely covered?!"); } -static DeclContext *getDeclContextForExpansion(const SILFunction &f) { - auto *dc = f.getDeclContext(); - if (!dc) - dc = f.getModule().getSwiftModule(); - auto *currentModule = f.getModule().getSwiftModule(); - if (!dc || !dc->isChildContextOf(currentModule)) - dc = currentModule; - return dc; -} - TypeExpansionContext::TypeExpansionContext(const SILFunction &f) : expansion(f.getResilienceExpansion()), - inContext(getDeclContextForExpansion(f)), + inContext(f.getModule().getAssociatedContext()), isContextWholeModule(f.getModule().isWholeModule()) {} CanSILFunctionType SILFunction::getLoweredFunctionTypeInContext( diff --git a/lib/SIL/IR/SILGlobalVariable.cpp b/lib/SIL/IR/SILGlobalVariable.cpp index 609a8318b153d..85407811bae76 100644 --- a/lib/SIL/IR/SILGlobalVariable.cpp +++ b/lib/SIL/IR/SILGlobalVariable.cpp @@ -272,7 +272,7 @@ SILFunction *swift::findInitializer(SILFunction *AddrF, if (!CallToOnce) return nullptr; SILFunction *callee = getCalleeOfOnceCall(CallToOnce); - if (!callee->getName().startswith("globalinit_")) + if (!callee->isGlobalInitOnceFunction()) return nullptr; return callee; } diff --git a/lib/SIL/IR/SILInstructions.cpp b/lib/SIL/IR/SILInstructions.cpp index 1faa9ec6ae6a1..bef2b17c534bc 100644 --- a/lib/SIL/IR/SILInstructions.cpp +++ b/lib/SIL/IR/SILInstructions.cpp @@ -762,10 +762,10 @@ getExtracteeType( LinearFunctionExtractInst::LinearFunctionExtractInst( SILModule &module, SILDebugLocation debugLoc, - LinearDifferentiableFunctionTypeComponent extractee, SILValue theFunction) - : InstructionBase(debugLoc, - getExtracteeType(theFunction, extractee, module)), - extractee(extractee), operands(this, theFunction) {} + LinearDifferentiableFunctionTypeComponent extractee, SILValue function) + : UnaryInstructionBase(debugLoc, function, + getExtracteeType(function, extractee, module)), + extractee(extractee) {} SILType DifferentiabilityWitnessFunctionInst::getDifferentiabilityWitnessType( SILModule &module, DifferentiabilityWitnessFunctionKind witnessKind, diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index bb84c23ef1e4c..17c3810556b77 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -462,18 +462,20 @@ static void printSILFunctionNameAndType( llvm::DenseMap &sugaredTypeNames) { function->printName(OS); OS << " : $"; - auto genSig = - function->getLoweredFunctionType()->getInvocationGenericSignature(); auto *genEnv = function->getGenericEnvironment(); - // If `genSig` and `genEnv` are both defined, get sugared names of generic + const GenericSignatureImpl *genSig = nullptr; + + // If `genEnv` is defined, get sugared names of generic // parameter types for printing. - if (genSig && genEnv) { + if (genEnv) { + genSig = genEnv->getGenericSignature().getPointer(); + llvm::DenseSet usedNames; llvm::SmallString<16> disambiguatedNameBuf; unsigned disambiguatedNameCounter = 1; for (auto *paramTy : genSig->getGenericParams()) { // Get a uniqued sugared name for the generic parameter type. - auto sugaredTy = genEnv->getSugaredType(paramTy); + auto sugaredTy = genEnv->getGenericSignature()->getSugaredType(paramTy); Identifier name = sugaredTy->getName(); while (!usedNames.insert(name).second) { disambiguatedNameBuf.clear(); @@ -495,7 +497,7 @@ static void printSILFunctionNameAndType( } } auto printOptions = PrintOptions::printSIL(); - printOptions.GenericEnv = genEnv; + printOptions.GenericSig = genSig; printOptions.AlternativeTypeNames = sugaredTypeNames.empty() ? nullptr : &sugaredTypeNames; function->getLoweredFunctionType()->print(OS, printOptions); @@ -2397,7 +2399,7 @@ class SILPrinter : public SILInstructionVisitor { break; } *this << "] "; - *this << getIDAndType(lfei->getFunctionOperand()); + *this << getIDAndType(lfei->getOperand()); } void visitDifferentiabilityWitnessFunctionInst( @@ -2598,15 +2600,15 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { if (isWithoutActuallyEscapingThunk()) OS << "[without_actually_escaping] "; - if (isAsync()) - OS << "[async] "; - switch (getSpecialPurpose()) { case SILFunction::Purpose::None: break; case SILFunction::Purpose::GlobalInit: OS << "[global_init] "; break; + case SILFunction::Purpose::GlobalInitOnceFunction: + OS << "[global_init_once_fn] "; + break; case SILFunction::Purpose::LazyPropertyGetter: OS << "[lazy_getter] "; break; @@ -3248,8 +3250,9 @@ void SILWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const { OS << "[serialized] "; getConformance()->printName(OS, Options); - Options.GenericEnv = - getConformance()->getDeclContext()->getGenericEnvironmentOfContext(); + Options.GenericSig = + getConformance()->getDeclContext()->getGenericSignatureOfContext() + .getPointer(); if (isDeclaration()) { OS << "\n\n"; @@ -3292,7 +3295,7 @@ void SILDefaultWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const { OS << getProtocol()->getName() << " {\n"; PrintOptions options = PrintOptions::printSIL(); - options.GenericEnv = Protocol->getGenericEnvironmentOfContext(); + options.GenericSig = Protocol->getGenericSignatureOfContext().getPointer(); for (auto &witness : getEntries()) { witness.print(OS, Verbose, options); @@ -3443,12 +3446,17 @@ void SILSpecializeAttr::print(llvm::raw_ostream &OS) const { OS << "exported: " << exported << ", "; OS << "kind: " << kind << ", "; + auto *genericEnv = getFunction()->getGenericEnvironment(); + GenericSignature genericSig; + if (genericEnv) + genericSig = genericEnv->getGenericSignature(); + ArrayRef requirements; SmallVector requirementsScratch; if (auto specializedSig = getSpecializedSignature()) { - if (auto env = getFunction()->getGenericEnvironment()) { + if (genericSig) { requirementsScratch = specializedSig->requirementsNotSatisfiedBy( - env->getGenericSignature()); + genericSig); requirements = requirementsScratch; } else { requirements = specializedSig->getRequirements(); @@ -3458,19 +3466,18 @@ void SILSpecializeAttr::print(llvm::raw_ostream &OS) const { OS << "where "; SILFunction *F = getFunction(); assert(F); - auto GenericEnv = F->getGenericEnvironment(); interleave(requirements, [&](Requirement req) { - if (!GenericEnv) { + if (!genericSig) { req.print(OS, SubPrinter); return; } // Use GenericEnvironment to produce user-friendly // names instead of something like t_0_0. - auto FirstTy = GenericEnv->getSugaredType(req.getFirstType()); + auto FirstTy = genericSig->getSugaredType(req.getFirstType()); if (req.getKind() != RequirementKind::Layout) { auto SecondTy = - GenericEnv->getSugaredType(req.getSecondType()); + genericSig->getSugaredType(req.getSecondType()); Requirement ReqWithDecls(req.getKind(), FirstTy, SecondTy); ReqWithDecls.print(OS, SubPrinter); } else { diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index aa007ad5c7d66..e06cb1ec471a1 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -421,10 +421,6 @@ namespace { RetTy visitArchetypeType(CanArchetypeType type, AbstractionPattern origType) { - if (type->requiresClass()) { - return asImpl().handleReference(type); - } - auto LayoutInfo = type->getLayoutConstraint(); if (LayoutInfo) { if (LayoutInfo->isFixedSizeTrivial()) { @@ -1623,7 +1619,7 @@ namespace { for (auto field : D->getStoredProperties()) { auto substFieldType = field->getInterfaceType().subst(subMap) - ->getCanonicalType(D->getGenericSignature()); + ->getCanonicalType(); // We are determining the recursive properties of the struct here, // not the lowered types of the fields, so instead of lowering the @@ -1676,7 +1672,7 @@ namespace { auto substEltType = elt->getArgumentInterfaceType().subst(subMap) - ->getCanonicalType(D->getGenericSignature()); + ->getCanonicalType(); auto origEltType = origType.unsafeGetSubstFieldType(elt, elt->getArgumentInterfaceType() @@ -1968,7 +1964,7 @@ TypeConverter::computeLoweredRValueType(TypeExpansionContext forExpansion, // Bridge the parameters and result of the function type. auto bridgedFnType = - TC.getBridgedFunctionType(origType, substFnType, extInfo, bridging); + TC.getBridgedFunctionType(origType, substFnType, bridging); substFnType = bridgedFnType; // Also rewrite the type of the abstraction pattern. diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 00ceaf52ca02e..f12b216fe0802 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -919,7 +919,6 @@ static bool parseDeclSILOptional(bool *isTransparent, bool *isWeakImported, AvailabilityContext *availability, bool *isWithoutActuallyEscapingThunk, - bool *isAsync, SmallVectorImpl *Semantics, SmallVectorImpl *SpecAttrs, ValueDecl **ClangDecl, @@ -958,12 +957,12 @@ static bool parseDeclSILOptional(bool *isTransparent, else if (isWithoutActuallyEscapingThunk && SP.P.Tok.getText() == "without_actually_escaping") *isWithoutActuallyEscapingThunk = true; - else if (isAsync && SP.P.Tok.getText() == "async") - *isAsync = true; else if (specialPurpose && SP.P.Tok.getText() == "global_init") *specialPurpose = SILFunction::Purpose::GlobalInit; else if (specialPurpose && SP.P.Tok.getText() == "lazy_getter") *specialPurpose = SILFunction::Purpose::LazyPropertyGetter; + else if (specialPurpose && SP.P.Tok.getText() == "global_init_once_fn") + *specialPurpose = SILFunction::Purpose::GlobalInitOnceFunction; else if (isWeakImported && SP.P.Tok.getText() == "weak_imported") { if (M.getASTContext().LangOpts.Target.isOSBinFormatCOFF()) SP.P.diagnose(SP.P.Tok, diag::attr_unsupported_on_target, @@ -5682,7 +5681,6 @@ bool SILParserState::parseDeclSIL(Parser &P) { bool isWeakImported = false; AvailabilityContext availability = AvailabilityContext::alwaysAvailable(); bool isWithoutActuallyEscapingThunk = false; - bool isAsync = false; Inline_t inlineStrategy = InlineDefault; OptimizationMode optimizationMode = OptimizationMode::NotSet; SmallVector Semantics; @@ -5697,8 +5695,8 @@ bool SILParserState::parseDeclSIL(Parser &P) { &isThunk, &isDynamic, &isExactSelfClass, &DynamicallyReplacedFunction, &objCReplacementFor, &specialPurpose, &inlineStrategy, &optimizationMode, nullptr, &isWeakImported, &availability, - &isWithoutActuallyEscapingThunk, &isAsync, &Semantics, &SpecAttrs, - &ClangDecl, &MRK, FunctionState, M) || + &isWithoutActuallyEscapingThunk, &Semantics, + &SpecAttrs, &ClangDecl, &MRK, FunctionState, M) || P.parseToken(tok::at_sign, diag::expected_sil_function_name) || P.parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) || P.parseToken(tok::colon, diag::expected_sil_type)) @@ -5736,7 +5734,6 @@ bool SILParserState::parseDeclSIL(Parser &P) { FunctionState.F->setAvailabilityForLinkage(availability); FunctionState.F->setWithoutActuallyEscapingThunk( isWithoutActuallyEscapingThunk); - FunctionState.F->setAsync(isAsync); FunctionState.F->setInlineStrategy(inlineStrategy); FunctionState.F->setOptimizationMode(optimizationMode); FunctionState.F->setEffectsKind(MRK); @@ -5922,9 +5919,10 @@ bool SILParserState::parseSILGlobal(Parser &P) { SILParser State(P); if (parseSILLinkage(GlobalLinkage, P) || parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, &isLet, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, State, M) || + nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, + &isLet, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, State, M) || P.parseToken(tok::at_sign, diag::expected_sil_value_name) || P.parseIdentifier(GlobalName, NameLoc, diag::expected_sil_value_name) || P.parseToken(tok::colon, diag::expected_sil_type)) @@ -5973,7 +5971,7 @@ bool SILParserState::parseSILProperty(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, SP, M)) + nullptr, nullptr, nullptr, SP, M)) return true; ValueDecl *VD; @@ -6043,7 +6041,8 @@ bool SILParserState::parseSILVTable(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, VTableState, M)) + nullptr, nullptr, nullptr, + VTableState, M)) return true; // Parse the class name. @@ -6579,7 +6578,8 @@ bool SILParserState::parseSILWitnessTable(Parser &P) { if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, WitnessState, M)) + nullptr, nullptr, nullptr, + WitnessState, M)) return true; Scope S(&P, ScopeKind::TopLevel); diff --git a/lib/SIL/Utils/Dominance.cpp b/lib/SIL/Utils/Dominance.cpp index 88e034ca64ca8..ad91ee6f3c547 100644 --- a/lib/SIL/Utils/Dominance.cpp +++ b/lib/SIL/Utils/Dominance.cpp @@ -119,7 +119,7 @@ void PostDominanceInfo::verify() const { // // Even though at the SIL level we have "one" return function, we can have // multiple exits provided by no-return functions. - auto *F = getRoots()[0]->getParent(); + auto *F = (*root_begin())->getParent(); PostDominanceInfo OtherDT(F); // And compare. diff --git a/lib/SIL/Utils/OptimizationRemark.cpp b/lib/SIL/Utils/OptimizationRemark.cpp index 00da367598e31..978527366bb05 100644 --- a/lib/SIL/Utils/OptimizationRemark.cpp +++ b/lib/SIL/Utils/OptimizationRemark.cpp @@ -152,6 +152,8 @@ static SourceLoc inferOptRemarkSearchForwards(SILInstruction &i) { for (auto &inst : llvm::make_range(std::next(i.getIterator()), i.getParent()->end())) { auto newLoc = inst.getLoc().getSourceLoc(); + if (auto inlinedLoc = inst.getDebugScope()->getOutermostInlineLocation()) + newLoc = inlinedLoc.getSourceLoc(); if (newLoc.isValid()) return newLoc; } @@ -167,7 +169,9 @@ static SourceLoc inferOptRemarkSearchBackwards(SILInstruction &i) { for (auto &inst : llvm::make_range(std::next(i.getReverseIterator()), i.getParent()->rend())) { auto loc = inst.getLoc(); - if (!bool(loc)) + if (auto inlinedLoc = inst.getDebugScope()->getOutermostInlineLocation()) + loc = inlinedLoc; + if (!loc.getSourceLoc().isValid()) continue; auto range = loc.getSourceRange(); @@ -178,55 +182,48 @@ static SourceLoc inferOptRemarkSearchBackwards(SILInstruction &i) { return SourceLoc(); } +static llvm::cl::opt IgnoreAlwaysInferForTesting( + "sil-opt-remark-ignore-always-infer", llvm::cl::Hidden, + llvm::cl::init(false), + llvm::cl::desc( + "Disables always infer source loc behavior for testing purposes")); + +// Attempt to infer a SourceLoc for \p i using heuristics specified by \p +// inferBehavior. +// +// NOTE: We distinguish in between situations where we always must infer +// (retain, release) and other situations where we are ok with original source +// locs if we are not inlined (alloc_ref, alloc_stack). SourceLoc swift::OptRemark::inferOptRemarkSourceLoc( SILInstruction &i, SourceLocInferenceBehavior inferBehavior) { - auto loc = i.getLoc().getSourceLoc(); - - // Do a quick check if we already have a valid loc. In such a case, just - // return. Otherwise, we try to infer using one of our heuristics below. - if (loc.isValid()) - return loc; - - // Otherwise, try to handle the individual behavior cases, returning loc at - // the end of each case (its invalid, so it will get ignored). If loc is not - // returned, we hit an assert at the end to make it easy to identify a case - // was missed. - switch (inferBehavior) { - case SourceLocInferenceBehavior::None: - return loc; - case SourceLocInferenceBehavior::ForwardScanOnly: { + // If we are only supposed to infer in inline contexts, see if we have a valid + // loc and if that loc is an inlined call site. + auto loc = i.getLoc(); + if (loc.getSourceLoc().isValid() && + !(bool(inferBehavior & SourceLocInferenceBehavior::AlwaysInfer) && + !IgnoreAlwaysInferForTesting) && + !(i.getDebugScope() && i.getDebugScope()->InlinedCallSite)) + return loc.getSourceLoc(); + + if (bool(inferBehavior & SourceLocInferenceBehavior::ForwardScan)) { SourceLoc newLoc = inferOptRemarkSearchForwards(i); if (newLoc.isValid()) return newLoc; - return loc; } - case SourceLocInferenceBehavior::BackwardScanOnly: { + + if (bool(inferBehavior & SourceLocInferenceBehavior::BackwardScan)) { SourceLoc newLoc = inferOptRemarkSearchBackwards(i); if (newLoc.isValid()) return newLoc; - return loc; } - case SourceLocInferenceBehavior::ForwardThenBackward: { + + if (bool(inferBehavior & SourceLocInferenceBehavior::ForwardScan2nd)) { SourceLoc newLoc = inferOptRemarkSearchForwards(i); if (newLoc.isValid()) return newLoc; - newLoc = inferOptRemarkSearchBackwards(i); - if (newLoc.isValid()) - return newLoc; - return loc; - } - case SourceLocInferenceBehavior::BackwardThenForward: { - SourceLoc newLoc = inferOptRemarkSearchBackwards(i); - if (newLoc.isValid()) - return newLoc; - newLoc = inferOptRemarkSearchForwards(i); - if (newLoc.isValid()) - return newLoc; - return loc; - } } - llvm_unreachable("Covered switch isn't covered?!"); + return SourceLoc(); } template diff --git a/lib/SIL/Utils/OwnershipUtils.cpp b/lib/SIL/Utils/OwnershipUtils.cpp index 8ece70a783b50..7cd18ae2376e1 100644 --- a/lib/SIL/Utils/OwnershipUtils.cpp +++ b/lib/SIL/Utils/OwnershipUtils.cpp @@ -12,6 +12,7 @@ #include "swift/SIL/OwnershipUtils.h" #include "swift/Basic/Defer.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/LinearLifetimeChecker.h" #include "swift/SIL/Projection.h" #include "swift/SIL/SILArgument.h" @@ -266,6 +267,48 @@ void BorrowingOperand::visitUserResultConsumingUses( } } +bool BorrowingOperand::getImplicitUses( + SmallVectorImpl &foundUses, + std::function *errorFunction) const { + if (!areAnyUserResultsBorrowIntroducers()) { + visitEndScopeInstructions([&](Operand *op) { foundUses.push_back(op); }); + return false; + } + + // Ok, we have an instruction that introduces a new borrow scope and its + // result is that borrow scope. In such a case, we need to not just add the + // end scope instructions of this scoped operand, but also look through any + // guaranteed phis and add their end_borrow to this list as well. + SmallVector worklist; + SmallPtrSet visitedValue; + worklist.push_back(*this); + visitedValue.insert(op); + bool foundError = false; + while (!worklist.empty()) { + auto scopedOperand = worklist.pop_back_val(); + scopedOperand.visitConsumingUsesOfBorrowIntroducingUserResults( + [&](Operand *op) { + if (auto subSub = BorrowingOperand::get(op)) { + if (!visitedValue.insert(op).second) { + if (errorFunction) { + (*errorFunction)(op); + } + foundError = true; + return; + } + + worklist.push_back(*subSub); + visitedValue.insert(subSub->op); + return; + } + + foundUses.push_back(op); + }); + } + + return foundError; +} + //===----------------------------------------------------------------------===// // Borrow Introducers //===----------------------------------------------------------------------===// @@ -459,6 +502,113 @@ bool BorrowedValue::visitInteriorPointerOperands( return true; } +//===----------------------------------------------------------------------===// +// InteriorPointerOperand +//===----------------------------------------------------------------------===// + +bool InteriorPointerOperand::getImplicitUses( + SmallVectorImpl &foundUses, + std::function *onError) { + SILValue projectedAddress = getProjectedAddress(); + SmallVector worklist(projectedAddress->getUses()); + + bool foundError = false; + + while (!worklist.empty()) { + auto *op = worklist.pop_back_val(); + + // Skip type dependent operands. + if (op->isTypeDependent()) + continue; + + // Before we do anything, add this operand to our implicit regular user + // list. + foundUses.push_back(op); + + // Then update the worklist with new things to find if we recognize this + // inst and then continue. If we fail, we emit an error at the bottom of the + // loop that we didn't recognize the user. + auto *user = op->getUser(); + + // First, eliminate "end point uses" that we just need to check liveness at + // and do not need to check transitive uses of. + if (isa(user) || isa(user) || + isIncidentalUse(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user)) { + continue; + } + + // Then handle users that we need to look at transitive uses of. + if (Projection::isAddressProjection(user) || + isa(user) || + isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user)) { + for (SILValue r : user->getResults()) { + llvm::copy(r->getUses(), std::back_inserter(worklist)); + } + continue; + } + + if (auto *builtin = dyn_cast(user)) { + if (auto kind = builtin->getBuiltinKind()) { + if (*kind == BuiltinValueKind::TSanInoutAccess) { + continue; + } + } + } + + // If we have a load_borrow, add it's end scope to the liveness requirement. + if (auto *lbi = dyn_cast(user)) { + transform(lbi->getEndBorrows(), std::back_inserter(foundUses), + [](EndBorrowInst *ebi) { return &ebi->getAllOperands()[0]; }); + continue; + } + + // TODO: Merge this into the full apply site code below. + if (auto *beginApply = dyn_cast(user)) { + // TODO: Just add this to implicit regular user list? + llvm::copy(beginApply->getTokenResult()->getUses(), + std::back_inserter(foundUses)); + continue; + } + + if (auto fas = FullApplySite::isa(user)) { + continue; + } + + if (auto *mdi = dyn_cast(user)) { + // If this is the base, just treat it as a liveness use. + if (op->get() == mdi->getBase()) { + continue; + } + + // If we are the value use, look through it. + llvm::copy(mdi->getValue()->getUses(), std::back_inserter(worklist)); + continue; + } + + // We were unable to recognize this user, so return true that we failed. + if (onError) { + (*onError)(op); + } + foundError = true; + } + + // We were able to recognize all of the uses of the address, so return false + // that we did not find any errors. + return foundError; +} + //===----------------------------------------------------------------------===// // Owned Value Introducers //===----------------------------------------------------------------------===// diff --git a/lib/SIL/Verifier/LinearLifetimeChecker.cpp b/lib/SIL/Verifier/LinearLifetimeChecker.cpp index ee5bdf839537a..ebc26a66c9adc 100644 --- a/lib/SIL/Verifier/LinearLifetimeChecker.cpp +++ b/lib/SIL/Verifier/LinearLifetimeChecker.cpp @@ -682,7 +682,6 @@ bool LinearLifetimeChecker::validateLifetime( bool LinearLifetimeChecker::usesNotContainedWithinLifetime( SILValue value, ArrayRef consumingUses, ArrayRef usesToTest) { - auto errorBehavior = ErrorBehaviorKind( ErrorBehaviorKind::ReturnFalse | ErrorBehaviorKind::StoreNonConsumingUsesOutsideLifetime); @@ -707,7 +706,13 @@ bool LinearLifetimeChecker::usesNotContainedWithinLifetime( assert(numFoundUses == uniqueUsers.size()); #endif - // Return true if we /did/ found an error and when emitting that error, we + // If we found any error except for uses outside of our lifetime, bail. + if (error.getFoundLeak() || error.getFoundOverConsume() || + error.getFoundUseAfterFree()) + return false; + + // Return true if we /did/ find an error and when emitting that error, we // found /all/ uses we were looking for. - return error.getFoundError() && numFoundUses == usesToTest.size(); + return error.getFoundUseOutsideOfLifetime() && + numFoundUses == usesToTest.size(); } diff --git a/lib/SIL/Verifier/SILOwnershipVerifier.cpp b/lib/SIL/Verifier/SILOwnershipVerifier.cpp index f829349d73051..8490e003d920a 100644 --- a/lib/SIL/Verifier/SILOwnershipVerifier.cpp +++ b/lib/SIL/Verifier/SILOwnershipVerifier.cpp @@ -99,14 +99,6 @@ class SILValueOwnershipChecker { /// is successful. SmallVector regularUsers; - /// The list of implicit non lifetime ending users that we found. This - /// consists of instructions like end_borrow that end a scoped lifetime. We - /// must treat those as regular uses and ensure that our value is not - /// destroyed while that sub-scope is valid. - /// - /// TODO: Rename to SubBorrowScopeUsers? - SmallVector implicitRegularUsers; - /// The set of blocks that we have visited. SmallPtrSetImpl &visitedBlocks; @@ -133,13 +125,10 @@ class SILValueOwnershipChecker { bool isCompatibleDefUse(Operand *op, ValueOwnershipKind ownershipKind); bool gatherUsers(SmallVectorImpl &lifetimeEndingUsers, - SmallVectorImpl ®ularUsers, - SmallVectorImpl &implicitRegularUsers); + SmallVectorImpl ®ularUsers); - bool - gatherNonGuaranteedUsers(SmallVectorImpl &lifetimeEndingUsers, - SmallVectorImpl ®ularUsers, - SmallVectorImpl &implicitRegularUsers); + bool gatherNonGuaranteedUsers(SmallVectorImpl &lifetimeEndingUsers, + SmallVectorImpl ®ularUsers); bool checkValueWithoutLifetimeEndingUses(); @@ -152,12 +141,6 @@ class SILValueOwnershipChecker { bool isSubobjectProjectionWithLifetimeEndingUses( SILValue value, const SmallVectorImpl &lifetimeEndingUsers) const; - bool discoverBorrowOperandImplicitRegularUsers( - const BorrowingOperand &initialScopedOperand, - SmallVectorImpl &implicitRegularUsers, bool isGuaranteed); - bool discoverInteriorPointerOperandImplicitRegularUsers( - const InteriorPointerOperand &interiorPointerOperand, - SmallVectorImpl &implicitRegularUsers); }; } // namespace swift @@ -175,7 +158,6 @@ bool SILValueOwnershipChecker::check() { llvm::copy(lifetimeEndingUsers, std::back_inserter(allLifetimeEndingUsers)); SmallVector allRegularUsers; llvm::copy(regularUsers, std::back_inserter(allRegularUsers)); - llvm::copy(implicitRegularUsers, std::back_inserter(allRegularUsers)); LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); auto linearLifetimeResult = checker.checkValue(value, allLifetimeEndingUsers, @@ -227,165 +209,9 @@ bool SILValueOwnershipChecker::isCompatibleDefUse( return false; } -/// Returns true if an error was found. -bool SILValueOwnershipChecker::discoverBorrowOperandImplicitRegularUsers( - const BorrowingOperand &initialScopedOperand, - SmallVectorImpl &implicitRegularUsers, bool isGuaranteed) { - if (!initialScopedOperand.areAnyUserResultsBorrowIntroducers()) { - initialScopedOperand.visitEndScopeInstructions( - [&](Operand *op) { implicitRegularUsers.push_back(op); }); - return false; - } - - // Ok, we have an instruction that introduces a new borrow scope and its - // result is that borrow scope. In such a case, we need to not just add the - // end scope instructions of this scoped operand, but also look through any - // guaranteed phis and add their end_borrow to this list as well. - SmallVector worklist; - SmallPtrSet visitedValue; - worklist.push_back(initialScopedOperand); - visitedValue.insert(initialScopedOperand.op); - bool foundError = false; - while (!worklist.empty()) { - auto scopedOperand = worklist.pop_back_val(); - scopedOperand.visitConsumingUsesOfBorrowIntroducingUserResults( - [&](Operand *op) { - if (auto subSub = BorrowingOperand::get(op)) { - if (!visitedValue.insert(op).second) { - errorBuilder.handleMalformedSIL([&] { - llvm::errs() - << "Implicit Regular User Guaranteed Phi Cycle!\n" - << "User: " << *op->getUser() - << "Initial: " << initialScopedOperand << "\n"; - }); - foundError = true; - return; - } - - worklist.push_back(*subSub); - visitedValue.insert(subSub->op); - return; - } - - implicitRegularUsers.push_back(op); - }); - } - - return foundError; -} - -bool SILValueOwnershipChecker:: - discoverInteriorPointerOperandImplicitRegularUsers( - const InteriorPointerOperand &interiorPointerOperand, - SmallVectorImpl &implicitRegularUsers) { - SILValue projectedAddress = interiorPointerOperand.getProjectedAddress(); - SmallVector worklist(projectedAddress->getUses()); - - bool foundError = false; - - while (!worklist.empty()) { - auto *op = worklist.pop_back_val(); - - // Skip type dependent operands. - if (op->isTypeDependent()) - continue; - - // Before we do anything, add this operand to our implicit regular user - // list. - implicitRegularUsers.push_back(op); - - // Then update the worklist with new things to find if we recognize this - // inst and then continue. If we fail, we emit an error at the bottom of the - // loop that we didn't recognize the user. - auto *user = op->getUser(); - - // First, eliminate "end point uses" that we just need to check liveness at - // and do not need to check transitive uses of. - if (isa(user) || isa(user) || - isIncidentalUse(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user)) { - continue; - } - - // Then handle users that we need to look at transitive uses of. - if (Projection::isAddressProjection(user) || - isa(user) || - isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user)) { - for (SILValue r : user->getResults()) { - llvm::copy(r->getUses(), std::back_inserter(worklist)); - } - continue; - } - - if (auto *builtin = dyn_cast(user)) { - if (auto kind = builtin->getBuiltinKind()) { - if (*kind == BuiltinValueKind::TSanInoutAccess) { - continue; - } - } - } - - // If we have a load_borrow, add it's end scope to the liveness requirement. - if (auto *lbi = dyn_cast(user)) { - transform(lbi->getEndBorrows(), std::back_inserter(implicitRegularUsers), - [](EndBorrowInst *ebi) { return &ebi->getAllOperands()[0]; }); - continue; - } - - // TODO: Merge this into the full apply site code below. - if (auto *beginApply = dyn_cast(user)) { - // TODO: Just add this to implicit regular user list? - llvm::copy(beginApply->getTokenResult()->getUses(), - std::back_inserter(implicitRegularUsers)); - continue; - } - - if (auto fas = FullApplySite::isa(user)) { - continue; - } - - if (auto *mdi = dyn_cast(user)) { - // If this is the base, just treat it as a liveness use. - if (op->get() == mdi->getBase()) { - continue; - } - - // If we are the value use, look through it. - llvm::copy(mdi->getValue()->getUses(), std::back_inserter(worklist)); - continue; - } - - // We were unable to recognize this user, so return true that we failed. - errorBuilder.handleMalformedSIL([&] { - llvm::errs() - << "Could not recognize address user of interior pointer operand!\n" - << "Interior Pointer Operand: " - << *interiorPointerOperand.operand->getUser() - << "Address User: " << *op->getUser(); - }); - foundError = true; - } - - // We were able to recognize all of the uses of the address, so return false - // that we did not find any errors. - return foundError; -} - bool SILValueOwnershipChecker::gatherNonGuaranteedUsers( SmallVectorImpl &lifetimeEndingUsers, - SmallVectorImpl &nonLifetimeEndingUsers, - SmallVectorImpl &implicitRegularUsers) { + SmallVectorImpl &nonLifetimeEndingUsers) { bool foundError = false; auto ownershipKind = value.getOwnershipKind(); @@ -442,8 +268,15 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers( // initial end scope instructions without any further work. // // Maybe: Is borrow scope non-local? - foundError |= discoverBorrowOperandImplicitRegularUsers( - *initialScopedOperand, implicitRegularUsers, false); + std::function error = [&](Operand *op) { + errorBuilder.handleMalformedSIL([&] { + llvm::errs() << "Implicit Regular User Guaranteed Phi Cycle!\n" + << "User: " << *op->getUser() + << "Initial: " << *initialScopedOperand << "\n"; + }); + }; + foundError |= + initialScopedOperand->getImplicitUses(nonLifetimeEndingUsers, &error); } return foundError; @@ -451,16 +284,15 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers( bool SILValueOwnershipChecker::gatherUsers( SmallVectorImpl &lifetimeEndingUsers, - SmallVectorImpl &nonLifetimeEndingUsers, - SmallVectorImpl &implicitRegularUsers) { + SmallVectorImpl &nonLifetimeEndingUsers) { // See if Value is guaranteed. If we are guaranteed and not forwarding, then // we need to look through subobject uses for more uses. Otherwise, if we are // forwarding, we do not create any lifetime ending users/non lifetime ending // users since we verify against our base. if (value.getOwnershipKind() != ValueOwnershipKind::Guaranteed) { - return !gatherNonGuaranteedUsers( - lifetimeEndingUsers, nonLifetimeEndingUsers, implicitRegularUsers); + return !gatherNonGuaranteedUsers(lifetimeEndingUsers, + nonLifetimeEndingUsers); } // Ok, we have a value with guarantee ownership. Before we continue, check if @@ -533,16 +365,32 @@ bool SILValueOwnershipChecker::gatherUsers( if (auto scopedOperand = BorrowingOperand::get(op)) { assert(!scopedOperand->consumesGuaranteedValues()); - foundError |= discoverBorrowOperandImplicitRegularUsers( - *scopedOperand, implicitRegularUsers, true); + std::function onError = [&](Operand *op) { + errorBuilder.handleMalformedSIL([&] { + llvm::errs() << "Implicit Regular User Guaranteed Phi Cycle!\n" + << "User: " << *op->getUser() + << "Initial: " << *scopedOperand << "\n"; + }); + }; + foundError |= + scopedOperand->getImplicitUses(nonLifetimeEndingUsers, &onError); } // Next see if our use is an interior pointer operand. If we have an // interior pointer, we need to add all of its address uses as "implicit // regular users" of our consumed value. if (auto interiorPointerOperand = InteriorPointerOperand::get(op)) { - foundError |= discoverInteriorPointerOperandImplicitRegularUsers( - *interiorPointerOperand, implicitRegularUsers); + std::function onError = [&](Operand *op) { + errorBuilder.handleMalformedSIL([&] { + llvm::errs() << "Could not recognize address user of interior " + "pointer operand!\n" + << "Interior Pointer Operand: " + << interiorPointerOperand->operand->getUser() + << "Address User: " << *op->getUser(); + }); + }; + foundError |= interiorPointerOperand->getImplicitUses( + nonLifetimeEndingUsers, &onError); } // Finally add the op to the non lifetime ending user list. @@ -759,7 +607,7 @@ bool SILValueOwnershipChecker::checkUses() { // 1. Verify that none of the uses are in the same block. This would be an // overconsume so in this case we assert. // 2. Verify that the uses are compatible with our ownership convention. - if (!gatherUsers(lifetimeEndingUsers, regularUsers, implicitRegularUsers)) { + if (!gatherUsers(lifetimeEndingUsers, regularUsers)) { // Silently return false if this fails. // // If the user pass in a ErrorBehaviorKind that will assert, we diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 83912db313ffb..297019bbf66d4 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -4730,7 +4730,7 @@ class SILVerifier : public SILVerifierBase { } void checkLinearFunctionExtractInst(LinearFunctionExtractInst *lfei) { - auto fnTy = lfei->getFunctionOperand()->getType().getAs(); + auto fnTy = lfei->getOperand()->getType().getAs(); require(fnTy, "The function operand must have a function type"); require(fnTy->getDifferentiabilityKind() == DifferentiabilityKind::Linear, "The function operand must be a '@differentiable(linear)' " diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index cd36b343f0e58..1eeb2d26095e4 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -415,6 +415,7 @@ SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess, SILFunctionType::ExtInfoBuilder(SILFunctionTypeRepresentation::Thin, /*pseudogeneric*/ false, /*non-escaping*/ false, + /*async*/ false, DifferentiabilityKind::NonDifferentiable, /*clangFunctionType*/ nullptr) .build(); @@ -675,17 +676,56 @@ bool SILGenModule::hasFunction(SILDeclRef constant) { void SILGenModule::visitFuncDecl(FuncDecl *fd) { emitFunction(fd); } -static void emitDelayedFunction(SILGenModule &SGM, - SILDeclRef constant, - SILFunction *f) { +void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { + + if (constant.isForeignToNativeThunk()) { + f->setThunk(IsThunk); + if (constant.asForeign().isClangGenerated()) + f->setSerialized(IsSerializable); + + auto loc = constant.getAsRegularLocation(); + loc.markAutoGenerated(); + auto *dc = loc.getAsDeclContext(); + assert(dc); + + preEmitFunction(constant, f, loc); + PrettyStackTraceSILFunction X("silgen emitForeignToNativeThunk", f); + SILGenFunction(*this, *f, dc).emitForeignToNativeThunk(constant); + postEmitFunction(constant, f); + return; + } + + if (constant.isNativeToForeignThunk()) { + auto loc = constant.getAsRegularLocation(); + loc.markAutoGenerated(); + auto *dc = loc.getAsDeclContext(); + assert(dc); + + preEmitFunction(constant, f, loc); + PrettyStackTraceSILFunction X("silgen emitNativeToForeignThunk", f); + f->setBare(IsBare); + f->setThunk(IsThunk); + SILGenFunction(*this, *f, dc).emitNativeToForeignThunk(constant); + postEmitFunction(constant, f); + return; + } + switch (constant.kind) { case SILDeclRef::Kind::Func: { + if (auto *ce = constant.getAbstractClosureExpr()) { + preEmitFunction(constant, f, ce); + PrettyStackTraceSILFunction X("silgen closureexpr", f); + SILGenFunction(*this, *f, ce).emitClosure(ce); + postEmitFunction(constant, f); + break; + } + auto *fd = cast(constant.getDecl()); - SGM.preEmitFunction(constant, fd, f, fd); + preEmitFunction(constant, f, fd); PrettyStackTraceSILFunction X("silgen emitFunction", f); - SILGenFunction(SGM, *f, fd).emitFunction(fd); - SGM.postEmitFunction(constant, f); + SILGenFunction(*this, *f, fd).emitFunction(fd); + postEmitFunction(constant, f); break; } @@ -695,16 +735,16 @@ static void emitDelayedFunction(SILGenModule &SGM, if (decl->getDeclContext()->getSelfClassDecl() && (decl->isDesignatedInit() || decl->isObjC())) { - SGM.preEmitFunction(constant, decl, f, decl); + preEmitFunction(constant, f, decl); PrettyStackTraceSILFunction X("silgen emitConstructor", f); - SILGenFunction(SGM, *f, decl).emitClassConstructorAllocator(decl); - SGM.postEmitFunction(constant, f); + SILGenFunction(*this, *f, decl).emitClassConstructorAllocator(decl); + postEmitFunction(constant, f); } else { - SGM.preEmitFunction(constant, decl, f, decl); + preEmitFunction(constant, f, decl); PrettyStackTraceSILFunction X("silgen emitConstructor", f); f->createProfiler(decl, constant, ForDefinition); - SILGenFunction(SGM, *f, decl).emitValueConstructor(decl); - SGM.postEmitFunction(constant, f); + SILGenFunction(*this, *f, decl).emitValueConstructor(decl); + postEmitFunction(constant, f); } break; } @@ -713,11 +753,11 @@ static void emitDelayedFunction(SILGenModule &SGM, auto *decl = cast(constant.getDecl()); assert(decl->getDeclContext()->getSelfClassDecl()); - SGM.preEmitFunction(constant, decl, f, decl); + preEmitFunction(constant, f, decl); PrettyStackTraceSILFunction X("silgen constructor initializer", f); f->createProfiler(decl, constant, ForDefinition); - SILGenFunction(SGM, *f, decl).emitClassConstructorInitializer(decl); - SGM.postEmitFunction(constant, f); + SILGenFunction(*this, *f, decl).emitClassConstructorInitializer(decl); + postEmitFunction(constant, f); break; } @@ -730,22 +770,22 @@ static void emitDelayedFunction(SILGenModule &SGM, case DefaultArgumentKind::Normal: { auto arg = param->getTypeCheckedDefaultExpr(); auto loc = RegularLocation::getAutoGeneratedLocation(arg); - SGM.preEmitFunction(constant, arg, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitDefaultArgGenerator ", f); - SILGenFunction SGF(SGM, *f, initDC); + SILGenFunction SGF(*this, *f, initDC); SGF.emitGeneratorFunction(constant, arg); - SGM.postEmitFunction(constant, f); + postEmitFunction(constant, f); break; } case DefaultArgumentKind::StoredProperty: { auto arg = param->getStoredProperty(); auto loc = RegularLocation::getAutoGeneratedLocation(arg); - SGM.preEmitFunction(constant, arg, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitDefaultArgGenerator ", f); - SILGenFunction SGF(SGM, *f, initDC); + SILGenFunction SGF(*this, *f, initDC); SGF.emitGeneratorFunction(constant, arg); - SGM.postEmitFunction(constant, f); + postEmitFunction(constant, f); break; } @@ -779,23 +819,23 @@ static void emitDelayedFunction(SILGenModule &SGM, } auto loc = RegularLocation::getAutoGeneratedLocation(init); - SGM.preEmitFunction(constant, init, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitStoredPropertyInitialization", f); f->createProfiler(init, constant, ForDefinition); - SILGenFunction SGF(SGM, *f, initDC); + SILGenFunction SGF(*this, *f, initDC); // If this is a stored property initializer inside a type at global scope, // it may close over a global variable. If we're emitting top-level code, // then emit a "mark_function_escape" that lists the captured global // variables so that definite initialization can reason about this // escape point. - if (!var->getDeclContext()->isLocalContext() && - SGM.TopLevelSGF && SGM.TopLevelSGF->B.hasValidInsertionPoint()) { - SGM.emitMarkFunctionEscapeForTopLevelCodeGlobals(var, captureInfo); + if (!var->getDeclContext()->isLocalContext() && TopLevelSGF && + TopLevelSGF->B.hasValidInsertionPoint()) { + emitMarkFunctionEscapeForTopLevelCodeGlobals(var, captureInfo); } SGF.emitGeneratorFunction(constant, init, /*EmitProfilerIncrement=*/true); - SGM.postEmitFunction(constant, f); + postEmitFunction(constant, f); break; } @@ -803,7 +843,7 @@ static void emitDelayedFunction(SILGenModule &SGM, auto *var = cast(constant.getDecl()); auto loc = RegularLocation::getAutoGeneratedLocation(var); - SGM.preEmitFunction(constant, var, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X( "silgen emitPropertyWrapperBackingInitializer", f); auto wrapperInfo = var->getPropertyWrapperBackingPropertyInfo(); @@ -811,26 +851,26 @@ static void emitDelayedFunction(SILGenModule &SGM, f->createProfiler(wrapperInfo.initializeFromOriginal, constant, ForDefinition); auto varDC = var->getInnermostDeclContext(); - SILGenFunction SGF(SGM, *f, varDC); + SILGenFunction SGF(*this, *f, varDC); SGF.emitGeneratorFunction(constant, wrapperInfo.initializeFromOriginal); - SGM.postEmitFunction(constant, f); + postEmitFunction(constant, f); break; } case SILDeclRef::Kind::GlobalAccessor: { auto *global = cast(constant.getDecl()); - auto found = SGM.delayedGlobals.find(global); - assert(found != SGM.delayedGlobals.end()); + auto found = delayedGlobals.find(global); + assert(found != delayedGlobals.end()); auto *onceToken = found->second.first; auto *onceFunc = found->second.second; auto loc = RegularLocation::getAutoGeneratedLocation(global); - SGM.preEmitFunction(constant, global, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitGlobalAccessor", f); - SILGenFunction(SGM, *f, global->getDeclContext()) + SILGenFunction(*this, *f, global->getDeclContext()) .emitGlobalAccessor(global, onceToken, onceFunc); - SGM.postEmitFunction(constant, f); + postEmitFunction(constant, f); break; } @@ -838,19 +878,63 @@ static void emitDelayedFunction(SILGenModule &SGM, auto *decl = cast(constant.getDecl()); auto loc = RegularLocation::getAutoGeneratedLocation(decl); - SGM.preEmitFunction(constant, decl, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen enum constructor", f); - SILGenFunction(SGM, *f, decl->getDeclContext()).emitEnumConstructor(decl); - SGM.postEmitFunction(constant, f); + SILGenFunction(*this, *f, decl->getDeclContext()).emitEnumConstructor(decl); + postEmitFunction(constant, f); break; } - case SILDeclRef::Kind::Destroyer: - case SILDeclRef::Kind::Deallocator: - case SILDeclRef::Kind::IVarInitializer: - case SILDeclRef::Kind::IVarDestroyer: - llvm_unreachable("Cannot emit as a delayed function"); - break; + case SILDeclRef::Kind::Destroyer: { + auto *dd = cast(constant.getDecl()); + preEmitFunction(constant, f, dd); + PrettyStackTraceSILFunction X("silgen emitDestroyingDestructor", f); + SILGenFunction(*this, *f, dd).emitDestroyingDestructor(dd); + postEmitFunction(constant, f); + return; + } + + case SILDeclRef::Kind::Deallocator: { + auto *dd = cast(constant.getDecl()); + auto *cd = cast(dd->getDeclContext()); + + if (usesObjCAllocator(cd)) { + preEmitFunction(constant, f, dd); + PrettyStackTraceSILFunction X("silgen emitDestructor -dealloc", f); + f->createProfiler(dd, constant, ForDefinition); + SILGenFunction(*this, *f, dd).emitObjCDestructor(constant); + postEmitFunction(constant, f); + return; + } + + auto loc = RegularLocation::getAutoGeneratedLocation(dd); + preEmitFunction(constant, f, loc); + PrettyStackTraceSILFunction X("silgen emitDeallocatingDestructor", f); + f->createProfiler(dd, constant, ForDefinition); + SILGenFunction(*this, *f, dd).emitDeallocatingDestructor(dd); + postEmitFunction(constant, f); + return; + } + + case SILDeclRef::Kind::IVarInitializer: { + auto *cd = cast(constant.getDecl()); + auto loc = RegularLocation::getAutoGeneratedLocation(cd); + preEmitFunction(constant, f, loc); + PrettyStackTraceSILFunction X("silgen emitDestructor ivar initializer", f); + SILGenFunction(*this, *f, cd).emitIVarInitializer(constant); + postEmitFunction(constant, f); + return; + } + + case SILDeclRef::Kind::IVarDestroyer: { + auto *cd = cast(constant.getDecl()); + auto loc = RegularLocation::getAutoGeneratedLocation(cd); + preEmitFunction(constant, f, loc); + PrettyStackTraceSILFunction X("silgen emitDestructor ivar destroyer", f); + SILGenFunction(*this, *f, cd).emitIVarDestroyer(constant); + postEmitFunction(constant, f); + return; + } } } @@ -888,22 +972,11 @@ static void emitOrDelayFunction(SILGenModule &SGM, return; } - emitDelayedFunction(SGM, constant, f); + SGM.emitFunctionDefinition(constant, f); } -void SILGenModule::preEmitFunction(SILDeclRef constant, - llvm::PointerUnion astNode, - SILFunction *F, +void SILGenModule::preEmitFunction(SILDeclRef constant, SILFunction *F, SILLocation Loc) { - // By default, use the astNode to create the location. - if (Loc.isNull()) { - if (auto *decl = astNode.get()) - Loc = RegularLocation(decl); - else - Loc = RegularLocation(astNode.get()); - } - assert(F->empty() && "already emitted function?!"); if (F->getLoweredFunctionType()->isPolymorphic()) @@ -917,14 +990,12 @@ void SILGenModule::preEmitFunction(SILDeclRef constant, llvm::dbgs() << " : "; F->getLoweredType().print(llvm::dbgs()); llvm::dbgs() << '\n'; - if (astNode) { - if (auto *decl = astNode.dyn_cast()) { - decl->dump(llvm::dbgs()); - } else { - astNode.get()->dump(llvm::dbgs()); - llvm::dbgs() << "\n"; - } + if (auto *decl = Loc.getAsASTNode()) { + decl->dump(llvm::dbgs()); llvm::dbgs() << '\n'; + } else if (auto *expr = Loc.getAsASTNode()) { + expr->dump(llvm::dbgs()); + llvm::dbgs() << "\n"; }); } @@ -1177,10 +1248,8 @@ SILFunction *SILGenModule::emitClosure(AbstractClosureExpr *ce) { // initializer of the containing type. if (!f->isExternalDeclaration()) return f; - preEmitFunction(constant, ce, f, ce); - PrettyStackTraceSILFunction X("silgen closureexpr", f); - SILGenFunction(*this, *f, ce).emitClosure(ce); - postEmitFunction(constant, f); + + emitFunctionDefinition(constant, f); return f; } @@ -1231,12 +1300,7 @@ void SILGenModule::emitObjCAllocatorDestructor(ClassDecl *cd, // Destructors are a necessary part of class metadata, so can't be delayed. if (dd->hasBody()) { SILDeclRef dealloc(dd, SILDeclRef::Kind::Deallocator); - SILFunction *f = getFunction(dealloc, ForDefinition); - preEmitFunction(dealloc, dd, f, dd); - PrettyStackTraceSILFunction X("silgen emitDestructor -dealloc", f); - f->createProfiler(dd, dealloc, ForDefinition); - SILGenFunction(*this, *f, dd).emitObjCDestructor(dealloc); - postEmitFunction(dealloc, f); + emitFunctionDefinition(dealloc, getFunction(dealloc, ForDefinition)); } // Emit the Objective-C -dealloc entry point if it has @@ -1248,24 +1312,16 @@ void SILGenModule::emitObjCAllocatorDestructor(ClassDecl *cd, if (requiresIVarInitialization(*this, cd)) { auto ivarInitializer = SILDeclRef(cd, SILDeclRef::Kind::IVarInitializer) .asForeign(); - SILFunction *f = getFunction(ivarInitializer, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(dd); - preEmitFunction(ivarInitializer, dd, f, loc); - PrettyStackTraceSILFunction X("silgen emitDestructor ivar initializer", f); - SILGenFunction(*this, *f, cd).emitIVarInitializer(ivarInitializer); - postEmitFunction(ivarInitializer, f); + emitFunctionDefinition(ivarInitializer, + getFunction(ivarInitializer, ForDefinition)); } // Emit the ivar destroyer, if needed. if (hasNonTrivialIVars(cd)) { auto ivarDestroyer = SILDeclRef(cd, SILDeclRef::Kind::IVarDestroyer) .asForeign(); - SILFunction *f = getFunction(ivarDestroyer, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(dd); - preEmitFunction(ivarDestroyer, dd, f, loc); - PrettyStackTraceSILFunction X("silgen emitDestructor ivar destroyer", f); - SILGenFunction(*this, *f, cd).emitIVarDestroyer(ivarDestroyer); - postEmitFunction(ivarDestroyer, f); + emitFunctionDefinition(ivarDestroyer, + getFunction(ivarDestroyer, ForDefinition)); } } @@ -1275,12 +1331,8 @@ void SILGenModule::emitDestructor(ClassDecl *cd, DestructorDecl *dd) { // Emit the ivar destroyer, if needed. if (requiresIVarDestroyer(cd)) { SILDeclRef ivarDestroyer(cd, SILDeclRef::Kind::IVarDestroyer); - SILFunction *f = getFunction(ivarDestroyer, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(dd); - preEmitFunction(ivarDestroyer, dd, f, loc); - PrettyStackTraceSILFunction X("silgen emitDestructor ivar destroyer", f); - SILGenFunction(*this, *f, dd).emitIVarDestroyer(ivarDestroyer); - postEmitFunction(ivarDestroyer, f); + emitFunctionDefinition(ivarDestroyer, + getFunction(ivarDestroyer, ForDefinition)); } // If the class would use the Objective-C allocator, only emit -dealloc. @@ -1293,24 +1345,14 @@ void SILGenModule::emitDestructor(ClassDecl *cd, DestructorDecl *dd) { // Destructors are a necessary part of class metadata, so can't be delayed. if (dd->hasBody()) { SILDeclRef destroyer(dd, SILDeclRef::Kind::Destroyer); - SILFunction *f = getFunction(destroyer, ForDefinition); - RegularLocation loc(dd); - preEmitFunction(destroyer, dd, f, loc); - PrettyStackTraceSILFunction X("silgen emitDestroyingDestructor", f); - SILGenFunction(*this, *f, dd).emitDestroyingDestructor(dd); - postEmitFunction(destroyer, f); + emitFunctionDefinition(destroyer, getFunction(destroyer, ForDefinition)); } // Emit the deallocating destructor. { SILDeclRef deallocator(dd, SILDeclRef::Kind::Deallocator); - SILFunction *f = getFunction(deallocator, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(dd); - preEmitFunction(deallocator, dd, f, loc); - PrettyStackTraceSILFunction X("silgen emitDeallocatingDestructor", f); - f->createProfiler(dd, deallocator, ForDefinition); - SILGenFunction(*this, *f, dd).emitDeallocatingDestructor(dd); - postEmitFunction(deallocator, f); + emitFunctionDefinition(deallocator, + getFunction(deallocator, ForDefinition)); } } @@ -1357,7 +1399,19 @@ SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName, cast(getBuiltinValueDecl(C, C.getIdentifier("once"))); auto blockParam = onceBuiltin->getParameters()->get(1); auto *type = blockParam->getType()->castTo(); - Type initType = FunctionType::get({}, TupleType::getEmpty(C), + SmallVector params; + // wasm: Lazy global init is used with swift_once which passes a context + // pointer parameter. If lazy global init doesn't take a context argument, + // caller and callee signatures are mismatched and it causes runtime + // exception on WebAssembly runtime. So we need to add dummy argument + // to consume the context pointer. + // See also: emitLazyGlobalInitializer + if (C.LangOpts.Target.isOSBinFormatWasm()) { + auto dummyParam = AnyFunctionType::Param(C.getUnsafeRawPointerDecl()->getDeclaredInterfaceType() + ->getCanonicalType()); + params.push_back(dummyParam); + } + Type initType = FunctionType::get(params, TupleType::getEmpty(C), type->getExtInfo()); auto initSILType = cast( Types.getLoweredRValueType(TypeExpansionContext::minimal(), initType)); @@ -1366,6 +1420,7 @@ SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName, auto *f = builder.createFunction( SILLinkage::Private, funcName, initSILType, nullptr, SILLocation(binding), IsNotBare, IsNotTransparent, IsNotSerialized, IsNotDynamic); + f->setSpecialPurpose(SILFunction::Purpose::GlobalInitOnceFunction); f->setDebugScope(new (M) SILDebugScope(RegularLocation(binding), f)); auto dc = binding->getDeclContext(); SILGenFunction(*this, *f, dc).emitLazyGlobalInitializer(binding, pbdEntry); @@ -1402,14 +1457,7 @@ void SILGenModule::emitObjCMethodThunk(FuncDecl *method) { return; // ObjC entry points are always externally usable, so can't be delay-emitted. - - SILFunction *f = getFunction(thunk, ForDefinition); - preEmitFunction(thunk, method, f, method); - PrettyStackTraceSILFunction X("silgen emitObjCMethodThunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, method).emitNativeToForeignThunk(thunk); - postEmitFunction(thunk, f); + emitNativeToForeignThunk(thunk); } void SILGenModule::emitObjCPropertyMethodThunks(AbstractStorageDecl *prop) { @@ -1425,18 +1473,9 @@ void SILGenModule::emitObjCPropertyMethodThunks(AbstractStorageDecl *prop) { if (hasFunction(getterRef)) return; - auto thunkBodyLoc = RegularLocation::getAutoGeneratedLocation(prop); // ObjC entry points are always externally usable, so emitting can't be // delayed. - { - SILFunction *f = getFunction(getterRef, ForDefinition); - preEmitFunction(getterRef, prop, f, thunkBodyLoc); - PrettyStackTraceSILFunction X("silgen objc property getter thunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, getter).emitNativeToForeignThunk(getterRef); - postEmitFunction(getterRef, f); - } + emitNativeToForeignThunk(getterRef); if (!prop->isSettable(prop->getDeclContext())) return; @@ -1444,14 +1483,7 @@ void SILGenModule::emitObjCPropertyMethodThunks(AbstractStorageDecl *prop) { // FIXME: Add proper location. auto *setter = prop->getOpaqueAccessor(AccessorKind::Set); auto setterRef = SILDeclRef(setter, SILDeclRef::Kind::Func).asForeign(); - - SILFunction *f = getFunction(setterRef, ForDefinition); - preEmitFunction(setterRef, prop, f, thunkBodyLoc); - PrettyStackTraceSILFunction X("silgen objc property setter thunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, setter).emitNativeToForeignThunk(setterRef); - postEmitFunction(setterRef, f); + emitNativeToForeignThunk(setterRef); } void SILGenModule::emitObjCConstructorThunk(ConstructorDecl *constructor) { @@ -1463,15 +1495,7 @@ void SILGenModule::emitObjCConstructorThunk(ConstructorDecl *constructor) { return; // ObjC entry points are always externally usable, so emitting can't be // delayed. - - SILFunction *f = getFunction(thunk, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(constructor); - preEmitFunction(thunk, constructor, f, loc); - PrettyStackTraceSILFunction X("silgen objc constructor thunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, constructor).emitNativeToForeignThunk(thunk); - postEmitFunction(thunk, f); + emitNativeToForeignThunk(thunk); } void SILGenModule::emitObjCDestructorThunk(DestructorDecl *destructor) { @@ -1481,14 +1505,8 @@ void SILGenModule::emitObjCDestructorThunk(DestructorDecl *destructor) { // Don't emit the thunk if it already exists. if (hasFunction(thunk)) return; - SILFunction *f = getFunction(thunk, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(destructor); - preEmitFunction(thunk, destructor, f, loc); - PrettyStackTraceSILFunction X("silgen objc destructor thunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, destructor).emitNativeToForeignThunk(thunk); - postEmitFunction(thunk, f); + + emitNativeToForeignThunk(thunk); } void SILGenModule::visitPatternBindingDecl(PatternBindingDecl *pd) { @@ -1887,6 +1905,12 @@ class SILGenModuleRAII { SGM.visit(D); } + for (Decl *D : sf->getHoistedDecls()) { + FrontendStatsTracer StatsTracer(SGM.getASTContext().Stats, + "SILgen-decl", D); + SGM.visit(D); + } + for (TypeDecl *TD : sf->LocalTypeDecls) { FrontendStatsTracer StatsTracer(SGM.getASTContext().Stats, "SILgen-tydecl", TD); @@ -1908,8 +1932,8 @@ class SILGenModuleRAII { || !SGM.pendingConformances.empty()) { while (!SGM.forcedFunctions.empty()) { auto &front = SGM.forcedFunctions.front(); - emitDelayedFunction(SGM, front, - SGM.getEmittedFunction(front, ForDefinition)); + SGM.emitFunctionDefinition( + front, SGM.getEmittedFunction(front, ForDefinition)); SGM.forcedFunctions.pop_front(); } while (!SGM.pendingConformances.empty()) { diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index 5e69eed1488d2..76708975f8919 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -270,7 +270,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { /// curried functions, curried entry point Functions are also generated and /// added to the current SILModule. void emitFunction(FuncDecl *fd); - + + /// Emits the function definition for a given SILDeclRef. + void emitFunctionDefinition(SILDeclRef constant, SILFunction *f); + /// Generates code for the given closure expression and adds the /// SILFunction to the current SILModule under the name SILDeclRef(ce). SILFunction *emitClosure(AbstractClosureExpr *ce); @@ -302,11 +305,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { /// Emits a thunk from a Swift function to the native Swift convention. void emitNativeToForeignThunk(SILDeclRef thunk); - void preEmitFunction(SILDeclRef constant, - llvm::PointerUnion astNode, - SILFunction *F, - SILLocation L); + void preEmitFunction(SILDeclRef constant, SILFunction *F, SILLocation L); void postEmitFunction(SILDeclRef constant, SILFunction *F); /// Add a global variable to the SILModule. diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index bffecc2c2c187..22d3136ca776c 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -76,7 +76,6 @@ getIndirectApplyAbstractionPattern(SILGenFunction &SGF, // bridged to a foreign type. auto bridgedType = SGF.SGM.Types.getBridgedFunctionType(pattern, fnType, - fnType->getExtInfo(), Bridgeability::Full); pattern.rewriteType(CanGenericSignature(), bridgedType); return pattern; diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index 7eedc3b1975fa..0c1bb7d417a89 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -350,8 +350,7 @@ getParameterTypes(AnyFunctionType::CanParamArrayRef params) { static CanAnyFunctionType getBridgedBlockType(SILGenModule &SGM, CanAnyFunctionType blockType) { return SGM.Types.getBridgedFunctionType(AbstractionPattern(blockType), - blockType, blockType->getExtInfo(), - Bridgeability::Full); + blockType, Bridgeability::Full); } static void buildFuncToBlockInvokeBody(SILGenFunction &SGF, diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 0aef4de8034b3..0f4866879fb90 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -216,11 +216,9 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, .forwardInto(SGF, Loc, init.get()); ++elti; } else { -#ifndef NDEBUG - assert( - field->getType()->isEqual(field->getParentInitializer()->getType()) - && "Checked by sema"); -#endif + assert(field->getType()->getReferenceStorageReferent()->isEqual( + field->getParentInitializer()->getType()) && + "Initialization of field with mismatched type!"); // Cleanup after this initialization. FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); diff --git a/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp index 551b438f461f0..eaaea20ea981d 100644 --- a/lib/SILGen/SILGenGlobalVariable.cpp +++ b/lib/SILGen/SILGenGlobalVariable.cpp @@ -178,20 +178,8 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd, ->areAllParamsConcrete()); } - // Emit the lazy initialization token for the initialization expression. - auto counter = anonymousSymbolCounter++; - - // Pick one variable of the pattern. Usually it's only one variable, but it - // can also be something like: var (a, b) = ... - Pattern *pattern = pd->getPattern(pbdEntry); - VarDecl *varDecl = nullptr; - pattern->forEachVariable([&](VarDecl *D) { - varDecl = D; - }); - assert(varDecl); - Mangle::ASTMangler TokenMangler; - std::string onceTokenBuffer = TokenMangler.mangleGlobalInit(varDecl, counter, + std::string onceTokenBuffer = TokenMangler.mangleGlobalInit(pd, pbdEntry, false); auto onceTy = BuiltinIntegerType::getWordType(M.getASTContext()); @@ -207,7 +195,7 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd, // Emit the initialization code into a function. Mangle::ASTMangler FuncMangler; - std::string onceFuncBuffer = FuncMangler.mangleGlobalInit(varDecl, counter, + std::string onceFuncBuffer = FuncMangler.mangleGlobalInit(pd, pbdEntry, true); SILFunction *onceFunc = emitLazyGlobalInitializer(onceFuncBuffer, pd, @@ -224,6 +212,19 @@ void SILGenFunction::emitLazyGlobalInitializer(PatternBindingDecl *binding, unsigned pbdEntry) { MagicFunctionName = SILGenModule::getMagicFunctionName(binding->getDeclContext()); + ASTContext &C = getASTContext(); + // wasm: Lazy global init is used with swift_once which passes a context + // pointer parameter. If lazy global init doesn't take a context argument, + // caller and callee signatures are mismatched and it causes runtime + // exception on WebAssembly runtime. So we need to add dummy argument + // to consume the context pointer. + // See also: emitLazyGlobalInitializer + if (C.LangOpts.Target.isOSBinFormatWasm()) { + auto UnsafeRawPointer = C.getUnsafeRawPointerDecl(); + auto UnsafeRawPtrTy = getLoweredType(UnsafeRawPointer->getDeclaredInterfaceType()); + F.front().createFunctionArgument(UnsafeRawPtrTy); + } + { Scope scope(Cleanups, binding); diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp index b7ee169fc9faf..a63b0bd512862 100644 --- a/lib/SILGen/SILGenPattern.cpp +++ b/lib/SILGen/SILGenPattern.cpp @@ -1038,20 +1038,35 @@ void PatternMatchEmission::emitDispatch(ClauseMatrix &clauses, ArgArray args, SGF.eraseBasicBlock(contBB); return; } - + // Otherwise, if there is no fallthrough, then the next row is - // unreachable: emit a dead code diagnostic. + // unreachable: emit a dead code diagnostic if: + // 1) It's for a 'default' case (since Space Engine already handles + // unreachable enum case patterns) or it's for a enum case which + // has expression patterns since redundancy checking for such + // patterns isn't sufficiently done by the Space Engine. + // 2) It's for a case statement in a do-catch. if (!clauses[firstRow].hasFallthroughTo()) { SourceLoc Loc; bool isDefault = false; + bool isParentDoCatch = false; + bool caseHasExprPattern = false; if (auto *S = clauses[firstRow].getClientData()) { Loc = S->getStartLoc(); - if (auto *CS = dyn_cast(S)) + if (auto *CS = dyn_cast(S)) { + caseHasExprPattern = llvm::any_of( + CS->getCaseLabelItems(), [&](const CaseLabelItem item) { + return item.getPattern()->getKind() == PatternKind::Expr; + }); + isParentDoCatch = CS->getParentKind() == CaseParentKind::DoCatch; isDefault = CS->isDefault(); + } } else { Loc = clauses[firstRow].getCasePattern()->getStartLoc(); } - SGF.SGM.diagnose(Loc, diag::unreachable_case, isDefault); + if (isParentDoCatch || isDefault || caseHasExprPattern) { + SGF.SGM.diagnose(Loc, diag::unreachable_case, isDefault); + } } } } diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp index 9854969b1470f..0f30f1c4c15bb 100644 --- a/lib/SILGen/SILGenStmt.cpp +++ b/lib/SILGen/SILGenStmt.cpp @@ -346,7 +346,13 @@ void StmtEmitter::visitBraceStmt(BraceStmt *S) { } else if (auto *E = ESD.dyn_cast()) { SGF.emitIgnoredExpr(E); } else { - SGF.visit(ESD.get()); + auto *D = ESD.get(); + + // Hoisted declarations are emitted at the top level by emitSourceFile(). + if (D->isHoisted()) + continue; + + SGF.visit(D); } } } diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index 8fd44deec40bc..e2c65ef1ee7be 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -90,32 +90,14 @@ SILGenFunction::emitDynamicMethodRef(SILLocation loc, SILDeclRef constant, void SILGenModule::emitForeignToNativeThunk(SILDeclRef thunk) { // Thunks are always emitted by need, so don't need delayed emission. - assert(!thunk.isForeign && "foreign-to-native thunks only"); - SILFunction *f = getFunction(thunk, ForDefinition); - f->setThunk(IsThunk); - if (thunk.asForeign().isClangGenerated()) - f->setSerialized(IsSerializable); - preEmitFunction(thunk, thunk.getDecl(), f, thunk.getDecl()); - PrettyStackTraceSILFunction X("silgen emitForeignToNativeThunk", f); - SILGenFunction(*this, *f, SwiftModule).emitForeignToNativeThunk(thunk); - postEmitFunction(thunk, f); + assert(thunk.isForeignToNativeThunk() && "foreign-to-native thunks only"); + emitFunctionDefinition(thunk, getFunction(thunk, ForDefinition)); } void SILGenModule::emitNativeToForeignThunk(SILDeclRef thunk) { // Thunks are always emitted by need, so don't need delayed emission. - assert(thunk.isForeign && "native-to-foreign thunks only"); - - SILFunction *f = getFunction(thunk, ForDefinition); - if (thunk.hasDecl()) - preEmitFunction(thunk, thunk.getDecl(), f, thunk.getDecl()); - else - preEmitFunction(thunk, thunk.getAbstractClosureExpr(), f, - thunk.getAbstractClosureExpr()); - PrettyStackTraceSILFunction X("silgen emitNativeToForeignThunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, SwiftModule).emitNativeToForeignThunk(thunk); - postEmitFunction(thunk, f); + assert(thunk.isNativeToForeignThunk() && "native-to-foreign thunks only"); + emitFunctionDefinition(thunk, getFunction(thunk, ForDefinition)); } SILValue diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 83f2de20c78f3..d30a74087fc3e 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -1038,7 +1038,7 @@ class SILGenType : public TypeMemberVisitor { // Build a vtable if this is a class. if (auto theClass = dyn_cast(theType)) { - for (Decl *member : theClass->getEmittedMembers()) + for (Decl *member : theClass->getSemanticMembers()) visit(member); SILGenVTable genVTable(SGM, theClass); diff --git a/lib/SILOptimizer/ARC/ARCBBState.cpp b/lib/SILOptimizer/ARC/ARCBBState.cpp index 0b2b0f331ded1..63ddaef0404ae 100644 --- a/lib/SILOptimizer/ARC/ARCBBState.cpp +++ b/lib/SILOptimizer/ARC/ARCBBState.cpp @@ -137,6 +137,34 @@ void ARCBBState::initPredTopDown(ARCBBState &PredBBState) { PtrToTopDownState = PredBBState.PtrToTopDownState; } +void ARCBBState::dumpBottomUpState() { + for (auto state : getBottomupStates()) { + if (!state.hasValue()) + continue; + auto elem = state.getValue(); + if (!elem.first) + continue; + llvm::dbgs() << "SILValue: "; + elem.first->dump(); + llvm::dbgs() << "RefCountState: "; + elem.second.dump(); + } +} + +void ARCBBState::dumpTopDownState() { + for (auto state : getTopDownStates()) { + if (!state.hasValue()) + continue; + auto elem = state.getValue(); + if (!elem.first) + continue; + llvm::dbgs() << "SILValue: "; + elem.first->dump(); + llvm::dbgs() << "RefCountState: "; + elem.second.dump(); + } +} + //===----------------------------------------------------------------------===// // ARCBBStateInfo //===----------------------------------------------------------------------===// diff --git a/lib/SILOptimizer/ARC/ARCBBState.h b/lib/SILOptimizer/ARC/ARCBBState.h index 286c1fc3565ad..e7d3abe5e8d10 100644 --- a/lib/SILOptimizer/ARC/ARCBBState.h +++ b/lib/SILOptimizer/ARC/ARCBBState.h @@ -137,6 +137,9 @@ class ARCSequenceDataflowEvaluator::ARCBBState { /// BB. Used to create an initial state before we merge in other /// predecessors. This is currently a stub. void initPredTopDown(ARCBBState &PredBB); + + void dumpBottomUpState(); + void dumpTopDownState(); }; class ARCSequenceDataflowEvaluator::ARCBBStateInfoHandle { diff --git a/lib/SILOptimizer/ARC/ARCLoopOpts.cpp b/lib/SILOptimizer/ARC/ARCLoopOpts.cpp index 2cadf6426c013..aa54592497e51 100644 --- a/lib/SILOptimizer/ARC/ARCLoopOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCLoopOpts.cpp @@ -47,7 +47,7 @@ class ARCLoopOpts : public SILFunctionTransform { return; // Skip global init functions. - if (F->getName().startswith("globalinit_")) + if (F->isGlobalInitOnceFunction()) return; auto *LA = getAnalysis(); diff --git a/lib/SILOptimizer/ARC/ARCMatchingSet.cpp b/lib/SILOptimizer/ARC/ARCMatchingSet.cpp index 442a4c9011b89..fc603c690f747 100644 --- a/lib/SILOptimizer/ARC/ARCMatchingSet.cpp +++ b/lib/SILOptimizer/ARC/ARCMatchingSet.cpp @@ -68,8 +68,6 @@ ARCMatchingSetBuilder::matchIncrementsToDecrements() { continue; } - // We need to be known safe over all increments/decrements we are matching - // up to ignore insertion points. bool BUIsKnownSafe = (*BURefCountState)->second.isKnownSafe(); LLVM_DEBUG(llvm::dbgs() << " BOTTOM UP KNOWNSAFE: " << (BUIsKnownSafe ? "true" : "false") << "\n"); @@ -152,8 +150,6 @@ ARCMatchingSetBuilder::matchDecrementsToIncrements() { continue; } - // We need to be known safe over all increments/decrements we are matching - // up to ignore insertion points. bool TDIsKnownSafe = (*TDRefCountState)->second.isKnownSafe(); LLVM_DEBUG(llvm::dbgs() << " TOP DOWN KNOWNSAFE: " << (TDIsKnownSafe ? "true" : "false") << "\n"); @@ -223,7 +219,7 @@ bool ARCMatchingSetBuilder::matchUpIncDecSetsForPtr() { LLVM_DEBUG(llvm::dbgs() << "Attempting to match up increments -> " "decrements:\n"); // For each increment in our list of new increments, attempt to match them - // up with decrements and gather the insertion points of the decrements. + // up with decrements. auto Result = matchIncrementsToDecrements(); if (!Result) { LLVM_DEBUG(llvm::dbgs() << " FAILED TO MATCH INCREMENTS -> " @@ -287,8 +283,6 @@ bool ARCMatchingSetBuilder::matchUpIncDecSetsForPtr() { assert(MatchSet.Increments.empty() == MatchSet.Decrements.empty() && "Match set without increments or decrements"); - // If we do not have any insertion points but we do have increments, we must - // be eliminating pairs. if (!MatchSet.Increments.empty()) MatchedPair = true; diff --git a/lib/SILOptimizer/ARC/ARCRegionState.cpp b/lib/SILOptimizer/ARC/ARCRegionState.cpp index f654bbeb6e485..c076b0ec198b2 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.cpp +++ b/lib/SILOptimizer/ARC/ARCRegionState.cpp @@ -12,6 +12,7 @@ #define DEBUG_TYPE "arc-sequence-opts" #include "ARCRegionState.h" +#include "ARCSequenceOptUtils.h" #include "RCStateTransitionVisitors.h" #include "swift/Basic/Range.h" #include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h" @@ -155,93 +156,30 @@ 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::UnwindInst: - case TermKind::YieldInst: - case TermKind::TryApplyInst: - case TermKind::SwitchValueInst: - case TermKind::SwitchEnumInst: - case TermKind::SwitchEnumAddrInst: - case TermKind::DynamicMethodBranchInst: - case TermKind::CheckedCastBranchInst: - case TermKind::CheckedCastValueBranchInst: - case TermKind::CheckedCastAddrBranchInst: - return true; - } - - llvm_unreachable("Unhandled TermKind in switch."); -} - -// 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, +bool ARCRegionState::processBlockBottomUp( + const LoopRegion *R, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, + EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI, + bool FreezeOwnedArgEpilogueReleases, + BlotMapVector &IncToDecStateMap, ImmutablePointerSetFactory &SetFactory) { - 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); - } - - for (auto &OtherState : getBottomupStates()) { - // If the other state's value is blotted, skip it. - if (!OtherState.hasValue()) - continue; - - OtherState->second.updateForPredTerminators(PredTerminators, - SetFactory, AA); - } -} + LLVM_DEBUG(llvm::dbgs() << ">>>> Bottom Up!\n"); -static bool processBlockBottomUpInsts( - ARCRegionState &State, SILBasicBlock &BB, - BottomUpDataflowRCStateVisitor &DataflowVisitor, - AliasAnalysis *AA, ImmutablePointerSetFactory &SetFactory) { + SILBasicBlock &BB = *R->getBlock(); + BottomUpDataflowRCStateVisitor DataflowVisitor( + RCIA, EAFI, *this, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, + SetFactory); - auto II = State.summarizedinterestinginsts_rbegin(); - auto IE = State.summarizedinterestinginsts_rend(); + auto II = summarizedinterestinginsts_rbegin(); + auto IE = summarizedinterestinginsts_rend(); // If we do not have any interesting instructions, bail and return false since // we can not have any nested instructions. if (II == IE) return false; - // If II is the terminator, skip it since our terminator was already processed - // in our successors. - if (*II == BB.getTerminator()) + // If II is not an arc significant terminator, skip it. + if (*II == BB.getTerminator() && + !isARCSignificantTerminator(cast(*II))) ++II; bool NestingDetected = false; @@ -266,9 +204,15 @@ static bool processBlockBottomUpInsts( // that the instruction "visits". SILValue Op = Result.RCIdentity; + std::function checkIfRefCountInstIsMatched = + [&IncToDecStateMap](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return IncToDecStateMap.find(Inst) != IncToDecStateMap.end(); + }; + // For all other (reference counted value, ref count state) we are // tracking... - for (auto &OtherState : State.getBottomupStates()) { + for (auto &OtherState : getBottomupStates()) { // If the other state's value is blotted, skip it. if (!OtherState.hasValue()) continue; @@ -278,49 +222,21 @@ static bool processBlockBottomUpInsts( if (Op && OtherState->first == Op) continue; - OtherState->second.updateForSameLoopInst(I, SetFactory, AA); + OtherState->second.updateForSameLoopInst(I, AA); + OtherState->second.checkAndResetKnownSafety( + I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); } } return NestingDetected; } -bool ARCRegionState::processBlockBottomUp( - const LoopRegion *R, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, - EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI, - bool FreezeOwnedArgEpilogueReleases, - BlotMapVector &IncToDecStateMap, - ImmutablePointerSetFactory &SetFactory) { - LLVM_DEBUG(llvm::dbgs() << ">>>> Bottom Up!\n"); - - SILBasicBlock &BB = *R->getBlock(); - BottomUpDataflowRCStateVisitor DataflowVisitor( - RCIA, EAFI, *this, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, - SetFactory); - - // Visit each non-terminator arc relevant instruction I in BB visited in - // reverse... - bool NestingDetected = - processBlockBottomUpInsts(*this, BB, DataflowVisitor, AA, SetFactory); - - // 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, SetFactory); - - return NestingDetected; -} - -// Find the relevant insertion points for the loop region R in its -// successors. Returns true if we succeeded. Returns false if any of the -// non-local successors of the region are not leaking blocks. We currently do -// not handle early exits, but do handle trapping blocks. -static bool getInsertionPtsForLoopRegionExits( +// Returns true if any of the non-local successors of the region are leaking +// blocks. We currently do not handle early exits, but do handle trapping +// blocks. Returns false if otherwise +static bool hasEarlyExits( const LoopRegion *R, LoopRegionFunctionInfo *LRFI, - llvm::DenseMap &RegionStateInfo, - llvm::SmallVectorImpl &InsertPts) { + llvm::DenseMap &RegionStateInfo) { assert(R->isLoop() && "Expected a loop region that is representing a loop"); // Go through all of our non local successors. If any of them cannot be @@ -329,48 +245,43 @@ static bool getInsertionPtsForLoopRegionExits( if (any_of(R->getNonLocalSuccs(), [&](unsigned SuccID) -> bool { return !RegionStateInfo[LRFI->getRegion(SuccID)]->allowsLeaks(); })) { - return false; - } - - // We assume that all of our loops have been canonicalized so that /all/ loop - // exit blocks only have exiting blocks as predecessors. This means that all - // successor regions of any region /cannot/ be a region representing a loop. - for (unsigned SuccID : R->getLocalSuccs()) { - auto *SuccRegion = LRFI->getRegion(SuccID); - assert(SuccRegion->isBlock() && "Loop canonicalization failed?!"); - InsertPts.push_back(&*SuccRegion->getBlock()->begin()); + return true; } - // Sort and unique the insert points so we can put them into - // ImmutablePointerSets. - sortUnique(InsertPts); - - return true; + return false; } bool ARCRegionState::processLoopBottomUp( const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, + RCIdentityFunctionInfo *RCIA, llvm::DenseMap &RegionStateInfo, - ImmutablePointerSetFactory &SetFactory) { + llvm::DenseSet &UnmatchedRefCountInsts) { ARCRegionState *State = RegionStateInfo[R]; - llvm::SmallVector InsertPts; - // Try to lookup insertion points for this region. If when checking for - // insertion points, we find that we have non-leaking early exits, clear state + // If we find that we have non-leaking early exits, clear state // and bail. We do not handle these for now. - if (!getInsertionPtsForLoopRegionExits(R, LRFI, RegionStateInfo, InsertPts)) { + if (hasEarlyExits(R, LRFI, RegionStateInfo)) { clearBottomUpState(); return false; } + std::function checkIfRefCountInstIsMatched = + [&UnmatchedRefCountInsts](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return UnmatchedRefCountInsts.find(Inst) == UnmatchedRefCountInsts.end(); + }; + // For each state that we are currently tracking, apply our summarized // instructions to it. for (auto &OtherState : getBottomupStates()) { if (!OtherState.hasValue()) continue; - for (auto *I : State->getSummarizedInterestingInsts()) - OtherState->second.updateForDifferentLoopInst(I, SetFactory, AA); + for (auto *I : State->getSummarizedInterestingInsts()) { + OtherState->second.updateForDifferentLoopInst(I, AA); + OtherState->second.checkAndResetKnownSafety( + I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); + } } return false; @@ -380,6 +291,7 @@ bool ARCRegionState::processBottomUp( AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI, bool FreezeOwnedArgEpilogueReleases, + llvm::DenseSet &UnmatchedRefCountInsts, BlotMapVector &IncToDecStateMap, llvm::DenseMap &RegionStateInfo, ImmutablePointerSetFactory &SetFactory) { @@ -388,7 +300,8 @@ bool ARCRegionState::processBottomUp( // We only process basic blocks for now. This ensures that we always propagate // the empty set from loops. if (!R->isBlock()) - return processLoopBottomUp(R, AA, LRFI, RegionStateInfo, SetFactory); + return processLoopBottomUp(R, AA, LRFI, RCIA, RegionStateInfo, + UnmatchedRefCountInsts); return processBlockBottomUp(R, AA, RCIA, EAFI, LRFI, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, SetFactory); @@ -444,6 +357,12 @@ bool ARCRegionState::processBlockTopDown( // that the instruction "visits". SILValue Op = Result.RCIdentity; + std::function checkIfRefCountInstIsMatched = + [&DecToIncStateMap](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return DecToIncStateMap.find(Inst) != DecToIncStateMap.end(); + }; + // For all other [(SILValue, TopDownState)] we are tracking... for (auto &OtherState : getTopDownStates()) { // If the other state's value is blotted, skip it. @@ -456,7 +375,9 @@ bool ARCRegionState::processBlockTopDown( if (Op && OtherState->first == Op) continue; - OtherState->second.updateForSameLoopInst(I, SetFactory, AA); + OtherState->second.updateForSameLoopInst(I, AA); + OtherState->second.checkAndResetKnownSafety( + I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); } } @@ -465,8 +386,8 @@ bool ARCRegionState::processBlockTopDown( bool ARCRegionState::processLoopTopDown( const LoopRegion *R, ARCRegionState *State, AliasAnalysis *AA, - LoopRegionFunctionInfo *LRFI, - ImmutablePointerSetFactory &SetFactory) { + LoopRegionFunctionInfo *LRFI, RCIdentityFunctionInfo *RCIA, + llvm::DenseSet &UnmatchedRefCountInsts) { assert(R->isLoop() && "We assume we are processing a loop"); @@ -482,14 +403,23 @@ bool ARCRegionState::processLoopTopDown( assert(PredRegion->isBlock() && "Expected the predecessor region to be a " "block"); + std::function checkIfRefCountInstIsMatched = + [&UnmatchedRefCountInsts](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return UnmatchedRefCountInsts.find(Inst) == UnmatchedRefCountInsts.end(); + }; + // For each state that we are currently tracking, apply our summarized // instructions to it. for (auto &OtherState : getTopDownStates()) { if (!OtherState.hasValue()) continue; - for (auto *I : State->getSummarizedInterestingInsts()) - OtherState->second.updateForDifferentLoopInst(I, SetFactory, AA); + for (auto *I : State->getSummarizedInterestingInsts()) { + OtherState->second.updateForDifferentLoopInst(I, AA); + OtherState->second.checkAndResetKnownSafety( + I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); + } } return false; @@ -498,6 +428,7 @@ bool ARCRegionState::processLoopTopDown( bool ARCRegionState::processTopDown( AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, LoopRegionFunctionInfo *LRFI, + llvm::DenseSet &UnmatchedRefCountInsts, BlotMapVector &DecToIncStateMap, llvm::DenseMap &RegionStateInfo, ImmutablePointerSetFactory &SetFactory) { @@ -506,7 +437,8 @@ bool ARCRegionState::processTopDown( // We only process basic blocks for now. This ensures that we always propagate // the empty set from loops. if (!R->isBlock()) - return processLoopTopDown(R, RegionStateInfo[R], AA, LRFI, SetFactory); + return processLoopTopDown(R, RegionStateInfo[R], AA, LRFI, RCIA, + UnmatchedRefCountInsts); return processBlockTopDown(*R->getBlock(), AA, RCIA, DecToIncStateMap, SetFactory); diff --git a/lib/SILOptimizer/ARC/ARCRegionState.h b/lib/SILOptimizer/ARC/ARCRegionState.h index 6facbb7d57cbe..c55af4604ed6a 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.h +++ b/lib/SILOptimizer/ARC/ARCRegionState.h @@ -188,6 +188,7 @@ class ARCRegionState { bool processTopDown( AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, LoopRegionFunctionInfo *LRFI, + llvm::DenseSet &UnmatchedRefCountInsts, BlotMapVector &DecToIncStateMap, llvm::DenseMap &LoopRegionState, ImmutablePointerSetFactory &SetFactory); @@ -200,6 +201,7 @@ class ARCRegionState { AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI, bool FreezeOwnedArgEpilogueReleases, + llvm::DenseSet &UnmatchedRefCountInsts, BlotMapVector &IncToDecStateMap, llvm::DenseMap &RegionStateInfo, ImmutablePointerSetFactory &SetFactory); @@ -219,9 +221,6 @@ class ARCRegionState { void removeInterestingInst(SILInstruction *I); private: - void processBlockBottomUpPredTerminators( - const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, - ImmutablePointerSetFactory &SetFactory); bool processBlockBottomUp( const LoopRegion *R, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, EpilogueARCFunctionInfo *EAFI, @@ -230,17 +229,18 @@ class ARCRegionState { ImmutablePointerSetFactory &SetFactory); bool processLoopBottomUp( const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, + RCIdentityFunctionInfo *RCIA, llvm::DenseMap &RegionStateInfo, - ImmutablePointerSetFactory &SetFactory); + llvm::DenseSet &UnmatchedRefCountInsts); bool processBlockTopDown( SILBasicBlock &BB, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, BlotMapVector &DecToIncStateMap, ImmutablePointerSetFactory &SetFactory); - bool - processLoopTopDown(const LoopRegion *R, ARCRegionState *State, - AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, - ImmutablePointerSetFactory &SetFactory); + bool processLoopTopDown( + const LoopRegion *R, ARCRegionState *State, AliasAnalysis *AA, + LoopRegionFunctionInfo *LRFI, RCIdentityFunctionInfo *RCIA, + llvm::DenseSet &UnmatchedRefCountInsts); void summarizeLoop( const LoopRegion *R, LoopRegionFunctionInfo *LRFI, diff --git a/lib/SILOptimizer/ARC/ARCSequenceOptUtils.cpp b/lib/SILOptimizer/ARC/ARCSequenceOptUtils.cpp new file mode 100644 index 0000000000000..ff04e27b99264 --- /dev/null +++ b/lib/SILOptimizer/ARC/ARCSequenceOptUtils.cpp @@ -0,0 +1,48 @@ +//===--- ARCSequenceOptUtils.cpp - ARCSequenceOpt utilities ------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "ARCSequenceOptUtils.h" + +using namespace swift; +namespace swift { +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::UnwindInst: + case TermKind::YieldInst: + case TermKind::TryApplyInst: + case TermKind::SwitchValueInst: + case TermKind::SwitchEnumInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::DynamicMethodBranchInst: + case TermKind::CheckedCastBranchInst: + case TermKind::CheckedCastValueBranchInst: + case TermKind::CheckedCastAddrBranchInst: + return true; + } + + llvm_unreachable("Unhandled TermKind in switch."); +} + +} // end namespace 'swift' diff --git a/lib/SILOptimizer/ARC/ARCSequenceOptUtils.h b/lib/SILOptimizer/ARC/ARCSequenceOptUtils.h new file mode 100644 index 0000000000000..b94af73cc1aab --- /dev/null +++ b/lib/SILOptimizer/ARC/ARCSequenceOptUtils.h @@ -0,0 +1,27 @@ +//===--- ARCSequenceOptUtils.h - ARCSequenceOpts utilities ----*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// Utilities used by the ARCSequenceOpts for analyzing and transforming +/// SILInstructions. +/// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_ARC_ARCSEQUENCEOPTUTILS_H +#define SWIFT_SILOPTIMIZER_ARC_ARCSEQUENCEOPTUTILS_H + +#include "swift/SIL/SILInstruction.h" + +namespace swift { +bool isARCSignificantTerminator(TermInst *TI); +} // end namespace swift + +#endif diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp index 00d284761f6a7..827b59d82d57b 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp @@ -45,12 +45,10 @@ llvm::cl::opt EnableLoopARC("enable-loop-arc", llvm::cl::init(false)); // Code Motion //===----------------------------------------------------------------------===// -// This routine takes in the ARCMatchingSet \p MatchSet and inserts new -// increments, decrements at the insertion points and adds the old increment, -// decrements to the delete list. Sets changed to true if anything was moved or -// deleted. +// This routine takes in the ARCMatchingSet \p MatchSet and adds the increments +// and decrements to the delete list. void ARCPairingContext::optimizeMatchingSet( - ARCMatchingSet &MatchSet, llvm::SmallVectorImpl &NewInsts, + ARCMatchingSet &MatchSet, llvm::SmallVectorImpl &DeadInsts) { LLVM_DEBUG(llvm::dbgs() << "**** Optimizing Matching Set ****\n"); // Add the old increments to the delete list. @@ -71,7 +69,6 @@ void ARCPairingContext::optimizeMatchingSet( } bool ARCPairingContext::performMatching( - llvm::SmallVectorImpl &NewInsts, llvm::SmallVectorImpl &DeadInsts) { bool MatchedPair = false; @@ -99,10 +96,7 @@ bool ARCPairingContext::performMatching( for (auto *I : Set.Decrements) DecToIncStateMap.erase(I); - // Add the Set to the callback. *NOTE* No instruction destruction can - // happen here since we may remove instructions that are insertion points - // for other instructions. - optimizeMatchingSet(Set, NewInsts, DeadInsts); + optimizeMatchingSet(Set, DeadInsts); } } @@ -136,7 +130,6 @@ void LoopARCPairingContext::runOnFunction(SILFunction *F) { bool LoopARCPairingContext::processRegion(const LoopRegion *Region, bool FreezePostDomReleases, bool RecomputePostDomReleases) { - llvm::SmallVector NewInsts; llvm::SmallVector DeadInsts; // We have already summarized all subloops of this loop. Now summarize our @@ -150,16 +143,7 @@ bool LoopARCPairingContext::processRegion(const LoopRegion *Region, do { NestingDetected = Evaluator.runOnLoop(Region, FreezePostDomReleases, RecomputePostDomReleases); - MatchedPair = Context.performMatching(NewInsts, DeadInsts); - - if (!NewInsts.empty()) { - LLVM_DEBUG(llvm::dbgs() << "Adding new interesting insts!\n"); - do { - auto *I = NewInsts.pop_back_val(); - LLVM_DEBUG(llvm::dbgs() << " " << *I); - Evaluator.addInterestingInst(I); - } while (!NewInsts.empty()); - } + MatchedPair = Context.performMatching(DeadInsts); if (!DeadInsts.empty()) { LLVM_DEBUG(llvm::dbgs() << "Removing dead interesting insts!\n"); @@ -172,6 +156,7 @@ bool LoopARCPairingContext::processRegion(const LoopRegion *Region, } MadeChange |= MatchedPair; + Evaluator.saveMatchingInfo(Region); Evaluator.clearLoopState(Region); Context.DecToIncStateMap.clear(); Context.IncToDecStateMap.clear(); @@ -199,7 +184,7 @@ processFunctionWithoutLoopSupport(SILFunction &F, bool FreezePostDomReleases, // globalinit_func. Since that is not *that* interesting from an ARC // perspective (i.e. no ref count operations in a loop), disable it on such // functions temporarily in order to unblock others. This should be removed. - if (F.getName().startswith("globalinit_")) + if (F.isGlobalInitOnceFunction()) return false; LLVM_DEBUG(llvm::dbgs() << "***** Processing " << F.getName() << " *****\n"); @@ -247,7 +232,7 @@ static bool processFunctionWithLoopSupport( // globalinit_func. Since that is not *that* interesting from an ARC // perspective (i.e. no ref count operations in a loop), disable it on such // functions temporarily in order to unblock others. This should be removed. - if (F.getName().startswith("globalinit_")) + if (F.isGlobalInitOnceFunction()) return false; LLVM_DEBUG(llvm::dbgs() << "***** Processing " << F.getName() << " *****\n"); diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.h b/lib/SILOptimizer/ARC/ARCSequenceOpts.h index 36d7eb57f2548..9be3af2cc3620 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.h +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.h @@ -39,11 +39,9 @@ struct ARCPairingContext { ARCPairingContext(SILFunction &F, RCIdentityFunctionInfo *RCIA) : F(F), DecToIncStateMap(), IncToDecStateMap(), RCIA(RCIA) {} - bool performMatching(llvm::SmallVectorImpl &NewInsts, - llvm::SmallVectorImpl &DeadInsts); + bool performMatching(llvm::SmallVectorImpl &DeadInsts); void optimizeMatchingSet(ARCMatchingSet &MatchSet, - llvm::SmallVectorImpl &NewInsts, llvm::SmallVectorImpl &DeadInsts); }; @@ -68,10 +66,8 @@ struct BlockARCPairingContext { bool NestingDetected = Evaluator.run(FreezePostDomReleases); Evaluator.clear(); - llvm::SmallVector NewInsts; llvm::SmallVector DeadInsts; - bool MatchedPair = Context.performMatching(NewInsts, DeadInsts); - NewInsts.clear(); + bool MatchedPair = Context.performMatching(DeadInsts); while (!DeadInsts.empty()) DeadInsts.pop_back_val()->eraseFromParent(); return NestingDetected && MatchedPair; diff --git a/lib/SILOptimizer/ARC/CMakeLists.txt b/lib/SILOptimizer/ARC/CMakeLists.txt index 2d3c592834b1b..bc14ca17698ac 100644 --- a/lib/SILOptimizer/ARC/CMakeLists.txt +++ b/lib/SILOptimizer/ARC/CMakeLists.txt @@ -4,6 +4,7 @@ target_sources(swiftSILOptimizer PRIVATE ARCMatchingSet.cpp ARCRegionState.cpp ARCSequenceOpts.cpp + ARCSequenceOptUtils.cpp GlobalARCSequenceDataflow.cpp GlobalLoopARCSequenceDataflow.cpp RCStateTransition.cpp diff --git a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp index 777548d884bdd..1e851075f9719 100644 --- a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp @@ -13,6 +13,7 @@ #define DEBUG_TYPE "arc-sequence-opts" #include "GlobalARCSequenceDataflow.h" #include "ARCBBState.h" +#include "ARCSequenceOptUtils.h" #include "RCStateTransitionVisitors.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" @@ -75,6 +76,12 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) { } } + std::function checkIfRefCountInstIsMatched = + [&DecToIncStateMap = DecToIncStateMap](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return DecToIncStateMap.find(Inst) != DecToIncStateMap.end(); + }; + // For each instruction I in BB... for (auto &I : BB) { @@ -93,7 +100,7 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) { // This SILValue may be null if we were unable to find a specific RCIdentity // that the instruction "visits". - SILValue Op = Result.RCIdentity; + SILValue CurrentRC = Result.RCIdentity; // For all other [(SILValue, TopDownState)] we are tracking... for (auto &OtherState : BBState.getTopDownStates()) { @@ -104,10 +111,12 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) { // If we visited an increment or decrement successfully (and thus Op is // set), if this is the state for this operand, skip it. We already // processed it. - if (Op && OtherState->first == Op) + if (CurrentRC && OtherState->first == CurrentRC) continue; - OtherState->second.updateForSameLoopInst(&I, SetFactory, AA); + OtherState->second.updateForSameLoopInst(&I, AA); + OtherState->second.checkAndResetKnownSafety( + &I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); } } @@ -117,7 +126,6 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) { void ARCSequenceDataflowEvaluator::mergePredecessors( ARCBBStateInfoHandle &DataHandle) { bool HasAtLeastOnePred = false; - llvm::SmallVector BBThatNeedInsertPts; SILBasicBlock *BB = DataHandle.getBB(); ARCBBState &BBState = DataHandle.getState(); @@ -195,39 +203,6 @@ 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::UnwindInst: - case TermKind::YieldInst: - case TermKind::TryApplyInst: - case TermKind::SwitchValueInst: - case TermKind::SwitchEnumInst: - case TermKind::SwitchEnumAddrInst: - case TermKind::DynamicMethodBranchInst: - case TermKind::CheckedCastBranchInst: - case TermKind::CheckedCastValueBranchInst: - case TermKind::CheckedCastAddrBranchInst: - return true; - } - - llvm_unreachable("Unhandled TermKind in switch."); -} - /// Analyze a single BB for refcount inc/dec instructions. /// /// If anything was found it will be added to DecToIncStateMap. @@ -254,8 +229,19 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp( RCIA, EAFI, BBState, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, SetFactory); - // For each terminator instruction I in BB visited in reverse... - for (auto II = std::next(BB.rbegin()), IE = BB.rend(); II != IE;) { + std::function checkIfRefCountInstIsMatched = + [&IncToDecStateMap = IncToDecStateMap](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return IncToDecStateMap.find(Inst) != IncToDecStateMap.end(); + }; + + auto II = BB.rbegin(); + if (!isARCSignificantTerminator(&cast(*II))) { + II++; + } + + // For each instruction I in BB visited in reverse... + for (auto IE = BB.rend(); II != IE;) { SILInstruction &I = *II; ++II; @@ -274,7 +260,7 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp( // This SILValue may be null if we were unable to find a specific RCIdentity // that the instruction "visits". - SILValue Op = Result.RCIdentity; + SILValue CurrentRC = Result.RCIdentity; // For all other (reference counted value, ref count state) we are // tracking... @@ -285,38 +271,15 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp( // If this is the state associated with the instruction that we are // currently visiting, bail. - if (Op && OtherState->first == Op) + if (CurrentRC && OtherState->first == CurrentRC) continue; - OtherState->second.updateForSameLoopInst(&I, SetFactory, AA); + OtherState->second.updateForSameLoopInst(&I, AA); + OtherState->second.checkAndResetKnownSafety( + &I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); } } - // 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.getPredecessorBlocks()) { - auto *TermInst = PredBB->getTerminator(); - if (!isARCSignificantTerminator(TermInst)) - continue; - PredTerminators.push_back(TermInst); - } - - for (auto &OtherState : BBState.getBottomupStates()) { - // If the other state's value is blotted, skip it. - if (!OtherState.hasValue()) - continue; - - OtherState->second.updateForPredTerminators(PredTerminators, - SetFactory, AA); - } - return NestingDetected; } @@ -416,9 +379,36 @@ ARCSequenceDataflowEvaluator::ARCSequenceDataflowEvaluator( bool ARCSequenceDataflowEvaluator::run(bool FreezeOwnedReleases) { bool NestingDetected = processBottomUp(FreezeOwnedReleases); NestingDetected |= processTopDown(); + + LLVM_DEBUG( + llvm::dbgs() << "*** Bottom-Up and Top-Down analysis results ***\n"); + LLVM_DEBUG(dumpDataflowResults()); + return NestingDetected; } +void ARCSequenceDataflowEvaluator::dumpDataflowResults() { + llvm::dbgs() << "IncToDecStateMap:\n"; + for (auto it : IncToDecStateMap) { + if (!it.hasValue()) + continue; + auto instAndState = it.getValue(); + llvm::dbgs() << "Increment: "; + instAndState.first->dump(); + instAndState.second.dump(); + } + + llvm::dbgs() << "DecToIncStateMap:\n"; + for (auto it : DecToIncStateMap) { + if (!it.hasValue()) + continue; + auto instAndState = it.getValue(); + llvm::dbgs() << "Decrement: "; + instAndState.first->dump(); + instAndState.second.dump(); + } +} + // We put the destructor here so we don't need to expose the type of // BBStateInfo to the outside world. ARCSequenceDataflowEvaluator::~ARCSequenceDataflowEvaluator() = default; diff --git a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h index bf9f8281dc5a3..615a755176be0 100644 --- a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h +++ b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h @@ -108,6 +108,8 @@ class ARCSequenceDataflowEvaluator { llvm::Optional getBottomUpBBState(SILBasicBlock *BB); llvm::Optional getTopDownBBState(SILBasicBlock *BB); + + void dumpDataflowResults(); }; } // end swift namespace diff --git a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp index c090a645eb6bd..108af5d805848 100644 --- a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp @@ -110,7 +110,8 @@ bool LoopARCSequenceDataflowEvaluator::processLoopTopDown(const LoopRegion *R) { // Then perform the dataflow. NestingDetected |= SubregionData.processTopDown( - AA, RCFI, LRFI, DecToIncStateMap, RegionStateInfo, SetFactory); + AA, RCFI, LRFI, UnmatchedRefCountInsts, DecToIncStateMap, + RegionStateInfo, SetFactory); } return NestingDetected; @@ -200,48 +201,23 @@ bool LoopARCSequenceDataflowEvaluator::processLoopBottomUp( bool NestingDetected = false; // For each BB in our post order... - auto Start = R->subregion_begin(), End = R->subregion_end(); - if (Start == End) - return false; - - --End; - while (Start != End) { - unsigned SubregionIndex = *End; - auto *Subregion = LRFI->getRegion(SubregionIndex); - auto &SubregionData = getARCState(Subregion); - - // This will always succeed since we have an entry for each BB in our post - // order. - LLVM_DEBUG(llvm::dbgs() << "Processing Subregion#: " << SubregionIndex - << "\n"); - - LLVM_DEBUG(llvm::dbgs() << "Merging Successors!\n"); - mergeSuccessors(Subregion, SubregionData); - - // Then perform the region optimization. - NestingDetected |= SubregionData.processBottomUp( - AA, RCFI, EAFI, LRFI, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, - RegionStateInfo, SetFactory); - --End; - } - - { - unsigned SubregionIndex = *End; + for (unsigned SubregionIndex : R->getReverseSubregions()) { auto *Subregion = LRFI->getRegion(SubregionIndex); auto &SubregionData = getARCState(Subregion); // This will always succeed since we have an entry for each BB in our post // order. - LLVM_DEBUG(llvm::dbgs() << "Processing Subregion#: " << SubregionIndex - << "\n"); + LLVM_DEBUG(llvm::dbgs() + << "Processing Subregion#: " << SubregionIndex << "\n"); LLVM_DEBUG(llvm::dbgs() << "Merging Successors!\n"); mergeSuccessors(Subregion, SubregionData); // Then perform the region optimization. NestingDetected |= SubregionData.processBottomUp( - AA, RCFI, EAFI, LRFI, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, - RegionStateInfo, SetFactory); + AA, RCFI, EAFI, LRFI, FreezeOwnedArgEpilogueReleases, + UnmatchedRefCountInsts, IncToDecStateMap, RegionStateInfo, + SetFactory); } return NestingDetected; @@ -278,13 +254,39 @@ LoopARCSequenceDataflowEvaluator::~LoopARCSequenceDataflowEvaluator() { bool LoopARCSequenceDataflowEvaluator::runOnLoop( const LoopRegion *R, bool FreezeOwnedArgEpilogueReleases, bool RecomputePostDomReleases) { + LLVM_DEBUG(llvm::dbgs() << "Run on region:\n"); + LLVM_DEBUG(R->dump(true)); bool NestingDetected = processLoopBottomUp(R, FreezeOwnedArgEpilogueReleases); NestingDetected |= processLoopTopDown(R); + LLVM_DEBUG( + llvm::dbgs() << "*** Bottom-Up and Top-Down analysis results ***\n"); + LLVM_DEBUG(dumpDataflowResults()); return NestingDetected; } -void LoopARCSequenceDataflowEvaluator::summarizeLoop( - const LoopRegion *R) { +void LoopARCSequenceDataflowEvaluator::dumpDataflowResults() { + llvm::dbgs() << "IncToDecStateMap:\n"; + for (auto it : IncToDecStateMap) { + if (!it.hasValue()) + continue; + auto instAndState = it.getValue(); + llvm::dbgs() << "Increment: "; + instAndState.first->dump(); + instAndState.second.dump(); + } + + llvm::dbgs() << "DecToIncStateMap:\n"; + for (auto it : DecToIncStateMap) { + if (!it.hasValue()) + continue; + auto instAndState = it.getValue(); + llvm::dbgs() << "Decrement: "; + instAndState.first->dump(); + instAndState.second.dump(); + } +} + +void LoopARCSequenceDataflowEvaluator::summarizeLoop(const LoopRegion *R) { RegionStateInfo[R]->summarize(LRFI, RegionStateInfo); } @@ -313,3 +315,34 @@ void LoopARCSequenceDataflowEvaluator::removeInterestingInst( auto *Region = LRFI->getRegion(I->getParent()); RegionStateInfo[Region]->removeInterestingInst(I); } + +// Compute if a RefCountInst was unmatched and populate in the persistent +// UnmatchedRefCountInsts. +// This can be done by looking up the RefCountInst in IncToDecStateMap or +// DecToIncStateMap. If the StrongIncrement was matched to a StrongDecrement, +// it will be found in IncToDecStateMap. If the StrongDecrement was matched to +// a StrongIncrement, it will be found in DecToIncStateMap. +void LoopARCSequenceDataflowEvaluator::saveMatchingInfo(const LoopRegion *R) { + if (R->isFunction()) + return; + for (unsigned SubregionID : R->getSubregions()) { + auto *Subregion = LRFI->getRegion(SubregionID); + if (!Subregion->isBlock()) + continue; + auto *RegionState = RegionStateInfo[Subregion]; + for (auto Inst : RegionState->getSummarizedInterestingInsts()) { + if (isa(Inst) || isa(Inst)) { + // unmatched if not found in IncToDecStateMap + if (IncToDecStateMap.find(Inst) == IncToDecStateMap.end()) + UnmatchedRefCountInsts.insert(Inst); + continue; + } + if (isa(Inst) || isa(Inst)) { + // unmatched if not found in DecToIncStateMap + if (DecToIncStateMap.find(Inst) == DecToIncStateMap.end()) + UnmatchedRefCountInsts.insert(Inst); + continue; + } + } + } +} diff --git a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h index 027e58745f499..09f86131b5ba4 100644 --- a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h +++ b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h @@ -72,6 +72,9 @@ class LoopARCSequenceDataflowEvaluator { /// Stashed information for each region. llvm::DenseMap RegionStateInfo; + /// Set of unmatched RefCountInsts + llvm::DenseSet UnmatchedRefCountInsts; + public: LoopARCSequenceDataflowEvaluator( SILFunction &F, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, @@ -108,6 +111,10 @@ class LoopARCSequenceDataflowEvaluator { /// Remove \p I from the interesting instruction list of its parent block. void removeInterestingInst(SILInstruction *I); + /// Compute if a RefCountInst was unmatched and populate the persistent + /// UnmatchedRefCountInsts set. + void saveMatchingInfo(const LoopRegion *R); + /// Clear the folding node set of the set factory we have stored internally. void clearSetFactory() { SetFactory.clear(); @@ -134,6 +141,8 @@ class LoopARCSequenceDataflowEvaluator { bool processLoopTopDown(const LoopRegion *R); bool processLoopBottomUp(const LoopRegion *R, bool FreezeOwnedArgEpilogueReleases); + + void dumpDataflowResults(); }; } // end swift namespace diff --git a/lib/SILOptimizer/ARC/RCStateTransition.h b/lib/SILOptimizer/ARC/RCStateTransition.h index 65829ff7b9556..7789cb9697f77 100644 --- a/lib/SILOptimizer/ARC/RCStateTransition.h +++ b/lib/SILOptimizer/ARC/RCStateTransition.h @@ -126,7 +126,6 @@ class RCStateTransition { /// Returns a Range of Mutators. Asserts if this transition is not a mutator /// transition. mutator_range getMutators() const { - assert(isMutator() && "This should never be called given mutators"); return {Mutators->begin(), Mutators->end()}; } diff --git a/lib/SILOptimizer/ARC/RefCountState.cpp b/lib/SILOptimizer/ARC/RefCountState.cpp index e0c43fed19040..1ffba9f5a38a2 100644 --- a/lib/SILOptimizer/ARC/RefCountState.cpp +++ b/lib/SILOptimizer/ARC/RefCountState.cpp @@ -118,7 +118,7 @@ bool BottomUpRefCountState::mightRemoveMutators() { // We will not remove mutators if we have a might be decremented value that // is not known safe. - return LatState != LatticeState::MightBeDecremented || isKnownSafe(); + return isCodeMotionSafe() || isKnownSafe(); } /// Uninitialize the current state. @@ -195,9 +195,7 @@ 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( - SILValue RCIdentity, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +bool BottomUpRefCountState::handleUser() { assert(valueCanBeUsedGivenLatticeState() && "Must be able to be used at this point of the lattice."); @@ -233,22 +231,17 @@ 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( - SILValue RCIdentity, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +bool BottomUpRefCountState::handleGuaranteedUser() { assert(valueCanBeGuaranteedUsedGivenLatticeState() && "Must be able to be used at this point of the lattice."); // Advance the sequence... switch (LatState) { - // If were decremented, insert the insertion point. case LatticeState::Decremented: { LatState = LatticeState::MightBeDecremented; return true; } case LatticeState::MightBeUsed: - // If we have a might be used, we already created an insertion point - // earlier. Just move to MightBeDecremented. LatState = LatticeState::MightBeDecremented; return true; case LatticeState::MightBeDecremented: @@ -273,14 +266,12 @@ bool BottomUpRefCountState::isRefCountInstMatchedToTrackedInstruction( if (!Transition.matchingInst(RefCountInst)) return false; - return handleRefCountInstMatch(RefCountInst); + return handleRefCountInstMatch(); } /// We have a matching ref count inst. Return true if we advance the sequence /// and false otherwise. -bool -BottomUpRefCountState:: -handleRefCountInstMatch(SILInstruction *RefCountInst) { +bool BottomUpRefCountState::handleRefCountInstMatch() { // Otherwise modify the state appropriately in preparation for removing the // increment, decrement pair. switch (LatState) { @@ -288,9 +279,6 @@ handleRefCountInstMatch(SILInstruction *RefCountInst) { return false; case LatticeState::Decremented: case LatticeState::MightBeUsed: - // Unset InsertPt so we remove retain release pairs instead of - // performing code motion. - LLVM_FALLTHROUGH; case LatticeState::MightBeDecremented: return true; } @@ -346,8 +334,7 @@ bool BottomUpRefCountState::merge(const BottomUpRefCountState &Other) { // the value we are tracking. If so advance the state's sequence appropriately // and return true. Otherwise return false. bool BottomUpRefCountState::handlePotentialGuaranteedUser( - SILInstruction *PotentialGuaranteedUser, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { + SILInstruction *PotentialGuaranteedUser, AliasAnalysis *AA) { // If we are not tracking a ref count, just return false. if (!isTrackingRefCount()) return false; @@ -381,7 +368,7 @@ bool BottomUpRefCountState::handlePotentialGuaranteedUser( FoundNonARCUser = true; // Otherwise, update the ref count state given the guaranteed user. - return handleGuaranteedUser(getRCRoot(), SetFactory, AA); + return handleGuaranteedUser(); } /// Check if PotentialDecrement can decrement the reference count associated @@ -414,9 +401,8 @@ bool BottomUpRefCountState::handlePotentialDecrement( // Check if PotentialUser could be a use of the reference counted value that // requires user to be alive. If so advance the state's sequence // appropriately and return true. Otherwise return false. -bool BottomUpRefCountState::handlePotentialUser( - SILInstruction *PotentialUser, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +bool BottomUpRefCountState::handlePotentialUser(SILInstruction *PotentialUser, + AliasAnalysis *AA) { // If we are not tracking a ref count, just return false. if (!isTrackingRefCount()) @@ -440,12 +426,11 @@ bool BottomUpRefCountState::handlePotentialUser( if (mustUseValue(PotentialUser, getRCRoot(), AA)) FoundNonARCUser = true; - return handleUser(getRCRoot(), SetFactory, AA); + return handleUser(); } -void BottomUpRefCountState::updateForSameLoopInst( - SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +void BottomUpRefCountState::updateForSameLoopInst(SILInstruction *I, + AliasAnalysis *AA) { // If this state is not tracking anything, there is nothing to update. if (!isTrackingRefCount()) return; @@ -454,7 +439,7 @@ void BottomUpRefCountState::updateForSameLoopInst( // instruction in a way that requires us to guarantee the lifetime of the // pointer up to this point. This has the effect of performing a use and a // decrement. - if (handlePotentialGuaranteedUser(I, SetFactory, AA)) { + if (handlePotentialGuaranteedUser(I, AA)) { LLVM_DEBUG(llvm::dbgs() << " Found Potential Guaranteed Use:\n " << getRCRoot()); return; @@ -471,15 +456,45 @@ void BottomUpRefCountState::updateForSameLoopInst( // Otherwise check if the reference counted value we are tracking // could be used by the given instruction. - if (!handlePotentialUser(I, SetFactory, AA)) + if (!handlePotentialUser(I, AA)) return; LLVM_DEBUG(llvm::dbgs() << " Found Potential Use:\n " << getRCRoot()); } -void BottomUpRefCountState::updateForDifferentLoopInst( - SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +// Remove "KnownSafe" on the BottomUpRefCountState. If we find another unmatched +// retain instruction with a different aliasing RCIdentity or the same +// RCIdentity in the child region in the loop case. +void BottomUpRefCountState::checkAndResetKnownSafety( + SILInstruction *I, SILValue VisitedRC, + std::function checkIfRefCountInstIsMatched, + RCIdentityFunctionInfo *RCIA, AliasAnalysis *AA) { + assert(VisitedRC); + // If the RefCountState was not marked "KnownSafe", there is nothing to do. + if (!isKnownSafe()) + return; + assert(Transition.getKind() == RCStateTransitionKind::StrongDecrement); + // We only care about retain instructions that can potentially pair with a + // previously visited release. + if (!(isa(I) || isa(I))) + return; + SILValue VisitingRC = RCIA->getRCIdentityRoot(I->getOperand(0)); + assert(VisitingRC); + // If the visiting retain instruction was not already pair with a release + // instruction, return. + if (checkIfRefCountInstIsMatched(I)) + return; + // If the VisitingRC and VisitedRC do not alias, they cannot be incorrectly + // paired. + if (AA->isNoAlias(VisitingRC, VisitedRC)) + return; + LLVM_DEBUG(llvm::dbgs() << "Clearing KnownSafe for: "); + LLVM_DEBUG(VisitedRC->dump()); + clearKnownSafe(); +} + +void BottomUpRefCountState::updateForDifferentLoopInst(SILInstruction *I, + AliasAnalysis *AA) { // If we are not tracking anything, bail. if (!isTrackingRefCount()) return; @@ -489,7 +504,7 @@ void BottomUpRefCountState::updateForDifferentLoopInst( mayDecrementRefCount(I, getRCRoot(), AA)) { LLVM_DEBUG(llvm::dbgs() << " Found potential guaranteed use:\n " << getRCRoot()); - handleGuaranteedUser(getRCRoot(), SetFactory, AA); + handleGuaranteedUser(); return; } } @@ -497,46 +512,12 @@ void BottomUpRefCountState::updateForDifferentLoopInst( // We can just handle potential users normally, since if we handle the user we // already saw a decrement implying that we will treat this like a guaranteed // use. - if (!handlePotentialUser(I, SetFactory, AA)) + if (!handlePotentialUser(I, AA)) return; LLVM_DEBUG(llvm::dbgs() << " Found Potential Use:\n " << getRCRoot()); } -void BottomUpRefCountState::updateForPredTerminators( - ArrayRef Terms, - ImmutablePointerSetFactory &SetFactory, 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(getRCRoot(), SetFactory, 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 mayHaveSymmetricInterference(I, getRCRoot(), AA); })) - return; - - handleUser(getRCRoot(), SetFactory, AA); -} - //===----------------------------------------------------------------------===// // Top Down Ref Count State //===----------------------------------------------------------------------===// @@ -625,9 +606,7 @@ bool TopDownRefCountState::valueCanBeDecrementedGivenLatticeState() const { /// If advance the state's sequence appropriately for a decrement. If we do /// advance return true. Otherwise return false. -bool TopDownRefCountState::handleDecrement( - SILInstruction *PotentialDecrement, - ImmutablePointerSetFactory &SetFactory) { +bool TopDownRefCountState::handleDecrement() { switch (LatState) { case LatticeState::Incremented: LatState = LatticeState::MightBeDecremented; @@ -658,9 +637,7 @@ bool TopDownRefCountState::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 TopDownRefCountState::handleUser(SILInstruction *PotentialUser, - SILValue RCIdentity, - AliasAnalysis *AA) { +bool TopDownRefCountState::handleUser() { assert(valueCanBeUsedGivenLatticeState() && "Must be able to be used at this point of the lattice."); @@ -697,22 +674,16 @@ 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 TopDownRefCountState::handleGuaranteedUser( - SILInstruction *PotentialGuaranteedUser, - SILValue RCIdentity, ImmutablePointerSetFactory &SetFactory, - AliasAnalysis *AA) { +bool TopDownRefCountState::handleGuaranteedUser() { assert(valueCanBeGuaranteedUsedGivenLatticeState() && "Must be able to be used at this point of the lattice."); // Advance the sequence... switch (LatState) { - // If were decremented, insert the insertion point. case LatticeState::Incremented: { LatState = LatticeState::MightBeUsed; return true; } case LatticeState::MightBeDecremented: - // If we have a might be used, we already created an insertion point - // earlier. Just move to MightBeDecremented. LatState = LatticeState::MightBeUsed; return true; case LatticeState::MightBeUsed: @@ -737,13 +708,12 @@ bool TopDownRefCountState::isRefCountInstMatchedToTrackedInstruction( if (!Transition.matchingInst(RefCountInst)) return false; - return handleRefCountInstMatch(RefCountInst); + return handleRefCountInstMatch(); } /// We have a matching ref count inst. Return true if we advance the sequence /// and false otherwise. -bool TopDownRefCountState:: -handleRefCountInstMatch(SILInstruction *RefCountInst) { +bool TopDownRefCountState::handleRefCountInstMatch() { // Otherwise modify the state appropriately in preparation for removing the // increment, decrement pair. switch (LatState) { @@ -805,8 +775,7 @@ bool TopDownRefCountState::merge(const TopDownRefCountState &Other) { // the value we are tracking. If so advance the state's sequence appropriately // and return true. Otherwise return false. bool TopDownRefCountState::handlePotentialGuaranteedUser( - SILInstruction *PotentialGuaranteedUser, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { + SILInstruction *PotentialGuaranteedUser, AliasAnalysis *AA) { // If we are not tracking a ref count, just return false. if (!isTrackingRefCount()) return false; @@ -832,16 +801,14 @@ bool TopDownRefCountState::handlePotentialGuaranteedUser( } // Otherwise, update our step given that we have a potential decrement. - return handleGuaranteedUser(PotentialGuaranteedUser, getRCRoot(), - SetFactory, AA); + return handleGuaranteedUser(); } // Check if PotentialDecrement can decrement the reference count associated with // the value we are tracking. If so advance the state's sequence appropriately // and return true. Otherwise return false. bool TopDownRefCountState::handlePotentialDecrement( - SILInstruction *PotentialDecrement, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { + SILInstruction *PotentialDecrement, AliasAnalysis *AA) { // If we are not tracking a ref count, just return false. if (!isTrackingRefCount()) return false; @@ -860,7 +827,7 @@ bool TopDownRefCountState::handlePotentialDecrement( return false; // Otherwise, update our state given the potential decrement. - return handleDecrement(PotentialDecrement, SetFactory); + return handleDecrement(); } // Check if PotentialUser could be a use of the reference counted value that @@ -883,12 +850,11 @@ bool TopDownRefCountState::handlePotentialUser(SILInstruction *PotentialUser, if (!mayHaveSymmetricInterference(PotentialUser, getRCRoot(), AA)) return false; - return handleUser(PotentialUser, getRCRoot(), AA); + return handleUser(); } -void TopDownRefCountState::updateForSameLoopInst( - SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +void TopDownRefCountState::updateForSameLoopInst(SILInstruction *I, + AliasAnalysis *AA) { // If we are not tracking anything, bail. if (!isTrackingRefCount()) return; @@ -897,7 +863,7 @@ void TopDownRefCountState::updateForSameLoopInst( // instruction in a way that requires us to guarantee the lifetime of the // pointer up to this point. This has the effect of performing a use and a // decrement. - if (handlePotentialGuaranteedUser(I, SetFactory, AA)) { + if (handlePotentialGuaranteedUser(I, AA)) { LLVM_DEBUG(llvm::dbgs() << " Found Potential Guaranteed Use:\n " << getRCRoot()); return; @@ -906,7 +872,7 @@ void TopDownRefCountState::updateForSameLoopInst( // Check if the instruction we are visiting could potentially decrement // the reference counted value we are tracking in a manner that could // cause us to change states. If we do change states continue... - if (handlePotentialDecrement(I, SetFactory, AA)) { + if (handlePotentialDecrement(I, AA)) { LLVM_DEBUG(llvm::dbgs() << " Found Potential Decrement:\n " << getRCRoot()); return; @@ -920,9 +886,39 @@ void TopDownRefCountState::updateForSameLoopInst( << getRCRoot()); } -void TopDownRefCountState::updateForDifferentLoopInst( - SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +// Remove "KnownSafe" on the TopDownRefCountState. If we find another unmatched +// release instruction with a different aliasing RCIdentity or the same +// RCIdentity in the child region in the loop case. +void TopDownRefCountState::checkAndResetKnownSafety( + SILInstruction *I, SILValue VisitedRC, + std::function checkIfRefCountInstIsMatched, + RCIdentityFunctionInfo *RCIA, AliasAnalysis *AA) { + assert(VisitedRC); + // If the RefCountState was not marked "KnownSafe", there is nothing to do. + if (!isKnownSafe()) + return; + assert(Transition.getKind() == RCStateTransitionKind::StrongIncrement); + // We only care about release instructions that can potentially pair with a + // previously visited retain. + if (!(isa(I) || isa(I))) + return; + SILValue VisitingRC = RCIA->getRCIdentityRoot(I->getOperand(0)); + assert(VisitingRC); + // If the visiting release instruction was already pair with a retain + // instruction, return. + if (checkIfRefCountInstIsMatched(I)) + return; + // If the VisitingRC and VisitedRC do not alias, they cannot be incorrectly + // paired. + if (AA->isNoAlias(VisitingRC, VisitedRC)) + return; + LLVM_DEBUG(llvm::dbgs() << "Clearing KnownSafe for: "); + LLVM_DEBUG(VisitedRC->dump()); + clearKnownSafe(); +} + +void TopDownRefCountState::updateForDifferentLoopInst(SILInstruction *I, + AliasAnalysis *AA) { // If we are not tracking anything, bail. if (!isTrackingRefCount()) return; @@ -931,7 +927,7 @@ void TopDownRefCountState::updateForDifferentLoopInst( if (mayGuaranteedUseValue(I, getRCRoot(), AA) || mayDecrementRefCount(I, getRCRoot(), AA)) { LLVM_DEBUG(llvm::dbgs() << " Found potential guaranteed use!\n"); - handleGuaranteedUser(I, getRCRoot(), SetFactory, AA); + handleGuaranteedUser(); return; } } @@ -946,6 +942,27 @@ void TopDownRefCountState::updateForDifferentLoopInst( // Printing Utilities //===----------------------------------------------------------------------===// +void BottomUpRefCountState::dump() { + llvm::dbgs() << LatState << " " + << (isKnownSafe() ? "KnownSafe" : "NotKnownSafe") << " " + << (isCodeMotionSafe() ? "CodeMotionSafe" : "NotCodeMotionSafe") + << "\n"; + llvm::dbgs() << "Matching Instructions:\n"; + for (auto it : getInstructions()) { + it->dump(); + } +} +void TopDownRefCountState::dump() { + llvm::dbgs() << LatState << " " + << (isKnownSafe() ? "KnownSafe" : "NotKnownSafe") << " " + << (isCodeMotionSafe() ? "CodeMotionSafe" : "NotCodeMotionSafe") + << "\n"; + llvm::dbgs() << "Matching Instructions:\n"; + for (auto it : getInstructions()) { + it->dump(); + } +} + namespace llvm { raw_ostream &operator<<(raw_ostream &OS, @@ -981,5 +998,4 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, llvm_unreachable("Unhandled LatticeState in switch."); } - } // end namespace llvm diff --git a/lib/SILOptimizer/ARC/RefCountState.h b/lib/SILOptimizer/ARC/RefCountState.h index 1bfb1ab44e133..bc9e2e46e81cc 100644 --- a/lib/SILOptimizer/ARC/RefCountState.h +++ b/lib/SILOptimizer/ARC/RefCountState.h @@ -14,12 +14,13 @@ #define SWIFT_SILOPTIMIZER_PASSMANAGER_ARC_REFCOUNTSTATE_H #include "RCStateTransition.h" -#include "swift/Basic/type_traits.h" +#include "swift/Basic/BlotMapVector.h" #include "swift/Basic/ImmutablePointerSet.h" -#include "swift/SIL/SILInstruction.h" +#include "swift/Basic/type_traits.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" -#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" @@ -134,6 +135,8 @@ class RefCountState { void updateKnownSafe(bool NewValue) { KnownSafe |= NewValue; } + + void clearKnownSafe() { KnownSafe = false; } }; //===----------------------------------------------------------------------===// @@ -185,31 +188,25 @@ class BottomUpRefCountState : public RefCountState { bool initWithMutatorInst(ImmutablePointerSet *I, RCIdentityFunctionInfo *RCFI); - /// Update this reference count's state given the instruction \p I. \p - /// InsertPt is the point furthest up the CFG where we can move the currently - /// tracked reference count. + /// Update this reference count's state given the instruction \p I. void updateForSameLoopInst(SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); - - /// Update this reference count's state given the instruction \p I. \p - /// InsertPts are the points furthest up the CFG where we can move the - /// currently tracked reference count. + /// Remove "KnownSafe" on the BottomUpRefCountState, if we find a retain + /// instruction with another RCIdentity can pair with the previously visited + /// retain instruction. + void checkAndResetKnownSafety( + SILInstruction *I, SILValue VisitedRC, + std::function checkIfRefCountInstIsMatched, + RCIdentityFunctionInfo *RCIA, AliasAnalysis *AA); + + /// Update this reference count's state given the instruction \p I. // /// The main difference in between this routine and update for same loop inst /// is that if we see any decrements on a value, we treat it as being /// guaranteed used. We treat any uses as regular uses. void updateForDifferentLoopInst( SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, - AliasAnalysis *AA); - - // Determine the conservative effect of the given list of predecessor - // terminators upon this reference count. - void updateForPredTerminators( - ArrayRef PredTerms, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// Attempt to merge \p Other into this ref count state. Return true if we @@ -223,6 +220,8 @@ class BottomUpRefCountState : public RefCountState { /// Uninitialize the current state. void clear(); + void dump(); + private: /// Return true if we *might* remove this instruction. /// @@ -251,19 +250,14 @@ class BottomUpRefCountState : public RefCountState { bool 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. \p InsertPt is - /// the location where if \p PotentialUser is a user of this ref count, we - /// would insert a release. - bool handleUser(SILValue RCIdentity, - ImmutablePointerSetFactory &SetFactory, - AliasAnalysis *AA); + /// lattice state. Return true if we do so and false otherwise. + bool handleUser(); /// Check if PotentialUser could be a use of the reference counted value that /// requires user to be alive. If so advance the state's sequence /// appropriately and return true. Otherwise return false. bool handlePotentialUser(SILInstruction *PotentialUser, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// Returns true if given the current lattice state, do we care if the value @@ -271,25 +265,19 @@ class BottomUpRefCountState : public RefCountState { bool 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. \p InsertPt is - /// the location where if \p PotentialUser is a user of this ref count, we - /// would insert a release. - bool - handleGuaranteedUser(SILValue RCIdentity, - ImmutablePointerSetFactory &SetFactory, - AliasAnalysis *AA); + /// lattice state. Return true if we do so and false otherwise. + bool handleGuaranteedUser(); /// Check if PotentialGuaranteedUser can use the reference count associated /// with the value we are tracking. If so advance the state's sequence /// appropriately and return true. Otherwise return false. bool handlePotentialGuaranteedUser( SILInstruction *User, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// We have a matching ref count inst. Return true if we advance the sequence /// and false otherwise. - bool handleRefCountInstMatch(SILInstruction *RefCountInst); + bool handleRefCountInstMatch(); }; //===----------------------------------------------------------------------===// @@ -345,24 +333,25 @@ class TopDownRefCountState : public RefCountState { /// Uninitialize the current state. void clear(); - /// Update this reference count's state given the instruction \p I. \p - /// InsertPt is the point furthest up the CFG where we can move the currently - /// tracked reference count. + /// Update this reference count's state given the instruction \p I. void updateForSameLoopInst(SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); - - /// Update this reference count's state given the instruction \p I. \p - /// InsertPts are the points furthest up the CFG where we can move the - /// currently tracked reference count. + /// Remove "KnownSafe" on the TopDownRefCountState, if we find a retain + /// instruction with another RCIdentity can pair with the previously visited + /// retain instruction. + void checkAndResetKnownSafety( + SILInstruction *I, SILValue VisitedRC, + std::function checkIfRefCountInstIsMatched, + RCIdentityFunctionInfo *RCIA, AliasAnalysis *AA); + + /// Update this reference count's state given the instruction \p I. /// /// The main difference in between this routine and update for same loop inst /// is that if we see any decrements on a value, we treat it as being /// guaranteed used. We treat any uses as regular uses. void updateForDifferentLoopInst( SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// Returns true if the passed in ref count inst matches the ref count inst @@ -373,6 +362,8 @@ class TopDownRefCountState : public RefCountState { /// succeed and false otherwise. bool merge(const TopDownRefCountState &Other); + void dump(); + private: /// Can we guarantee that the given reference counted value has been modified? bool isRefCountStateModified() const; @@ -383,15 +374,13 @@ class TopDownRefCountState : 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, - ImmutablePointerSetFactory &SetFactory); + bool handleDecrement(); /// Check if PotentialDecrement can decrement the reference count associated /// with the value we are tracking. If so advance the state's sequence /// appropriately and return true. Otherwise return false. bool handlePotentialDecrement( SILInstruction *PotentialDecrement, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// Returns true if given the current lattice state, do we care if the value @@ -400,8 +389,7 @@ class TopDownRefCountState : public RefCountState { /// 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 handleUser(SILInstruction *PotentialUser, - SILValue RCIdentity, AliasAnalysis *AA); + bool handleUser(); /// Check if PotentialUser could be a use of the reference counted value that /// requires user to be alive. If so advance the state's sequence @@ -414,23 +402,18 @@ class TopDownRefCountState : public RefCountState { /// 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 - handleGuaranteedUser(SILInstruction *PotentialGuaranteedUser, - SILValue RCIdentity, - ImmutablePointerSetFactory &SetFactory, - AliasAnalysis *AA); + bool handleGuaranteedUser(); /// Check if PotentialGuaranteedUser can use the reference count associated /// with the value we are tracking. If so advance the state's sequence /// appropriately and return true. Otherwise return false. bool handlePotentialGuaranteedUser( SILInstruction *PotentialGuaranteedUser, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// We have a matching ref count inst. Return true if we advance the sequence /// and false otherwise. - bool handleRefCountInstMatch(SILInstruction *RefCountInst); + bool handleRefCountInstMatch(); }; // These static asserts are here for performance reasons. diff --git a/lib/SILOptimizer/Analysis/DifferentiableActivityAnalysis.cpp b/lib/SILOptimizer/Analysis/DifferentiableActivityAnalysis.cpp index 3d1da0abb78fd..884f544a9d5f4 100644 --- a/lib/SILOptimizer/Analysis/DifferentiableActivityAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/DifferentiableActivityAnalysis.cpp @@ -557,6 +557,8 @@ void DifferentiableActivityInfo::dump(SILAutoDiffIndices indices, for (auto &inst : bb) for (auto res : inst.getResults()) dump(res, indices, s); - s << '\n'; + if (std::next(bb.getIterator()) != fn.end()) + s << '\n'; } + s << "End activity info for " << fn.getName() << " at " << indices << "\n\n"; } diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp index 594cb81485a8c..c651cb5bf2943 100644 --- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp @@ -1623,6 +1623,13 @@ void EscapeAnalysis::ConnectionGraph::verify() const { if (auto ai = dyn_cast(&i)) { if (EA->canOptimizeArrayUninitializedCall(ai).isValid()) continue; + // Ignore checking CGNode mapping for result of apply to a no return + // function that will have a null ReturnNode + if (auto *callee = ai->getReferencedFunctionOrNull()) { + if (EA->getFunctionInfo(callee)->isValid()) + if (!EA->getConnectionGraph(callee)->getReturnNodeOrNull()) + continue; + } } for (auto result : i.getResults()) { if (EA->getPointerBase(result)) diff --git a/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp b/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp index ad6a9f10327b5..2050c2d9c9b2d 100644 --- a/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp @@ -45,8 +45,8 @@ LoopRegion::FunctionTy *LoopRegion::getFunction() const { return Ptr.get(); } -void LoopRegion::dump() const { - print(llvm::outs()); +void LoopRegion::dump(bool isVerbose) const { + print(llvm::outs(), false, isVerbose); llvm::outs() << "\n"; } @@ -69,7 +69,8 @@ void LoopRegion::printName(llvm::raw_ostream &os) const { return; } -void LoopRegion::print(llvm::raw_ostream &os, bool isShort) const { +void LoopRegion::print(llvm::raw_ostream &os, bool isShort, + bool isVerbose) const { os << "(region id:" << ID; if (isShort) { os << ")"; @@ -88,6 +89,20 @@ void LoopRegion::print(llvm::raw_ostream &os, bool isShort) const { os << " ucfh:" << (IsUnknownControlFlowEdgeHead? "true " : "false") << " ucft:" << (IsUnknownControlFlowEdgeTail? "true " : "false"); + + if (!isVerbose) { + return; + } + os << "\n"; + if (isBlock()) { + getBlock()->dump(); + } else if (isLoop()) { + getLoop()->dump(); + } else if (isFunction()) { + getFunction()->dump(); + } else { + llvm_unreachable("Unknown region type"); + } } llvm::raw_ostream &llvm::operator<<(llvm::raw_ostream &os, LoopRegion &LR) { diff --git a/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp b/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp index 7a04927a9dc5a..e9e07a1a13f0a 100644 --- a/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp @@ -522,13 +522,18 @@ void RCIdentityFunctionInfo::getRCUsers( /// We only use the instruction analysis here. void RCIdentityFunctionInfo::getRCUses(SILValue InputValue, llvm::SmallVectorImpl &Uses) { + return visitRCUses(InputValue, + [&](Operand *op) { return Uses.push_back(op); }); +} +void RCIdentityFunctionInfo::visitRCUses( + SILValue InputValue, function_ref Visitor) { // Add V to the worklist. - llvm::SmallVector Worklist; + SmallVector Worklist; Worklist.push_back(InputValue); // A set used to ensure we only visit uses once. - llvm::SmallPtrSet VisitedOps; + SmallPtrSet VisitedOps; // Then until we finish the worklist... while (!Worklist.empty()) { @@ -564,7 +569,7 @@ void RCIdentityFunctionInfo::getRCUses(SILValue InputValue, } // Otherwise, stop searching and report this RC operand. - Uses.push_back(Op); + Visitor(Op); } } } diff --git a/lib/SILOptimizer/CMakeLists.txt b/lib/SILOptimizer/CMakeLists.txt index 4bf45e0ebd8db..ec1440d2b06a1 100644 --- a/lib/SILOptimizer/CMakeLists.txt +++ b/lib/SILOptimizer/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory(LoopTransforms) add_subdirectory(Mandatory) add_subdirectory(PassManager) add_subdirectory(SILCombiner) +add_subdirectory(SemanticARC) add_subdirectory(Transforms) add_subdirectory(UtilityPasses) add_subdirectory(Utils) diff --git a/lib/SILOptimizer/Differentiation/JVPCloner.cpp b/lib/SILOptimizer/Differentiation/JVPCloner.cpp index 8152f409d7592..86c587e9bc47b 100644 --- a/lib/SILOptimizer/Differentiation/JVPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/JVPCloner.cpp @@ -134,19 +134,6 @@ class JVPCloner::Implementation final // General utilities //--------------------------------------------------------------------------// - SILBasicBlock::iterator getNextDifferentialLocalAllocationInsertionPoint() { - // If there are no local allocations, insert at the beginning of the tangent - // entry. - if (differentialLocalAllocations.empty()) - return getDifferential().getEntryBlock()->begin(); - // Otherwise, insert before the last local allocation. Inserting before - // rather than after ensures that allocation and zero initialization - // instructions are grouped together. - auto lastLocalAlloc = differentialLocalAllocations.back(); - auto it = lastLocalAlloc->getDefiningInstruction()->getIterator(); - return it; - } - /// Get the lowered SIL type of the given AST type. SILType getLoweredType(Type type) { auto jvpGenSig = jvp->getLoweredFunctionType()->getSubstGenericSignature(); @@ -309,6 +296,8 @@ class JVPCloner::Implementation final // Tangent buffer mapping //--------------------------------------------------------------------------// + /// Sets the tangent buffer for the original buffer. Asserts that the + /// original buffer does not already have a tangent buffer. void setTangentBuffer(SILBasicBlock *origBB, SILValue originalBuffer, SILValue tangentBuffer) { assert(originalBuffer->getType().isAddress()); @@ -318,13 +307,14 @@ class JVPCloner::Implementation final (void)insertion; } + /// Returns the tangent buffer for the original buffer. Asserts that the + /// original buffer has a tangent buffer. SILValue &getTangentBuffer(SILBasicBlock *origBB, SILValue originalBuffer) { assert(originalBuffer->getType().isAddress()); assert(originalBuffer->getFunction() == original); - auto insertion = - bufferMap.try_emplace({origBB, originalBuffer}, SILValue()); - assert(!insertion.second && "Tangent buffer should already exist"); - return insertion.first->getSecond(); + auto it = bufferMap.find({origBB, originalBuffer}); + assert(it != bufferMap.end() && "Tangent buffer should already exist"); + return it->getSecond(); } //--------------------------------------------------------------------------// @@ -446,27 +436,27 @@ class JVPCloner::Implementation final // If an `apply` has active results or active inout parameters, replace it // with an `apply` of its JVP. void visitApplyInst(ApplyInst *ai) { + bool shouldDifferentiate = + differentialInfo.shouldDifferentiateApplySite(ai); + // If the function has no active arguments or results, zero-initialize the + // tangent buffers of the active indirect results. + if (!shouldDifferentiate) { + for (auto indResult : ai->getIndirectSILResults()) + if (activityInfo.isActive(indResult, getIndices())) { + auto &tanBuf = getTangentBuffer(ai->getParent(), indResult); + emitZeroIndirect(tanBuf->getType().getASTType(), tanBuf, + tanBuf.getLoc()); + } + } // If the function should not be differentiated or its the array literal // initialization intrinsic, just do standard cloning. - if (!differentialInfo.shouldDifferentiateApplySite(ai) || + if (!shouldDifferentiate || ArraySemanticsCall(ai, semantics::ARRAY_UNINITIALIZED_INTRINSIC)) { LLVM_DEBUG(getADDebugStream() << "No active results:\n" << *ai << '\n'); TypeSubstCloner::visitApplyInst(ai); return; } - // Diagnose functions with active inout arguments. - // TODO(TF-129): Support `inout` argument differentiation. - for (auto inoutArg : ai->getInoutArguments()) { - if (activityInfo.isActive(inoutArg, getIndices())) { - context.emitNondifferentiabilityError( - ai, invoker, - diag::autodiff_cannot_differentiate_through_inout_arguments); - errorOccurred = true; - return; - } - } - auto loc = ai->getLoc(); auto &builder = getBuilder(); auto origCallee = getOpValue(ai->getCallee()); @@ -565,9 +555,14 @@ class JVPCloner::Implementation final if (!originalFnTy->getParameters()[paramIndex] .getSILStorageInterfaceType() .isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - ai->getArgumentsWithoutIndirectResults()[paramIndex], - invoker, diag::autodiff_nondifferentiable_argument); + auto arg = ai->getArgumentsWithoutIndirectResults()[paramIndex]; + auto startLoc = arg.getLoc().getStartSourceLoc(); + auto endLoc = arg.getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + arg, invoker, diag::autodiff_nondifferentiable_argument) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } @@ -585,9 +580,14 @@ class JVPCloner::Implementation final .getSILStorageInterfaceType(); } if (!remappedResultType.isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - origCallee, invoker, - diag::autodiff_nondifferentiable_result); + auto startLoc = ai->getLoc().getStartSourceLoc(); + auto endLoc = ai->getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + origCallee, invoker, + diag::autodiff_nondifferentiable_result) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } @@ -704,9 +704,11 @@ class JVPCloner::Implementation final getModule(), jvpSubstMap, TypeExpansionContext::minimal()); differentialType = differentialType.subst(getModule(), jvpSubstMap); auto differentialFnType = differentialType.castTo(); - auto differentialSubstType = differentialPartialApply->getType().castTo(); + + // If necessary, convert the differential value to the returned differential + // function type. SILValue differentialValue; if (differentialSubstType == differentialFnType) { differentialValue = differentialPartialApply; @@ -717,11 +719,8 @@ class JVPCloner::Implementation final loc, differentialPartialApply, differentialType, /*withoutActuallyEscaping*/ false); } else { - // When `diag::autodiff_loadable_value_addressonly_tangent_unsupported` - // applies, the return type may be ABI-incomaptible with the type of the - // partially applied differential. In these cases, produce an undef and - // rely on other code to emit a diagnostic. - differentialValue = SILUndef::get(differentialType, *jvp); + llvm::report_fatal_error("Differential value type is not ABI-compatible " + "with the returned differential type"); } // Return a tuple of the original result and differential. @@ -792,7 +791,7 @@ class JVPCloner::Implementation final auto &diffBuilder = getDifferentialBuilder(); auto loc = dvi->getLoc(); auto tanVal = materializeTangent(getTangentValue(dvi->getOperand()), loc); - diffBuilder.emitDestroyValue(loc, tanVal); + diffBuilder.emitDestroyValueOperation(loc, tanVal); } CLONE_AND_EMIT_TANGENT(CopyValue, cvi) { @@ -807,7 +806,20 @@ class JVPCloner::Implementation final /// Handle `load` instruction. /// Original: y = load x /// Tangent: tan[y] = load tan[x] - CLONE_AND_EMIT_TANGENT(Load, li) { + void visitLoadInst(LoadInst *li) { + TypeSubstCloner::visitLoadInst(li); + // If an active buffer is loaded with take to a non-active value, destroy + // the active buffer's tangent buffer. + if (!differentialInfo.shouldDifferentiateInstruction(li)) { + auto isTake = + (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take); + if (isTake && activityInfo.isActive(li->getOperand(), getIndices())) { + auto &tanBuf = getTangentBuffer(li->getParent(), li->getOperand()); + getDifferentialBuilder().emitDestroyOperation(tanBuf.getLoc(), tanBuf); + } + return; + } + // Otherwise, do standard differential cloning. auto &diffBuilder = getDifferentialBuilder(); auto *bb = li->getParent(); auto loc = li->getLoc(); @@ -832,7 +844,19 @@ class JVPCloner::Implementation final /// Handle `store` instruction in the differential. /// Original: store x to y /// Tangent: store tan[x] to tan[y] - CLONE_AND_EMIT_TANGENT(Store, si) { + void visitStoreInst(StoreInst *si) { + TypeSubstCloner::visitStoreInst(si); + // If a non-active value is stored into an active buffer, zero-initialize + // the active buffer's tangent buffer. + if (!differentialInfo.shouldDifferentiateInstruction(si)) { + if (activityInfo.isActive(si->getDest(), getIndices())) { + auto &tanBufDest = getTangentBuffer(si->getParent(), si->getDest()); + emitZeroIndirect(tanBufDest->getType().getASTType(), tanBufDest, + tanBufDest.getLoc()); + } + return; + } + // Otherwise, do standard differential cloning. auto &diffBuilder = getDifferentialBuilder(); auto loc = si->getLoc(); auto tanValSrc = materializeTangent(getTangentValue(si->getSrc()), loc); @@ -844,7 +868,19 @@ class JVPCloner::Implementation final /// Handle `store_borrow` instruction in the differential. /// Original: store_borrow x to y /// Tangent: store_borrow tan[x] to tan[y] - CLONE_AND_EMIT_TANGENT(StoreBorrow, sbi) { + void visitStoreBorrowInst(StoreBorrowInst *sbi) { + TypeSubstCloner::visitStoreBorrowInst(sbi); + // If a non-active value is stored into an active buffer, zero-initialize + // the active buffer's tangent buffer. + if (!differentialInfo.shouldDifferentiateInstruction(sbi)) { + if (activityInfo.isActive(sbi->getDest(), getIndices())) { + auto &tanBufDest = getTangentBuffer(sbi->getParent(), sbi->getDest()); + emitZeroIndirect(tanBufDest->getType().getASTType(), tanBufDest, + tanBufDest.getLoc()); + } + return; + } + // Otherwise, do standard differential cloning. auto &diffBuilder = getDifferentialBuilder(); auto loc = sbi->getLoc(); auto tanValSrc = materializeTangent(getTangentValue(sbi->getSrc()), loc); @@ -855,13 +891,32 @@ class JVPCloner::Implementation final /// Handle `copy_addr` instruction. /// Original: copy_addr x to y /// Tangent: copy_addr tan[x] to tan[y] - CLONE_AND_EMIT_TANGENT(CopyAddr, cai) { + void visitCopyAddrInst(CopyAddrInst *cai) { + TypeSubstCloner::visitCopyAddrInst(cai); + // If a non-active buffer is copied into an active buffer, zero-initialize + // the destination buffer's tangent buffer. + // If an active buffer is copied with take into a non-active buffer, destroy + // the source buffer's tangent buffer. + if (!differentialInfo.shouldDifferentiateInstruction(cai)) { + if (activityInfo.isActive(cai->getDest(), getIndices())) { + auto &tanBufDest = getTangentBuffer(cai->getParent(), cai->getDest()); + emitZeroIndirect(tanBufDest->getType().getASTType(), tanBufDest, + tanBufDest.getLoc()); + } + if (cai->isTakeOfSrc() && + activityInfo.isActive(cai->getSrc(), getIndices())) { + auto &tanBufSrc = getTangentBuffer(cai->getParent(), cai->getSrc()); + getDifferentialBuilder().emitDestroyOperation(tanBufSrc.getLoc(), + tanBufSrc); + } + return; + } + // Otherwise, do standard differential cloning. auto diffBuilder = getDifferentialBuilder(); auto loc = cai->getLoc(); auto *bb = cai->getParent(); auto &tanSrc = getTangentBuffer(bb, cai->getSrc()); auto tanDest = getTangentBuffer(bb, cai->getDest()); - diffBuilder.createCopyAddr(loc, tanSrc, tanDest, cai->isTakeOfSrc(), cai->isInitializationOfDest()); } @@ -921,8 +976,8 @@ class JVPCloner::Implementation final auto &diffBuilder = getDifferentialBuilder(); auto *bb = eai->getParent(); auto loc = eai->getLoc(); - auto tanSrc = getTangentBuffer(bb, eai->getOperand()); - diffBuilder.createEndAccess(loc, tanSrc, eai->isAborting()); + auto tanOperand = getTangentBuffer(bb, eai->getOperand()); + diffBuilder.createEndAccess(loc, tanOperand, eai->isAborting()); } /// Handle `alloc_stack` instruction. @@ -933,7 +988,7 @@ class JVPCloner::Implementation final auto *mappedAllocStackInst = diffBuilder.createAllocStack( asi->getLoc(), getRemappedTangentType(asi->getElementType()), asi->getVarInfo()); - bufferMap.try_emplace({asi->getParent(), asi}, mappedAllocStackInst); + setTangentBuffer(asi->getParent(), asi, mappedAllocStackInst); } /// Handle `dealloc_stack` instruction. @@ -1065,16 +1120,15 @@ class JVPCloner::Implementation final auto tanType = getRemappedTangentType(tei->getType()); auto tanSource = materializeTangent(getTangentValue(tei->getOperand()), loc); - SILValue tanBuf; - // If the tangent buffer of the source does not have a tuple type, then + // If the tangent value of the source does not have a tuple type, then // it must represent a "single element tuple type". Use it directly. if (!tanSource->getType().is()) { setTangentValue(tei->getParent(), tei, makeConcreteTangentValue(tanSource)); } else { - tanBuf = + auto tanElt = diffBuilder.createTupleExtract(loc, tanSource, tanIndex, tanType); - bufferMap.try_emplace({tei->getParent(), tei}, tanBuf); + setTangentValue(tei->getParent(), tei, makeConcreteTangentValue(tanElt)); } } @@ -1103,7 +1157,7 @@ class JVPCloner::Implementation final tanBuf = diffBuilder.createTupleElementAddr(teai->getLoc(), tanSource, tanIndex, tanType); } - bufferMap.try_emplace({teai->getParent(), teai}, tanBuf); + setTangentBuffer(teai->getParent(), teai, tanBuf); } /// Handle `destructure_tuple` instruction. @@ -1242,6 +1296,10 @@ class JVPCloner::Implementation final SmallVector differentialAllResults; collectAllActualResultsInTypeOrder( differentialCall, differentialDirectResults, differentialAllResults); + for (auto inoutArg : ai->getInoutArguments()) + origAllResults.push_back(inoutArg); + for (auto inoutArg : differentialCall->getInoutArguments()) + differentialAllResults.push_back(inoutArg); assert(applyIndices.results->getNumIndices() == differentialAllResults.size()); @@ -1281,9 +1339,8 @@ class JVPCloner::Implementation final // Collect original results. SmallVector originalResults; collectAllDirectResultsInTypeOrder(*original, originalResults); - // Collect differential return elements. + // Collect differential direct results. SmallVector retElts; - // for (auto origResult : originalResults) { for (auto i : range(originalResults.size())) { auto origResult = originalResults[i]; if (!getIndices().results->contains(i)) @@ -1400,7 +1457,10 @@ JVPCloner::Implementation::getDifferentialStructElement(SILBasicBlock *origBB, void JVPCloner::Implementation::prepareForDifferentialGeneration() { // Create differential blocks and arguments. auto &differential = getDifferential(); + auto diffLoc = differential.getLocation(); auto *origEntry = original->getEntryBlock(); + auto origFnTy = original->getLoweredFunctionType(); + for (auto &origBB : *original) { auto *diffBB = differential.createBasicBlock(); diffBBMap.insert({&origBB, diffBB}); @@ -1481,18 +1541,51 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { << " as the tangent of original result " << *origArg); } - // Initialize tangent mapping for indirect results. - auto origIndResults = original->getIndirectResults(); + // Initialize tangent mapping for original indirect results and non-wrt + // `inout` parameters. The tangent buffers of these address values are + // differential indirect results. + + // Collect original results. + SmallVector originalResults; + collectAllFormalResultsInTypeOrder(*original, originalResults); + + // Iterate over differentiability results. + differentialBuilder.setInsertionPoint(differential.getEntryBlock()); auto diffIndResults = differential.getIndirectResults(); -#ifndef NDEBUG - unsigned numInoutParameters = llvm::count_if( - original->getLoweredFunctionType()->getParameters(), - [](SILParameterInfo paramInfo) { return paramInfo.isIndirectInOut(); }); - assert(origIndResults.size() + numInoutParameters == diffIndResults.size()); -#endif - for (auto &origBB : *original) - for (auto i : indices(origIndResults)) - setTangentBuffer(&origBB, origIndResults[i], diffIndResults[i]); + unsigned differentialIndirectResultIndex = 0; + for (auto resultIndex : getIndices().results->getIndices()) { + auto origResult = originalResults[resultIndex]; + // Handle original formal indirect result. + if (resultIndex < origFnTy->getNumResults()) { + // Skip original direct results. + if (origResult->getType().isObject()) + continue; + auto diffIndResult = diffIndResults[differentialIndirectResultIndex++]; + setTangentBuffer(origEntry, origResult, diffIndResult); + // If original indirect result is non-varied, zero-initialize its tangent + // buffer. + if (!activityInfo.isVaried(origResult, getIndices().parameters)) + emitZeroIndirect(diffIndResult->getType().getASTType(), + diffIndResult, diffLoc); + continue; + } + // Handle original non-wrt `inout` parameter. + // Only original *non-wrt* `inout` parameters have corresponding + // differential indirect results. + auto inoutParamIndex = resultIndex - origFnTy->getNumResults(); + auto inoutParamIt = std::next( + origFnTy->getIndirectMutatingParameters().begin(), inoutParamIndex); + auto paramIndex = + std::distance(origFnTy->getParameters().begin(), &*inoutParamIt); + if (getIndices().parameters->contains(paramIndex)) + continue; + auto diffIndResult = diffIndResults[differentialIndirectResultIndex++]; + setTangentBuffer(origEntry, origResult, diffIndResult); + // Original `inout` parameters are initialized, so their tangent buffers + // must also be initialized. + emitZeroIndirect(diffIndResult->getType().getASTType(), + diffIndResult, diffLoc); + } } /*static*/ SILFunction *JVPCloner::Implementation::createEmptyDifferential( @@ -1522,23 +1615,9 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { auto origParams = origTy->getParameters(); auto indices = witness->getSILAutoDiffIndices(); - // Add differential results. - Optional inoutDiffParam = None; - for (auto origParam : origTy->getParameters()) { - if (!origParam.isIndirectInOut()) - continue; - inoutDiffParam = origParam; - } - - if (inoutDiffParam) { - dfResults.push_back( - SILResultInfo(inoutDiffParam->getInterfaceType() - ->getAutoDiffTangentSpace(lookupConformance) - ->getType() - ->getCanonicalType(witnessCanGenSig), - ResultConvention::Indirect)); - } else { - for (auto resultIndex : indices.results->getIndices()) { + for (auto resultIndex : indices.results->getIndices()) { + if (resultIndex < origTy->getNumResults()) { + // Handle formal original result. auto origResult = origTy->getResults()[resultIndex]; origResult = origResult.getWithInterfaceType( origResult.getInterfaceType()->getCanonicalType(witnessCanGenSig)); @@ -1548,6 +1627,24 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { ->getType() ->getCanonicalType(witnessCanGenSig), origResult.getConvention())); + } else { + // Handle original `inout` parameter. + auto inoutParamIndex = resultIndex - origTy->getNumResults(); + auto inoutParamIt = std::next( + origTy->getIndirectMutatingParameters().begin(), inoutParamIndex); + auto paramIndex = + std::distance(origTy->getParameters().begin(), &*inoutParamIt); + // If the original `inout` parameter is a differentiability parameter, + // then it already has a corresponding differential parameter. Do not add + // a corresponding differential result. + if (indices.parameters->contains(paramIndex)) + continue; + auto inoutParam = origTy->getParameters()[paramIndex]; + auto paramTan = inoutParam.getInterfaceType()->getAutoDiffTangentSpace( + lookupConformance); + assert(paramTan && "Parameter type does not have a tangent space?"); + dfResults.push_back( + {paramTan->getCanonicalType(), ResultConvention::Indirect}); } } diff --git a/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp b/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp index 4582c20521d6d..8fe0323a91315 100644 --- a/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp +++ b/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp @@ -141,8 +141,6 @@ LinearMapInfo::createBranchingTraceDecl(SILBasicBlock *originalBB, if (genericSig) branchingTraceDecl->setGenericSignature(genericSig); computeAccessLevel(branchingTraceDecl, original->getEffectiveSymbolLinkage()); - branchingTraceDecl->getInterfaceType(); - assert(branchingTraceDecl->hasInterfaceType()); file.addTopLevelDecl(branchingTraceDecl); // Add basic block enum cases. for (auto *predBB : originalBB->getPredecessorBlocks()) { @@ -165,7 +163,6 @@ LinearMapInfo::createBranchingTraceDecl(SILBasicBlock *originalBB, /*IdentifierLoc*/ loc, DeclName(astCtx.getIdentifier(bbId)), paramList, loc, /*RawValueExpr*/ nullptr, branchingTraceDecl); enumEltDecl->setImplicit(); - enumEltDecl->getInterfaceType(); auto *enumCaseDecl = EnumCaseDecl::create( /*CaseLoc*/ loc, {enumEltDecl}, branchingTraceDecl); enumCaseDecl->setImplicit(); @@ -207,8 +204,6 @@ LinearMapInfo::createLinearMapStruct(SILBasicBlock *originalBB, if (genericSig) linearMapStruct->setGenericSignature(genericSig); computeAccessLevel(linearMapStruct, original->getEffectiveSymbolLinkage()); - linearMapStruct->getInterfaceType(); - assert(linearMapStruct->hasInterfaceType()); file.addTopLevelDecl(linearMapStruct); return linearMapStruct; } @@ -460,7 +455,8 @@ void LinearMapInfo::generateDifferentiationDataStructures( /// 3. The instruction has both an active result (direct or indirect) and an /// active argument. bool LinearMapInfo::shouldDifferentiateApplySite(FullApplySite applySite) { - // Function applications with an inout argument should be differentiated. + // Function applications with an active inout argument should be + // differentiated. for (auto inoutArg : applySite.getInoutArguments()) if (activityInfo.isActive(inoutArg, indices)) return true; diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index 79611c38eaaf4..d018f274a7f11 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -562,7 +562,7 @@ class PullbackCloner::Implementation final /// /// This method first tries to find an existing entry in the adjoint buffer /// mapping. If no entry exists, creates a zero adjoint buffer. - SILValue &getAdjointBuffer(SILBasicBlock *origBB, SILValue originalValue) { + SILValue getAdjointBuffer(SILBasicBlock *origBB, SILValue originalValue) { assert(getTangentValueCategory(originalValue) == SILValueCategory::Address); assert(originalValue->getFunction() == &getOriginal()); auto insertion = bufferMap.try_emplace({origBB, originalValue}, SILValue()); @@ -1011,28 +1011,68 @@ class PullbackCloner::Implementation final auto *bb = si->getParent(); auto loc = si->getLoc(); auto *structDecl = si->getStructDecl(); - auto av = getAdjointValue(bb, si); - switch (av.getKind()) { - case AdjointValueKind::Zero: - for (auto *field : structDecl->getStoredProperties()) { - auto fv = si->getFieldValue(field); - addAdjointValue( - bb, fv, makeZeroAdjointValue(getRemappedTangentType(fv->getType())), - loc); + switch (getTangentValueCategory(si)) { + case SILValueCategory::Object: { + auto av = getAdjointValue(bb, si); + switch (av.getKind()) { + case AdjointValueKind::Zero: { + for (auto *field : structDecl->getStoredProperties()) { + auto fv = si->getFieldValue(field); + addAdjointValue( + bb, fv, + makeZeroAdjointValue(getRemappedTangentType(fv->getType())), loc); + } + break; } - break; - case AdjointValueKind::Concrete: { - auto adjStruct = materializeAdjointDirect(std::move(av), loc); - auto *dti = builder.createDestructureStruct(si->getLoc(), adjStruct); + case AdjointValueKind::Concrete: { + auto adjStruct = materializeAdjointDirect(std::move(av), loc); + auto *dti = builder.createDestructureStruct(si->getLoc(), adjStruct); - // Find the struct `TangentVector` type. - auto structTy = remapType(si->getType()).getASTType(); + // Find the struct `TangentVector` type. + auto structTy = remapType(si->getType()).getASTType(); #ifndef NDEBUG - auto tangentVectorTy = getTangentSpace(structTy)->getCanonicalType(); - assert(!getTypeLowering(tangentVectorTy).isAddressOnly()); - assert(tangentVectorTy->getStructOrBoundGenericStruct()); + auto tangentVectorTy = getTangentSpace(structTy)->getCanonicalType(); + assert(!getTypeLowering(tangentVectorTy).isAddressOnly()); + assert(tangentVectorTy->getStructOrBoundGenericStruct()); #endif + // Accumulate adjoints for the fields of the `struct` operand. + unsigned fieldIndex = 0; + for (auto it = structDecl->getStoredProperties().begin(); + it != structDecl->getStoredProperties().end(); + ++it, ++fieldIndex) { + VarDecl *field = *it; + if (field->getAttrs().hasAttribute()) + continue; + // Find the corresponding field in the tangent space. + auto *tanField = getTangentStoredProperty( + getContext(), field, structTy, loc, getInvoker()); + if (!tanField) { + errorOccurred = true; + return; + } + auto tanElt = dti->getResult(fieldIndex); + addAdjointValue(bb, si->getFieldValue(field), + makeConcreteAdjointValue(tanElt), si->getLoc()); + } + break; + } + case AdjointValueKind::Aggregate: { + // Note: All user-called initializations go through the calls to the + // initializer, and synthesized initializers only have one level of + // struct formation which will not result into any aggregate adjoint + // valeus. + llvm_unreachable( + "Aggregate adjoint values should not occur for `struct` " + "instructions"); + } + } + break; + } + case SILValueCategory::Address: { + auto adjBuf = getAdjointBuffer(bb, si); + // Find the struct `TangentVector` type. + auto structTy = remapType(si->getType()).getASTType(); // Accumulate adjoints for the fields of the `struct` operand. unsigned fieldIndex = 0; for (auto it = structDecl->getStoredProperties().begin(); @@ -1047,19 +1087,25 @@ class PullbackCloner::Implementation final errorOccurred = true; return; } - auto tanElt = dti->getResult(fieldIndex); - addAdjointValue(bb, si->getFieldValue(field), - makeConcreteAdjointValue(tanElt), si->getLoc()); + auto *adjFieldBuf = + builder.createStructElementAddr(loc, adjBuf, tanField); + auto fieldValue = si->getFieldValue(field); + switch (getTangentValueCategory(fieldValue)) { + case SILValueCategory::Object: { + auto adjField = builder.emitLoadValueOperation( + loc, adjFieldBuf, LoadOwnershipQualifier::Copy); + recordTemporary(adjField); + addAdjointValue(bb, fieldValue, makeConcreteAdjointValue(adjField), + loc); + break; + } + case SILValueCategory::Address: { + addToAdjointBuffer(bb, fieldValue, adjFieldBuf, loc); + break; + } + } } - break; - } - case AdjointValueKind::Aggregate: { - // Note: All user-called initializations go through the calls to the - // initializer, and synthesized initializers only have one level of struct - // formation which will not result into any aggregate adjoint valeus. - llvm_unreachable("Aggregate adjoint values should not occur for `struct` " - "instructions"); - } + } break; } } @@ -1071,41 +1117,75 @@ class PullbackCloner::Implementation final void visitStructExtractInst(StructExtractInst *sei) { auto *bb = sei->getParent(); auto loc = getValidLocation(sei); - auto structTy = remapType(sei->getOperand()->getType()).getASTType(); - auto tangentVectorTy = getTangentSpace(structTy)->getCanonicalType(); - assert(!getTypeLowering(tangentVectorTy).isAddressOnly()); - auto tangentVectorSILTy = SILType::getPrimitiveObjectType(tangentVectorTy); - auto *tangentVectorDecl = tangentVectorTy->getStructOrBoundGenericStruct(); - assert(tangentVectorDecl); // Find the corresponding field in the tangent space. + auto structTy = remapType(sei->getOperand()->getType()).getASTType(); auto *tanField = getTangentStoredProperty(getContext(), sei, structTy, getInvoker()); - assert(tanField && "Invalid projections should have been diagnosed"); - // Accumulate adjoint for the `struct_extract` operand. - auto av = getAdjointValue(bb, sei); - switch (av.getKind()) { - case AdjointValueKind::Zero: - addAdjointValue(bb, sei->getOperand(), - makeZeroAdjointValue(tangentVectorSILTy), loc); - break; - case AdjointValueKind::Concrete: - case AdjointValueKind::Aggregate: { - SmallVector eltVals; - for (auto *field : tangentVectorDecl->getStoredProperties()) { - if (field == tanField) { - eltVals.push_back(av); - } else { - auto substMap = tangentVectorTy->getMemberSubstitutionMap( - field->getModuleContext(), field); - auto fieldTy = field->getType().subst(substMap); - auto fieldSILTy = getTypeLowering(fieldTy).getLoweredType(); - assert(fieldSILTy.isObject()); - eltVals.push_back(makeZeroAdjointValue(fieldSILTy)); + // Check the `struct_extract` operand's value tangent category. + switch (getTangentValueCategory(sei->getOperand())) { + case SILValueCategory::Object: { + auto tangentVectorTy = getTangentSpace(structTy)->getCanonicalType(); + auto *tangentVectorDecl = + tangentVectorTy->getStructOrBoundGenericStruct(); + assert(tangentVectorDecl); + auto tangentVectorSILTy = + SILType::getPrimitiveObjectType(tangentVectorTy); + assert(tanField && "Invalid projections should have been diagnosed"); + // Accumulate adjoint for the `struct_extract` operand. + auto av = getAdjointValue(bb, sei); + switch (av.getKind()) { + case AdjointValueKind::Zero: + addAdjointValue(bb, sei->getOperand(), + makeZeroAdjointValue(tangentVectorSILTy), loc); + break; + case AdjointValueKind::Concrete: + case AdjointValueKind::Aggregate: { + SmallVector eltVals; + for (auto *field : tangentVectorDecl->getStoredProperties()) { + if (field == tanField) { + eltVals.push_back(av); + } else { + auto substMap = tangentVectorTy->getMemberSubstitutionMap( + field->getModuleContext(), field); + auto fieldTy = field->getType().subst(substMap); + auto fieldSILTy = getTypeLowering(fieldTy).getLoweredType(); + assert(fieldSILTy.isObject()); + eltVals.push_back(makeZeroAdjointValue(fieldSILTy)); + } } + addAdjointValue(bb, sei->getOperand(), + makeAggregateAdjointValue(tangentVectorSILTy, eltVals), + loc); } - addAdjointValue(bb, sei->getOperand(), - makeAggregateAdjointValue(tangentVectorSILTy, eltVals), - loc); + } + break; + } + case SILValueCategory::Address: { + auto adjBase = getAdjointBuffer(bb, sei->getOperand()); + auto *adjBaseElt = + builder.createStructElementAddr(loc, adjBase, tanField); + // Check the `struct_extract`'s value tangent category. + switch (getTangentValueCategory(sei)) { + case SILValueCategory::Object: { + auto adjElt = getAdjointValue(bb, sei); + auto concreteAdjElt = materializeAdjointDirect(adjElt, loc); + auto concreteAdjEltCopy = + builder.emitCopyValueOperation(loc, concreteAdjElt); + auto *alloc = builder.createAllocStack(loc, adjElt.getType()); + builder.emitStoreValueOperation(loc, concreteAdjEltCopy, alloc, + StoreOwnershipQualifier::Init); + accumulateIndirect(adjBaseElt, alloc, loc); + builder.createDestroyAddr(loc, alloc); + builder.createDeallocStack(loc, alloc); + break; + } + case SILValueCategory::Address: { + auto adjElt = getAdjointBuffer(bb, sei); + accumulateIndirect(adjBaseElt, adjElt, loc); + break; + } + } + break; } } } @@ -1171,52 +1251,73 @@ class PullbackCloner::Implementation final /// excluding non-differentiable elements void visitTupleInst(TupleInst *ti) { auto *bb = ti->getParent(); - auto av = getAdjointValue(bb, ti); - switch (av.getKind()) { - case AdjointValueKind::Zero: - for (auto elt : ti->getElements()) { - if (!getTangentSpace(elt->getType().getASTType())) - continue; - addAdjointValue( - bb, elt, - makeZeroAdjointValue(getRemappedTangentType(elt->getType())), - ti->getLoc()); + auto loc = ti->getLoc(); + switch (getTangentValueCategory(ti)) { + case SILValueCategory::Object: { + auto av = getAdjointValue(bb, ti); + switch (av.getKind()) { + case AdjointValueKind::Zero: + for (auto elt : ti->getElements()) { + if (!getTangentSpace(elt->getType().getASTType())) + continue; + addAdjointValue( + bb, elt, + makeZeroAdjointValue(getRemappedTangentType(elt->getType())), + loc); + } + break; + case AdjointValueKind::Concrete: { + auto adjVal = av.getConcreteValue(); + auto adjValCopy = builder.emitCopyValueOperation(loc, adjVal); + SmallVector adjElts; + if (!adjVal->getType().getAs()) { + recordTemporary(adjValCopy); + adjElts.push_back(adjValCopy); + } else { + auto *dti = builder.createDestructureTuple(loc, adjValCopy); + for (auto adjElt : dti->getResults()) + recordTemporary(adjElt); + adjElts.append(dti->getResults().begin(), dti->getResults().end()); + } + // Accumulate adjoints for `tuple` operands, skipping the + // non-`Differentiable` ones. + unsigned adjIndex = 0; + for (auto i : range(ti->getNumOperands())) { + if (!getTangentSpace(ti->getOperand(i)->getType().getASTType())) + continue; + auto adjElt = adjElts[adjIndex++]; + addAdjointValue(bb, ti->getOperand(i), + makeConcreteAdjointValue(adjElt), loc); + } + break; } - break; - case AdjointValueKind::Concrete: { - auto adjVal = av.getConcreteValue(); - unsigned adjIdx = 0; - auto adjValCopy = builder.emitCopyValueOperation(ti->getLoc(), adjVal); - SmallVector adjElts; - if (!adjVal->getType().getAs()) { - recordTemporary(adjValCopy); - adjElts.push_back(adjValCopy); - } else { - auto *dti = builder.createDestructureTuple(ti->getLoc(), adjValCopy); - for (auto adjElt : dti->getResults()) - recordTemporary(adjElt); - adjElts.append(dti->getResults().begin(), dti->getResults().end()); + case AdjointValueKind::Aggregate: + unsigned adjIndex = 0; + for (auto i : range(ti->getElements().size())) { + if (!getTangentSpace(ti->getElement(i)->getType().getASTType())) + continue; + addAdjointValue(bb, ti->getElement(i), + av.getAggregateElement(adjIndex++), loc); + } + break; } + break; + } + case SILValueCategory::Address: { + auto adjBuf = getAdjointBuffer(bb, ti); // Accumulate adjoints for `tuple` operands, skipping the - // non-differentiable ones. + // non-`Differentiable` ones. + unsigned adjIndex = 0; for (auto i : range(ti->getNumOperands())) { if (!getTangentSpace(ti->getOperand(i)->getType().getASTType())) continue; - auto adjElt = adjElts[adjIdx++]; - addAdjointValue(bb, ti->getOperand(i), makeConcreteAdjointValue(adjElt), - ti->getLoc()); + auto adjBufElt = + builder.createTupleElementAddr(loc, adjBuf, adjIndex++); + auto adjElt = getAdjointBuffer(bb, ti->getOperand(i)); + accumulateIndirect(adjElt, adjBufElt, loc); } break; } - case AdjointValueKind::Aggregate: - unsigned adjIdx = 0; - for (auto i : range(ti->getElements().size())) { - if (!getTangentSpace(ti->getElement(i)->getType().getASTType())) - continue; - addAdjointValue(bb, ti->getElement(i), av.getAggregateElement(adjIdx++), - ti->getLoc()); - } - break; } } @@ -1276,26 +1377,58 @@ class PullbackCloner::Implementation final /// adj[x].n += adj[yn] void visitDestructureTupleInst(DestructureTupleInst *dti) { auto *bb = dti->getParent(); + auto loc = dti->getLoc(); auto tupleTanTy = getRemappedTangentType(dti->getOperand()->getType()); - SmallVector adjValues; - for (auto origElt : dti->getResults()) { - if (!getTangentSpace(remapType(origElt->getType()).getASTType())) - continue; - adjValues.push_back(getAdjointValue(bb, origElt)); + // Check the `destructure_tuple` operand's value tangent category. + switch (getTangentValueCategory(dti->getOperand())) { + case SILValueCategory::Object: { + SmallVector adjValues; + for (auto origElt : dti->getResults()) { + // Skip non-`Differentiable` tuple elements. + if (!getTangentSpace(remapType(origElt->getType()).getASTType())) + continue; + adjValues.push_back(getAdjointValue(bb, origElt)); + } + // Handle tuple tangent type. + // Add adjoints for every tuple element that has a tangent space. + if (tupleTanTy.is()) { + assert(adjValues.size() > 1); + addAdjointValue(bb, dti->getOperand(), + makeAggregateAdjointValue(tupleTanTy, adjValues), loc); + } + // Handle non-tuple tangent type. + // Add adjoint for the single tuple element that has a tangent space. + else { + assert(adjValues.size() == 1); + addAdjointValue(bb, dti->getOperand(), adjValues.front(), loc); + } + break; } - // Handle tuple tangent type. - // Add adjoints for every tuple element that has a tangent space. - if (tupleTanTy.is()) { - assert(adjValues.size() > 1); - addAdjointValue(bb, dti->getOperand(), - makeAggregateAdjointValue(tupleTanTy, adjValues), - dti->getLoc()); + case SILValueCategory::Address: { + auto adjBuf = getAdjointBuffer(bb, dti->getOperand()); + unsigned adjIndex = 0; + for (auto origElt : dti->getResults()) { + // Skip non-`Differentiable` tuple elements. + if (!getTangentSpace(remapType(origElt->getType()).getASTType())) + continue; + // Handle tuple tangent type. + // Add adjoints for every tuple element that has a tangent space. + if (tupleTanTy.is()) { + auto adjEltBuf = getAdjointBuffer(bb, origElt); + auto adjBufElt = + builder.createTupleElementAddr(loc, adjBuf, adjIndex); + accumulateIndirect(adjBufElt, adjEltBuf, loc); + } + // Handle non-tuple tangent type. + // Add adjoint for the single tuple element that has a tangent space. + else { + auto adjEltBuf = getAdjointBuffer(bb, origElt); + addToAdjointBuffer(bb, dti->getOperand(), adjEltBuf, loc); + } + ++adjIndex; + } + break; } - // Handle non-tuple tangent type. - // Add adjoint for the single tuple element that has a tangent space. - else { - assert(adjValues.size() == 1); - addAdjointValue(bb, dti->getOperand(), adjValues.front(), dti->getLoc()); } } @@ -1337,7 +1470,7 @@ class PullbackCloner::Implementation final /// Adjoint: adj[x] += load adj[y]; adj[y] = 0 void visitStoreOperation(SILBasicBlock *bb, SILLocation loc, SILValue origSrc, SILValue origDest) { - auto &adjBuf = getAdjointBuffer(bb, origDest); + auto adjBuf = getAdjointBuffer(bb, origDest); switch (getTangentValueCategory(origSrc)) { case SILValueCategory::Object: { auto adjVal = builder.emitLoadValueOperation( @@ -1369,7 +1502,7 @@ class PullbackCloner::Implementation final /// Adjoint: adj[x] += adj[y]; adj[y] = 0 void visitCopyAddrInst(CopyAddrInst *cai) { auto *bb = cai->getParent(); - auto &adjDest = getAdjointBuffer(bb, cai->getDest()); + auto adjDest = getAdjointBuffer(bb, cai->getDest()); auto destType = remapType(adjDest->getType()); addToAdjointBuffer(bb, cai->getSrc(), adjDest, cai->getLoc()); builder.emitDestroyAddrAndFold(cai->getLoc(), adjDest); @@ -1388,7 +1521,7 @@ class PullbackCloner::Implementation final break; } case SILValueCategory::Address: { - auto &adjDest = getAdjointBuffer(bb, cvi); + auto adjDest = getAdjointBuffer(bb, cvi); auto destType = remapType(adjDest->getType()); addToAdjointBuffer(bb, cvi->getOperand(), adjDest, cvi->getLoc()); builder.emitDestroyAddrAndFold(cvi->getLoc(), adjDest); @@ -1410,7 +1543,7 @@ class PullbackCloner::Implementation final break; } case SILValueCategory::Address: { - auto &adjDest = getAdjointBuffer(bb, bbi); + auto adjDest = getAdjointBuffer(bb, bbi); auto destType = remapType(adjDest->getType()); addToAdjointBuffer(bb, bbi->getOperand(), adjDest, bbi->getLoc()); builder.emitDestroyAddrAndFold(bbi->getLoc(), adjDest); @@ -1449,8 +1582,8 @@ class PullbackCloner::Implementation final void visitUnconditionalCheckedCastAddrInst( UnconditionalCheckedCastAddrInst *uccai) { auto *bb = uccai->getParent(); - auto &adjDest = getAdjointBuffer(bb, uccai->getDest()); - auto &adjSrc = getAdjointBuffer(bb, uccai->getSrc()); + auto adjDest = getAdjointBuffer(bb, uccai->getDest()); + auto adjSrc = getAdjointBuffer(bb, uccai->getSrc()); auto destType = remapType(adjDest->getType()); auto castBuf = builder.createAllocStack(uccai->getLoc(), adjSrc->getType()); builder.createUnconditionalCheckedCastAddr( @@ -1479,7 +1612,7 @@ class PullbackCloner::Implementation final break; } case SILValueCategory::Address: { - auto &adjDest = getAdjointBuffer(bb, urci); + auto adjDest = getAdjointBuffer(bb, urci); auto destType = remapType(adjDest->getType()); addToAdjointBuffer(bb, urci->getOperand(), adjDest, urci->getLoc()); builder.emitDestroyAddrAndFold(urci->getLoc(), adjDest); @@ -1506,7 +1639,7 @@ class PullbackCloner::Implementation final break; } case SILValueCategory::Address: { - auto &adjDest = getAdjointBuffer(bb, ui); + auto adjDest = getAdjointBuffer(bb, ui); auto destType = remapType(adjDest->getType()); addToAdjointBuffer(bb, ui->getOperand(), adjDest, ui->getLoc()); builder.emitDestroyAddrAndFold(ui->getLoc(), adjDest); @@ -1721,22 +1854,36 @@ bool PullbackCloner::Implementation::run() { domOrder.pushChildren(bb); } - // Create pullback blocks and arguments, visiting original blocks in - // post-order post-dominance order. - SmallVector postOrderPostDomOrder; - // Start from the root node, which may have a marker `nullptr` block if - // there are multiple roots. - PostOrderPostDominanceOrder postDomOrder(postDomInfo->getRootNode(), - postOrderInfo, original.size()); - while (auto *origNode = postDomOrder.getNext()) { - auto *origBB = origNode->getBlock(); - postDomOrder.pushChildren(origNode); - // If node is the `nullptr` marker basic block, do not push it. - if (!origBB) - continue; - postOrderPostDomOrder.push_back(origBB); + // Create pullback blocks and arguments, visiting original blocks using BFS + // starting from the original exit block. Unvisited original basic blocks + // (e.g unreachable blocks) are not relevant for pullback generation and thus + // ignored. + // The original blocks in traversal order for pullback generation. + SmallVector originalBlocks; + // The set of visited original blocks. + SmallDenseSet visitedBlocks; + + // Perform BFS from the original exit block. + { + std::deque worklist = {}; + worklist.push_back(origExit); + visitedBlocks.insert(origExit); + while (!worklist.empty()) { + auto *BB = worklist.front(); + worklist.pop_front(); + + originalBlocks.push_back(BB); + + for (auto *nextBB : BB->getPredecessorBlocks()) { + if (!visitedBlocks.count(nextBB)) { + worklist.push_back(nextBB); + visitedBlocks.insert(nextBB); + } + } + } } - for (auto *origBB : postOrderPostDomOrder) { + + for (auto *origBB : originalBlocks) { auto *pullbackBB = pullback.createBasicBlock(); pullbackBBMap.insert({origBB, pullbackBB}); auto pbStructLoweredType = @@ -1801,6 +1948,9 @@ bool PullbackCloner::Implementation::run() { // struct argument. They branch from a pullback successor block to the // pullback original block, passing adjoint values of active values. for (auto *succBB : origBB->getSuccessorBlocks()) { + // Skip generating pullback block for original unreachable blocks. + if (!visitedBlocks.count(succBB)) + continue; auto *pullbackTrampolineBB = pullback.createBasicBlockBefore(pullbackBB); pullbackTrampolineBBMap.insert({{origBB, succBB}, pullbackTrampolineBB}); // Get the enum element type (i.e. the pullback struct type). The enum @@ -1870,7 +2020,7 @@ bool PullbackCloner::Implementation::run() { // Visit original blocks blocks in post-order and perform differentiation // in corresponding pullback blocks. If errors occurred, back out. else { - for (auto *bb : postOrderPostDomOrder) { + for (auto *bb : originalBlocks) { visitSILBasicBlock(bb); if (errorOccurred) return true; @@ -2018,12 +2168,10 @@ void PullbackCloner::Implementation::accumulateAdjointForOptional( SILBasicBlock *bb, SILValue optionalValue, SILValue wrappedAdjoint) { auto pbLoc = getPullback().getLocation(); // Handle `switch_enum` on `Optional`. - auto *optionalEnumDecl = getASTContext().getOptionalDecl(); - auto optionalTy = optionalValue->getType(); - assert(optionalTy.getASTType().getEnumOrBoundGenericEnum() == - optionalEnumDecl); // `Optional` - optionalTy = remapType(optionalTy); + auto optionalTy = remapType(optionalValue->getType()); + assert(optionalTy.getASTType().getEnumOrBoundGenericEnum() == + getASTContext().getOptionalDecl()); // `T` auto wrappedType = optionalTy.getOptionalObjectType(); // `T.TangentVector` @@ -2056,8 +2204,8 @@ void PullbackCloner::Implementation::accumulateAdjointForOptional( // Find `Optional.some` EnumElementDecl. auto someEltDecl = builder.getASTContext().getOptionalSomeDecl(); - // Initialize a `Optional` buffer from `wrappedAdjoint`as the - // input for `Optional.TangentVector.init`. + // Initialize an `Optional` buffer from `wrappedAdjoint` as + // the input for `Optional.TangentVector.init`. auto *optArgBuf = builder.createAllocStack(pbLoc, optionalOfWrappedTanType); if (optionalOfWrappedTanType.isLoadableOrOpaque(builder.getFunction())) { // %enum = enum $Optional, #Optional.some!enumelt, @@ -2066,7 +2214,7 @@ void PullbackCloner::Implementation::accumulateAdjointForOptional( optionalOfWrappedTanType); // store %enum to %optArgBuf builder.emitStoreValueOperation(pbLoc, enumInst, optArgBuf, - StoreOwnershipQualifier::Trivial); + StoreOwnershipQualifier::Init); } else { // %enumAddr = init_enum_data_addr %optArgBuf $Optional, // #Optional.some!enumelt @@ -2279,14 +2427,15 @@ void PullbackCloner::Implementation::visitSILBasicBlock(SILBasicBlock *bb) { for (auto pair : incomingValues) { auto *predBB = std::get<0>(pair); auto incomingValue = std::get<1>(pair); - blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy); // Handle `switch_enum` on `Optional`. auto termInst = bbArg->getSingleTerminator(); - if (isSwitchEnumInstOnOptional(termInst)) + if (isSwitchEnumInstOnOptional(termInst)) { accumulateAdjointForOptional(bb, incomingValue, concreteBBArgAdjCopy); - else + } else { + blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy); setAdjointValue(predBB, incomingValue, makeConcreteAdjointValue(concreteBBArgAdjCopy)); + } } break; } @@ -2413,7 +2562,7 @@ bool PullbackCloner::Implementation::runForSemanticMemberGetter() { // Switch based on the base tangent struct's value category. // TODO(TF-1255): Simplify using unified adjoint value data structure. - switch (tangentVectorSILTy.getCategory()) { + switch (getTangentValueCategory(origSelf)) { case SILValueCategory::Object: { auto adjResult = getAdjointValue(origEntry, origResult); switch (adjResult.getKind()) { @@ -2454,7 +2603,7 @@ bool PullbackCloner::Implementation::runForSemanticMemberGetter() { if (field == tanField) { // Switch based on the property's value category. // TODO(TF-1255): Simplify using unified adjoint value data structure. - switch (origResult->getType().getCategory()) { + switch (getTangentValueCategory(origResult)) { case SILValueCategory::Object: { auto adjResult = getAdjointValue(origEntry, origResult); auto adjResultValue = materializeAdjointDirect(adjResult, pbLoc); diff --git a/lib/SILOptimizer/Differentiation/Thunk.cpp b/lib/SILOptimizer/Differentiation/Thunk.cpp index 820805fff06d9..a59dc092302e5 100644 --- a/lib/SILOptimizer/Differentiation/Thunk.cpp +++ b/lib/SILOptimizer/Differentiation/Thunk.cpp @@ -249,6 +249,58 @@ CanSILFunctionType buildThunkType(SILFunction *fn, fn->getASTContext()); } +/// Forward function arguments, handling ownership convention mismatches. +/// Adapted from `forwardFunctionArguments` in SILGenPoly.cpp. +/// +/// Forwarded arguments are appended to `forwardedArgs`. +/// +/// Local allocations are appended to `localAllocations`. They need to be +/// deallocated via `dealloc_stack`. +/// +/// Local values requiring cleanup are appended to `valuesToCleanup`. +static void forwardFunctionArgumentsConvertingOwnership( + SILBuilder &builder, SILLocation loc, CanSILFunctionType fromTy, + CanSILFunctionType toTy, ArrayRef originalArgs, + SmallVectorImpl &forwardedArgs, + SmallVectorImpl &localAllocations, + SmallVectorImpl &valuesToCleanup) { + auto fromParameters = fromTy->getParameters(); + auto toParameters = toTy->getParameters(); + assert(fromParameters.size() == toParameters.size()); + assert(fromParameters.size() == originalArgs.size()); + for (auto index : indices(originalArgs)) { + auto &arg = originalArgs[index]; + auto fromParam = fromParameters[index]; + auto toParam = toParameters[index]; + // To convert guaranteed argument to be owned, create a copy. + if (fromParam.isConsumed() && !toParam.isConsumed()) { + // If the argument has an object type, create a `copy_value`. + if (arg->getType().isObject()) { + auto argCopy = builder.emitCopyValueOperation(loc, arg); + forwardedArgs.push_back(argCopy); + continue; + } + // If the argument has an address type, create a local allocation and + // `copy_addr` its contents to the local allocation. + auto *alloc = builder.createAllocStack(loc, arg->getType()); + builder.createCopyAddr(loc, arg, alloc, IsNotTake, IsInitialization); + localAllocations.push_back(alloc); + forwardedArgs.push_back(alloc); + continue; + } + // To convert owned argument to be guaranteed, borrow the argument. + if (fromParam.isGuaranteed() && !toParam.isGuaranteed()) { + auto bbi = builder.emitBeginBorrowOperation(loc, arg); + forwardedArgs.push_back(bbi); + valuesToCleanup.push_back(bbi); + valuesToCleanup.push_back(arg); + continue; + } + // Otherwise, simply forward the argument. + forwardedArgs.push_back(arg); + } +} + SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, SILModule &module, SILLocation loc, SILFunction *caller, @@ -274,18 +326,13 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, thunkType, fromInterfaceType, toInterfaceType, Type(), module.getSwiftModule()); - // FIXME(TF-989): Mark reabstraction thunks as transparent. This requires - // generating ossa reabstraction thunks so that they can be inlined during - // mandatory inlining when `-enable-strip-ownership-after-serialization` is - // true and ownership model eliminator is not run after differentiation. auto *thunk = fb.getOrCreateSharedFunction( - loc, name, thunkDeclType, IsBare, IsNotTransparent, IsSerialized, + loc, name, thunkDeclType, IsBare, IsTransparent, IsSerialized, ProfileCounter(), IsReabstractionThunk, IsNotDynamic); if (!thunk->empty()) return thunk; thunk->setGenericEnvironment(genericEnv); - thunk->setOwnershipEliminated(); auto *entry = thunk->createBasicBlock(); SILBuilder builder(entry); createEntryArguments(thunk); @@ -294,13 +341,21 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, SILFunctionConventions toConv(toType, module); assert(toConv.useLoweredAddresses()); - auto *fnArg = thunk->getArgumentsWithoutIndirectResults().back(); + // Forward thunk arguments, handling ownership convention mismatches. + SmallVector forwardedArgs; + for (auto indRes : thunk->getIndirectResults()) + forwardedArgs.push_back(indRes); + SmallVector localAllocations; + SmallVector valuesToCleanup; + forwardFunctionArgumentsConvertingOwnership( + builder, loc, fromType, toType, + thunk->getArgumentsWithoutIndirectResults().drop_back(), forwardedArgs, + localAllocations, valuesToCleanup); SmallVector arguments; - auto toArgIter = thunk->getArguments().begin(); + auto toArgIter = forwardedArgs.begin(); auto useNextArgument = [&]() { arguments.push_back(*toArgIter++); }; - SmallVector localAllocations; auto createAllocStack = [&](SILType type) { auto *alloc = builder.createAllocStack(loc, type); localAllocations.push_back(alloc); @@ -350,21 +405,25 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, if (!paramTy.hasArchetype()) paramTy = thunk->mapTypeIntoContext(paramTy); assert(paramTy.isAddress()); - auto *toArg = *toArgIter++; + auto toArg = *toArgIter++; auto *buf = createAllocStack(toArg->getType()); - builder.createStore(loc, toArg, buf, - StoreOwnershipQualifier::Unqualified); + toArg = builder.emitCopyValueOperation(loc, toArg); + builder.emitStoreValueOperation(loc, toArg, buf, + StoreOwnershipQualifier::Init); + valuesToCleanup.push_back(buf); arguments.push_back(buf); continue; } // Convert direct parameter to indirect parameter. assert(toParam.isFormalIndirect()); - auto *toArg = *toArgIter++; - auto *load = - builder.createLoad(loc, toArg, LoadOwnershipQualifier::Unqualified); + auto toArg = *toArgIter++; + auto load = builder.emitLoadBorrowOperation(loc, toArg); + if (isa(load)) + valuesToCleanup.push_back(load); arguments.push_back(load); } + auto *fnArg = thunk->getArgumentsWithoutIndirectResults().back(); auto *apply = builder.createApply(loc, fnArg, SubstitutionMap(), arguments, /*isNonThrowing*/ false); @@ -413,8 +472,8 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, // Load direct results from indirect results. if (fromRes.isFormalIndirect()) { auto indRes = *fromIndResultsIter++; - auto *load = - builder.createLoad(loc, indRes, LoadOwnershipQualifier::Unqualified); + auto load = builder.emitLoadValueOperation(loc, indRes, + LoadOwnershipQualifier::Take); results.push_back(load); continue; } @@ -426,11 +485,28 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, assert(resultTy.isAddress()); #endif auto indRes = *toIndResultsIter++; - builder.createStore(loc, *fromDirResultsIter++, indRes, - StoreOwnershipQualifier::Unqualified); + auto dirRes = *fromDirResultsIter++; + builder.emitStoreValueOperation(loc, dirRes, indRes, + StoreOwnershipQualifier::Init); } auto retVal = joinElements(results, builder, loc); + // Clean up local values. + // Guaranteed values need an `end_borrow`. + // Owned values need to be destroyed. + for (auto arg : valuesToCleanup) { + switch (arg.getOwnershipKind()) { + case ValueOwnershipKind::Guaranteed: + builder.emitEndBorrowOperation(loc, arg); + break; + case ValueOwnershipKind::Owned: + case ValueOwnershipKind::Unowned: + case ValueOwnershipKind::None: + builder.emitDestroyOperation(loc, arg); + break; + } + } + // Deallocate local allocations. for (auto *alloc : llvm::reverse(localAllocations)) builder.createDeallocStack(loc, alloc); @@ -549,11 +625,11 @@ getOrCreateSubsetParametersThunkForLinearMap( auto *buf = builder.createAllocStack(loc, zeroSILObjType); localAllocations.push_back(buf); emitZeroIntoBuffer(builder, zeroType, buf, loc); - if (zeroSILType.isAddress()) + if (zeroSILType.isAddress()) { arguments.push_back(buf); - else { - auto *arg = - builder.createLoad(loc, buf, LoadOwnershipQualifier::Unqualified); + } else { + auto arg = builder.emitLoadValueOperation(loc, buf, + LoadOwnershipQualifier::Take); arguments.push_back(arg); } break; @@ -810,8 +886,6 @@ getOrCreateSubsetParametersThunkForDerivativeFunction( if (!thunk->empty()) return {thunk, interfaceSubs}; - // TODO(TF-1206): Enable ownership in all differentiation thunks. - thunk->setOwnershipEliminated(); thunk->setGenericEnvironment(genericEnv); auto *entry = thunk->createBasicBlock(); SILBuilder builder(entry); diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index ef3980436d9d1..d28fb859a9093 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -201,9 +201,11 @@ class VJPCloner::Implementation final getModule(), vjpSubstMap, TypeExpansionContext::minimal()); pullbackType = pullbackType.subst(getModule(), vjpSubstMap); auto pullbackFnType = pullbackType.castTo(); - auto pullbackSubstType = pullbackPartialApply->getType().castTo(); + + // If necessary, convert the pullback value to the returned pullback + // function type. SILValue pullbackValue; if (pullbackSubstType == pullbackFnType) { pullbackValue = pullbackPartialApply; @@ -213,11 +215,8 @@ class VJPCloner::Implementation final builder.createConvertFunction(loc, pullbackPartialApply, pullbackType, /*withoutActuallyEscaping*/ false); } else { - // When `diag::autodiff_loadable_value_addressonly_tangent_unsupported` - // applies, the return type may be ABI-incomaptible with the type of the - // partially applied pullback. In these cases, produce an undef and rely - // on other code to emit a diagnostic. - pullbackValue = SILUndef::get(pullbackType, *vjp); + llvm::report_fatal_error("Pullback value type is not ABI-compatible " + "with the returned pullback type"); } // Return a tuple of the original result and pullback. @@ -458,9 +457,14 @@ class VJPCloner::Implementation final if (!originalFnTy->getParameters()[paramIndex] .getSILStorageInterfaceType() .isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - ai->getArgumentsWithoutIndirectResults()[paramIndex], invoker, - diag::autodiff_nondifferentiable_argument); + auto arg = ai->getArgumentsWithoutIndirectResults()[paramIndex]; + auto startLoc = arg.getLoc().getStartSourceLoc(); + auto endLoc = arg.getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + arg, invoker, diag::autodiff_nondifferentiable_argument) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } @@ -478,8 +482,14 @@ class VJPCloner::Implementation final .getSILStorageInterfaceType(); } if (!remappedResultType.isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - origCallee, invoker, diag::autodiff_nondifferentiable_result); + auto startLoc = ai->getLoc().getStartSourceLoc(); + auto endLoc = ai->getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + origCallee, invoker, + diag::autodiff_nondifferentiable_result) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } @@ -618,6 +628,18 @@ class VJPCloner::Implementation final getOpValue(origCallee)->getDefiningInstruction()); } + void visitTryApplyInst(TryApplyInst *tai) { + // Build pullback struct value for original block. + auto *pbStructVal = buildPullbackValueStructValue(tai); + // Create a new `try_apply` instruction. + auto args = getOpValueArray<8>(tai->getArguments()); + getBuilder().createTryApply( + tai->getLoc(), getOpValue(tai->getCallee()), + getOpSubstitutionMap(tai->getSubstitutionMap()), args, + createTrampolineBasicBlock(tai, pbStructVal, tai->getNormalBB()), + createTrampolineBasicBlock(tai, pbStructVal, tai->getErrorBB())); + } + void visitDifferentiableFunctionInst(DifferentiableFunctionInst *dfi) { // Clone `differentiable_function` from original to VJP, then add the cloned // instruction to the `differentiable_function` worklist. @@ -733,6 +755,8 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { pattern, tanType, TypeExpansionContext::minimal()); ParameterConvention conv; switch (origResConv) { + case ResultConvention::Unowned: + case ResultConvention::UnownedInnerPointer: case ResultConvention::Owned: case ResultConvention::Autoreleased: if (tl.isAddressOnly()) { @@ -742,10 +766,6 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { : ParameterConvention::Direct_Guaranteed; } break; - case ResultConvention::Unowned: - case ResultConvention::UnownedInnerPointer: - conv = ParameterConvention::Direct_Unowned; - break; case ResultConvention::Indirect: conv = ParameterConvention::Indirect_In_Guaranteed; break; diff --git a/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp b/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp index ea8429c854876..ce00fdd8b8e43 100644 --- a/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp +++ b/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp @@ -337,9 +337,6 @@ bool CrossModuleSerializationSetup::canSerialize(SILInstruction *inst, }); return canUse; } - if (auto *GAI = dyn_cast(inst)) { - return !GAI->getReferencedGlobal()->getName().startswith("globalinit_"); - } if (auto *MI = dyn_cast(inst)) { return !MI->getMember().isForeign; } diff --git a/lib/SILOptimizer/IPO/GlobalOpt.cpp b/lib/SILOptimizer/IPO/GlobalOpt.cpp index 113d71ccb32b8..9c9e7bfc3b7a9 100644 --- a/lib/SILOptimizer/IPO/GlobalOpt.cpp +++ b/lib/SILOptimizer/IPO/GlobalOpt.cpp @@ -260,7 +260,7 @@ void SILGlobalOpt::collectOnceCall(BuiltinInst *BI) { UnhandledOnceCallee = true; return; } - if (!Callee->getName().startswith("globalinit_")) + if (!Callee->isGlobalInitOnceFunction()) return; // We currently disable optimizing the initializer if a globalinit_func @@ -301,7 +301,7 @@ bool SILGlobalOpt::isInLoop(SILBasicBlock *CurBB) { if (LoopCheckedFunctions.insert(F).second) { for (auto I = scc_begin(F); !I.isAtEnd(); ++I) { - if (I.hasLoop()) + if (I.hasCycle()) for (SILBasicBlock *BB : *I) LoopBlocks.insert(BB); } diff --git a/lib/SILOptimizer/LoopTransforms/LICM.cpp b/lib/SILOptimizer/LoopTransforms/LICM.cpp index e4be5ac35f5fa..69a0f32be343d 100644 --- a/lib/SILOptimizer/LoopTransforms/LICM.cpp +++ b/lib/SILOptimizer/LoopTransforms/LICM.cpp @@ -214,8 +214,8 @@ static void getDominatingBlocks(SmallVectorImpl &domBlocks, SILLoop *Loop, DominanceInfo *DT) { auto HeaderBB = Loop->getHeader(); auto DTRoot = DT->getNode(HeaderBB); - SmallVector ExitingBBs; - Loop->getExitingBlocks(ExitingBBs); + SmallVector ExitingAndLatchBBs; + Loop->getExitingAndLatchBlocks(ExitingAndLatchBBs); for (llvm::df_iterator It = llvm::df_begin(DTRoot), E = llvm::df_end(DTRoot); It != E;) { @@ -223,7 +223,7 @@ static void getDominatingBlocks(SmallVectorImpl &domBlocks, // Don't decent into control-dependent code. Only traverse into basic blocks // that dominate all exits. - if (!std::all_of(ExitingBBs.begin(), ExitingBBs.end(), + if (!std::all_of(ExitingAndLatchBBs.begin(), ExitingAndLatchBBs.end(), [=](SILBasicBlock *ExitBB) { return DT->dominates(CurBB, ExitBB); })) { diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h index 66a878cc5717f..1cea674c1e3b8 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h @@ -176,6 +176,11 @@ class DIMemoryObjectInfo { MemoryInst->isDerivedClassSelfOnly(); } + /// True if this memory object is the 'self' of a root class init method. + bool isRootClassSelf() const { + return isClassInitSelf() && MemoryInst->isRootSelf(); + } + /// True if this memory object is the 'self' of a non-root class init method. bool isNonRootClassSelf() const { return isClassInitSelf() && !MemoryInst->isRootSelf(); diff --git a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp index ab7a60c936c07..14a63285fb1f3 100644 --- a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp +++ b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp @@ -1072,7 +1072,13 @@ void LifetimeChecker::handleStoreUse(unsigned UseID) { // it for later. Once we've collected all of the conditional init/assigns, // we can insert a single control variable for the memory object for the // whole function. - if (!Use.onlyTouchesTrivialElements(TheMemory)) + // + // For root class initializers, we must keep track of initializations of + // trivial stored properties also, since we need to know when the object + // has been fully initialized when deciding if a strong_release should + // lower to a partial_dealloc_ref. + if (TheMemory.isRootClassSelf() || + !Use.onlyTouchesTrivialElements(TheMemory)) HasConditionalInitAssign = true; return; } @@ -2186,12 +2192,12 @@ static void updateControlVariable(SILLocation Loc, } /// Test a bit in the control variable at the current insertion point. -static SILValue testControlVariable(SILLocation Loc, - unsigned Elt, - SILValue ControlVariableAddr, - Identifier &ShiftRightFn, - Identifier &TruncateFn, - SILBuilder &B) { +static SILValue testControlVariableBit(SILLocation Loc, + unsigned Elt, + SILValue ControlVariableAddr, + Identifier &ShiftRightFn, + Identifier &TruncateFn, + SILBuilder &B) { SILValue ControlVariable = B.createLoad(Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial); @@ -2224,6 +2230,32 @@ static SILValue testControlVariable(SILLocation Loc, {}, CondVal); } +/// Test if all bits in the control variable are set at the current +/// insertion point. +static SILValue testAllControlVariableBits(SILLocation Loc, + SILValue ControlVariableAddr, + Identifier &CmpEqFn, + SILBuilder &B) { + SILValue ControlVariable = + B.createLoad(Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial); + + SILValue CondVal = ControlVariable; + CanBuiltinIntegerType IVType = CondVal->getType().castTo(); + + if (IVType->getFixedWidth() == 1) + return CondVal; + + SILValue AllBitsSet = B.createIntegerLiteral(Loc, CondVal->getType(), -1); + if (!CmpEqFn.get()) + CmpEqFn = getBinaryFunction("cmp_eq", CondVal->getType(), + B.getASTContext()); + SILValue Args[] = { CondVal, AllBitsSet }; + + return B.createBuiltin(Loc, CmpEqFn, + SILType::getBuiltinIntegerType(1, B.getASTContext()), + {}, Args); +} + /// handleConditionalInitAssign - This memory object has some stores /// into (some element of) it that is either an init or an assign based on the /// control flow path through the function, or have a destroy event that happens @@ -2285,7 +2317,13 @@ SILValue LifetimeChecker::handleConditionalInitAssign() { // If this ambiguous store is only of trivial types, then we don't need to // do anything special. We don't even need keep the init bit for the // element precise. - if (Use.onlyTouchesTrivialElements(TheMemory)) + // + // For root class initializers, we must keep track of initializations of + // trivial stored properties also, since we need to know when the object + // has been fully initialized when deciding if a strong_release should + // lower to a partial_dealloc_ref. + if (!TheMemory.isRootClassSelf() && + Use.onlyTouchesTrivialElements(TheMemory)) continue; B.setInsertionPoint(Use.Inst); @@ -2324,9 +2362,9 @@ SILValue LifetimeChecker::handleConditionalInitAssign() { // initialization. for (unsigned Elt = Use.FirstElement, e = Elt+Use.NumElements; Elt != e; ++Elt) { - auto CondVal = testControlVariable(Loc, Elt, ControlVariableAddr, - ShiftRightFn, TruncateFn, - B); + auto CondVal = testControlVariableBit(Loc, Elt, ControlVariableAddr, + ShiftRightFn, TruncateFn, + B); SILBasicBlock *TrueBB, *FalseBB, *ContBB; InsertCFGDiamond(CondVal, Loc, B, @@ -2395,7 +2433,7 @@ SILValue LifetimeChecker::handleConditionalInitAssign() { void LifetimeChecker:: handleConditionalDestroys(SILValue ControlVariableAddr) { SILBuilderWithScope B(TheMemory.getUninitializedValue()); - Identifier ShiftRightFn, TruncateFn; + Identifier ShiftRightFn, TruncateFn, CmpEqFn; unsigned NumMemoryElements = TheMemory.getNumElements(); @@ -2465,9 +2503,9 @@ handleConditionalDestroys(SILValue ControlVariableAddr) { // Insert a load of the liveness bitmask and split the CFG into a diamond // right before the destroy_addr, if we haven't already loaded it. - auto CondVal = testControlVariable(Loc, Elt, ControlVariableAddr, - ShiftRightFn, TruncateFn, - B); + auto CondVal = testControlVariableBit(Loc, Elt, ControlVariableAddr, + ShiftRightFn, TruncateFn, + B); SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock; @@ -2486,11 +2524,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) { // depending on if the self box was initialized or not. auto emitReleaseOfSelfWhenNotConsumed = [&](SILLocation Loc, SILInstruction *Release) { - auto CondVal = testControlVariable(Loc, SelfInitializedElt, - ControlVariableAddr, - ShiftRightFn, - TruncateFn, - B); + auto CondVal = testControlVariableBit(Loc, SelfInitializedElt, + ControlVariableAddr, + ShiftRightFn, + TruncateFn, + B); SILBasicBlock *ReleaseBlock, *ConsumedBlock, *ContBlock; @@ -2522,12 +2560,50 @@ handleConditionalDestroys(SILValue ControlVariableAddr) { // Just conditionally destroy each memory element, and for classes, // also free the partially initialized object. if (!TheMemory.isNonRootClassSelf()) { - destroyMemoryElements(Loc, Availability); - processUninitializedRelease(Release, false, B.getInsertionPoint()); + assert(!Availability.isAllYes() && + "Should not end up here if fully initialized"); + + // For root class initializers, we check if all proeprties were + // dynamically initialized, and if so, treat this as a release of + // an initialized 'self', instead of tearing down the fields + // one by one and deallocating memory. + // + // This is required for correctness, since the condition that + // allows 'self' to escape is that all stored properties were + // initialized. So we cannot deallocate the memory if 'self' may + // have escaped. + // + // This also means the deinitializer will run if all stored + // properties were initialized. + if (TheMemory.isClassInitSelf() && + Availability.hasAny(DIKind::Partial)) { + auto CondVal = testAllControlVariableBits(Loc, ControlVariableAddr, + CmpEqFn, B); + + SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock; + + InsertCFGDiamond(CondVal, Loc, B, + ReleaseBlock, DeallocBlock, ContBlock); + + // If true, self was fully initialized and must be released. + B.setInsertionPoint(ReleaseBlock->begin()); + B.setCurrentDebugScope(ReleaseBlock->begin()->getDebugScope()); + Release->moveBefore(&*B.getInsertionPoint()); + + // If false, self is uninitialized and must be freed. + B.setInsertionPoint(DeallocBlock->begin()); + B.setCurrentDebugScope(DeallocBlock->begin()->getDebugScope()); + destroyMemoryElements(Loc, Availability); + processUninitializedRelease(Release, false, B.getInsertionPoint()); + } else { + destroyMemoryElements(Loc, Availability); + processUninitializedRelease(Release, false, B.getInsertionPoint()); + + // The original strong_release or destroy_addr instruction is + // always dead at this point. + deleteDeadRelease(CDElt.ReleaseID); + } - // The original strong_release or destroy_addr instruction is - // always dead at this point. - deleteDeadRelease(CDElt.ReleaseID); continue; } @@ -2573,11 +2649,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) { // self.init or super.init may or may not have been called. // We have not yet stored 'self' into the box. - auto CondVal = testControlVariable(Loc, SuperInitElt, - ControlVariableAddr, - ShiftRightFn, - TruncateFn, - B); + auto CondVal = testControlVariableBit(Loc, SuperInitElt, + ControlVariableAddr, + ShiftRightFn, + TruncateFn, + B); SILBasicBlock *ConsumedBlock, *DeallocBlock, *ContBlock; @@ -2607,11 +2683,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) { // self.init or super.init may or may not have been called. // We may or may have stored 'self' into the box. - auto CondVal = testControlVariable(Loc, SuperInitElt, - ControlVariableAddr, - ShiftRightFn, - TruncateFn, - B); + auto CondVal = testControlVariableBit(Loc, SuperInitElt, + ControlVariableAddr, + ShiftRightFn, + TruncateFn, + B); SILBasicBlock *LiveBlock, *DeallocBlock, *ContBlock; diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index 5156ffac9e792..083f840e892e7 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -158,8 +158,7 @@ static bool diagnoseNoReturn(ADContext &context, SILFunction *original, /// flow unsupported" error at appropriate source locations. Returns true if /// error is emitted. /// -/// Update as control flow support is added. Currently, branching terminators -/// other than `br`, `cond_br`, `switch_enum` are not supported. +/// Update as control flow support is added. static bool diagnoseUnsupportedControlFlow(ADContext &context, SILFunction *original, DifferentiationInvoker invoker) { @@ -173,7 +172,7 @@ static bool diagnoseUnsupportedControlFlow(ADContext &context, isa(term) || isa(term) || isa(term) || isa(term) || - isa(term)) + isa(term) || isa(term)) continue; // If terminator is an unsupported branching terminator, emit an error. if (term->isBranch()) { @@ -1330,7 +1329,7 @@ bool DifferentiationTransformer::processLinearFunctionInst( cast(lfi)); PrettyStackTraceSILFunction fnTrace("...in", lfi->getFunction()); LLVM_DEBUG({ - auto &s = getADDebugStream() << "Processing LinearFunctoinInst:\n"; + auto &s = getADDebugStream() << "Processing LinearFunctionInst:\n"; lfi->printInContext(s); }); @@ -1385,8 +1384,8 @@ void Differentiation::run() { if (auto *dfi = dyn_cast(&i)) { context.getDifferentiableFunctionInstWorklist().push_back(dfi); } else if (auto *lfi = dyn_cast(&i)) { - // If linear map transposition is not enable and an uncanonical - // `linear_function` instruction is encounter, emit a diagnostic. + // If linear map transposition is not enabled and an uncanonical + // `linear_function` instruction is encountered, emit a diagnostic. // FIXME(SR-11850): Finish support for linear map transposition. if (!EnableExperimentalLinearMapTransposition) { if (!lfi->hasTransposeFunction()) { diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp index fd5d3a012b555..4774b9fd46a75 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp @@ -806,6 +806,8 @@ void SILCombiner::buildConcreteOpenedExistentialInfos( // BuilderContext before rewriting any uses of the ConcreteType. OpenedArchetypesTracker.addOpenedArchetypeDef( cast(CEI.ConcreteType), CEI.ConcreteTypeDef); + } else if (auto *I = CEI.ConcreteValue->getDefiningInstruction()) { + OpenedArchetypesTracker.registerUsedOpenedArchetypes(I); } } } diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp index c499356dfbea5..4321485140fb2 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp @@ -554,7 +554,8 @@ SILInstruction *SILCombiner::visitAllocStackInst(AllocStackInst *AS) { // Be careful with open archetypes, because they cannot be moved before // their definitions. if (IEI && !OEI && - !IEI->getLoweredConcreteType().isOpenedExistential()) { + !IEI->getLoweredConcreteType().hasOpenedExistential()) { + assert(!IEI->getLoweredConcreteType().isOpenedExistential()); auto *ConcAlloc = Builder.createAllocStack( AS->getLoc(), IEI->getLoweredConcreteType(), AS->getVarInfo()); IEI->replaceAllUsesWith(ConcAlloc); diff --git a/lib/SILOptimizer/SemanticARC/BorrowScopeOpts.cpp b/lib/SILOptimizer/SemanticARC/BorrowScopeOpts.cpp new file mode 100644 index 0000000000000..600c6f41d5072 --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/BorrowScopeOpts.cpp @@ -0,0 +1,58 @@ +//===--- BorrowScopeOpts.cpp ----------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Optimizations that attempt to simplify and or eliminate borrow scopes. Today +/// we only eliminate scopes, but we could also eliminate redundant scopes by +/// converting struct_extract operations to use destructure operations. +/// +//===----------------------------------------------------------------------===// + +#include "SemanticARCOptVisitor.h" + +using namespace swift; +using namespace swift::semanticarc; + +bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) { + auto kind = bbi->getOperand().getOwnershipKind(); + SmallVector endBorrows; + for (auto *op : bbi->getUses()) { + if (!op->isConsumingUse()) { + // Make sure that this operand can accept our arguments kind. + auto map = op->getOwnershipKindMap(); + if (map.canAcceptKind(kind)) + continue; + return false; + } + + // Otherwise, this borrow is being consumed. See if our consuming inst is an + // end_borrow. If it isn't, then return false, this scope is + // needed. Otherwise, add the end_borrow to our list of end borrows. + auto *ebi = dyn_cast(op->getUser()); + if (!ebi) { + return false; + } + endBorrows.push_back(ebi); + } + + // At this point, we know that the begin_borrow's operand can be + // used as an argument to all non-end borrow uses. Eliminate the + // begin borrow and end borrows. + while (!endBorrows.empty()) { + auto *ebi = endBorrows.pop_back_val(); + eraseInstruction(ebi); + } + + eraseAndRAUWSingleValueInstruction(bbi, bbi->getOperand()); + return true; +} diff --git a/lib/SILOptimizer/SemanticARC/CMakeLists.txt b/lib/SILOptimizer/SemanticARC/CMakeLists.txt new file mode 100644 index 0000000000000..24d12d704ff4d --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(swiftSILOptimizer PRIVATE + SemanticARCOpts.cpp + OwnershipLiveRange.cpp + LoadCopyToLoadBorrowOpt.cpp + BorrowScopeOpts.cpp + CopyValueOpts.cpp + OwnedToGuaranteedPhiOpt.cpp) diff --git a/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp b/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp new file mode 100644 index 0000000000000..4d2ba9134d731 --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp @@ -0,0 +1,478 @@ +//===--- CopyValueOpts.cpp ------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Contains optimizations that eliminate redundant copy values. +/// +//===----------------------------------------------------------------------===// + +#include "OwnershipPhiOperand.h" +#include "SemanticARCOptVisitor.h" + +using namespace swift; +using namespace swift::semanticarc; + +//===----------------------------------------------------------------------===// +// Guaranteed Copy Value Optimization +//===----------------------------------------------------------------------===// + +// Eliminate a copy of a borrowed value, if: +// +// 1. All of the copies users do not consume the copy (and thus can accept a +// borrowed value instead). +// 2. The copies's non-destroy_value users are strictly contained within the +// scope of the borrowed value. +// +// Example: +// +// %0 = @guaranteed (argument or instruction) +// %1 = copy_value %0 +// apply %f(%1) : $@convention(thin) (@guaranteed ...) ... +// other_non_consuming_use %1 +// destroy_value %1 +// end_borrow %0 (if an instruction) +// +// => +// +// %0 = @guaranteed (argument or instruction) +// apply %f(%0) : $@convention(thin) (@guaranteed ...) ... +// other_non_consuming_use %0 +// end_borrow %0 (if an instruction) +// +// NOTE: This means that the destroy_value technically can be after the +// end_borrow. In practice, this will not be the case but we use this to avoid +// having to reason about the ordering of the end_borrow and destroy_value. +// +// NOTE: Today we only perform this for guaranteed parameters since this enables +// us to avoid doing the linear lifetime check to make sure that all destroys +// are within the borrow scope. +// +// TODO: This needs a better name. +bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization( + CopyValueInst *cvi) { + // For now, do not run this optimization. This is just to be careful. + if (onlyGuaranteedOpts) + return false; + + SmallVector borrowScopeIntroducers; + + // Find all borrow introducers for our copy operand. If we are unable to find + // all of the reproducers (due to pattern matching failure), conservatively + // return false. We can not optimize. + // + // NOTE: We can get multiple introducers if our copy_value's operand + // value runs through a phi or an aggregate forming instruction. + if (!getAllBorrowIntroducingValues(cvi->getOperand(), borrowScopeIntroducers)) + return false; + + // Then go over all of our uses and see if the value returned by our copy + // value forms a dead live range or a live range that would be dead if it was + // not consumed by phi nodes. If we do not have such a live range, there must + // be some consuming use that we either do not understand is /actually/ + // forwarding or a user that truly represents a necessary consume of the value + // (e.x. storing into memory). + OwnershipLiveRange lr(cvi); + auto hasUnknownConsumingUseState = + lr.hasUnknownConsumingUse(assumingAtFixedPoint); + if (hasUnknownConsumingUseState == + OwnershipLiveRange::HasConsumingUse_t::Yes) { + return false; + } + + // Next check if we do not have any destroys of our copy_value and are + // processing a local borrow scope. In such a case, due to the way we ignore + // dead end blocks, we may eliminate the copy_value, creating a use of the + // borrowed value after the end_borrow. To avoid this, in such cases we + // bail. In contrast, a non-local borrow scope does not have any end scope + // instructions, implying we can avoid this hazard and still optimize in such + // a case. + // + // DISCUSSION: Consider the following SIL: + // + // ``` + // %1 = begin_borrow %0 : $KlassPair (1) + // %2 = struct_extract %1 : $KlassPair, #KlassPair.firstKlass + // %3 = copy_value %2 : $Klass + // ... + // end_borrow %1 : $LintCommand (2) + // cond_br ..., bb1, bb2 + // + // ... + // + // bbN: + // // Never return type implies dead end block. + // apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> Never (3) + // unreachable + // ``` + // + // For simplicity, note that if bbN post-dominates %3, given that when we + // compute linear lifetime errors we ignore dead end blocks, we would not + // register that the copy_values only use is outside of the begin_borrow + // region defined by (1), (2) and thus would eliminate the copy. This would + // result in %2 being used by %f, causing the linear lifetime checker to + // error. + // + // Naively one may assume that the solution to this is to just check if %3 has + // /any/ destroy_values at all and if it doesn't have any reachable + // destroy_values, then we are in this case. But is this correct in + // general. We prove this below: + // + // The only paths along which the copy_value can not be destroyed or consumed + // is along paths to dead end blocks. Trivially, we know that such a dead end + // block, can not be reachable from the end_borrow since by their nature dead + // end blocks end in unreachables. + // + // So we know that we can only run into this bug if we have a dead end block + // reachable from the end_borrow, meaning that the bug can not occur if we + // branch before the end_borrow since in that case, the borrow scope would + // last over the dead end block's no return meaning that we will not use the + // borrowed value after its lifetime is ended by the end_borrow. + // + // With that in hand, we note again that if we have exactly one consumed, + // destroy_value /after/ the end_borrow we will not optimize here. This means + // that this bug can only occur if the copy_value is only post-dominated by + // dead end blocks that use the value in a non-consuming way. + // + // TODO: There may be some way of sinking this into the loop below. + bool haveAnyLocalScopes = + llvm::any_of(borrowScopeIntroducers, [](BorrowedValue borrowScope) { + return borrowScope.isLocalScope(); + }); + + auto destroys = lr.getDestroyingUses(); + if (destroys.empty() && haveAnyLocalScopes) { + return false; + } + + // If we reached this point, then we know that all of our users can accept a + // guaranteed value and our owned value is destroyed only by a set of + // destroy_values. Check if: + // + // 1. All of our destroys are joint post-dominated by our end borrow scope + // set. If they do not, then the copy_value is lifetime extending the + // guaranteed value, we can not eliminate it. + // + // 2. If all of our destroy_values are dead end. In such a case, the linear + // lifetime checker will not perform any checks since it assumes that dead + // end destroys can be ignored. Since we are going to end the program + // anyways, we want to be conservative here and optimize only if we do not + // need to insert an end_borrow since all of our borrow introducers are + // non-local scopes. + { + bool foundNonDeadEnd = false; + for (auto *d : destroys) { + foundNonDeadEnd |= !getDeadEndBlocks().isDeadEnd(d->getParentBlock()); + } + if (!foundNonDeadEnd && haveAnyLocalScopes) + return false; + SmallVector scratchSpace; + SmallPtrSet visitedBlocks; + if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) { + return !borrowScope.areUsesWithinScope(lr.getAllConsumingUses(), + scratchSpace, visitedBlocks, + getDeadEndBlocks()); + })) { + return false; + } + } + + // Otherwise, we know that our copy_value/destroy_values are all completely + // within the guaranteed value scope. So we /could/ optimize it. Now check if + // we were truly dead or if we are dead if we can eliminate phi arg uses. If + // we need to handle the phi arg uses, we bail. After we reach a fixed point, + // we will try to eliminate this value then if we can find a complete set of + // all incoming values to our phi argument. + if (hasUnknownConsumingUseState == + OwnershipLiveRange::HasConsumingUse_t::YesButAllPhiArgs) { + auto opPhi = *OwnershipPhiOperand::get(lr.getSingleUnknownConsumingUse()); + SmallVector scratchSpace; + SmallPtrSet visitedBlocks; + + bool canOptimizePhi = opPhi.visitResults([&](SILValue value) { + SWIFT_DEFER { + scratchSpace.clear(); + visitedBlocks.clear(); + }; + + OwnershipLiveRange phiArgLR(value); + if (bool(phiArgLR.hasUnknownConsumingUse())) { + return false; + } + + if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) { + return !borrowScope.areUsesWithinScope( + phiArgLR.getAllConsumingUses(), scratchSpace, visitedBlocks, + getDeadEndBlocks()); + })) { + return false; + } + + return true; + }); + + if (canOptimizePhi) { + opPhi.visitResults([&](SILValue value) { + joinedOwnedIntroducerToConsumedOperands.insert(value, + opPhi.getOperand()); + return true; + }); + } + + return false; + } + + // Otherwise, our copy must truly not be needed, o RAUW and convert to + // guaranteed! + std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), getCallbacks()); + return true; +} + +//===----------------------------------------------------------------------===// +// Trivial Live Range Elimination +//===----------------------------------------------------------------------===// + +/// If cvi only has destroy value users, then cvi is a dead live range. Lets +/// eliminate all such dead live ranges. +bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue( + CopyValueInst *cvi) { + // This is a cheap optimization generally. + + // See if we are lucky and have a simple case. + if (auto *op = cvi->getSingleUse()) { + if (auto *dvi = dyn_cast(op->getUser())) { + eraseInstruction(dvi); + eraseInstructionAndAddOperandsToWorklist(cvi); + return true; + } + } + + // If all of our copy_value users are destroy_value, zap all of the + // instructions. We begin by performing that check and gathering up our + // destroy_value. + SmallVector destroys; + if (!all_of(cvi->getUses(), [&](Operand *op) { + auto *dvi = dyn_cast(op->getUser()); + if (!dvi) + return false; + + // Stash dvi in destroys so we can easily eliminate it later. + destroys.push_back(dvi); + return true; + })) { + return false; + } + + // Now that we have a truly dead live range copy value, eliminate it! + while (!destroys.empty()) { + eraseInstruction(destroys.pop_back_val()); + } + eraseInstructionAndAddOperandsToWorklist(cvi); + return true; +} + +//===----------------------------------------------------------------------===// +// Live Range Joining +//===----------------------------------------------------------------------===// + +// Handle simple checking where we do not need to form live ranges and visit a +// bunch of instructions. +static bool canSafelyJoinSimpleRange(SILValue cviOperand, + DestroyValueInst *cviOperandDestroy, + CopyValueInst *cvi) { + // We only handle cases where our copy_value has a single consuming use that + // is not a forwarding use. We need to use the LiveRange functionality to + // guarantee correctness in the presence of forwarding uses. + // + // NOTE: This use may be any type of consuming use and may not be a + // destroy_value. + auto *cviConsumer = cvi->getSingleConsumingUse(); + if (!cviConsumer || isOwnedForwardingInstruction(cviConsumer->getUser())) { + return false; + } + + // Ok, we may be able to eliminate this. The main thing we need to be careful + // of here is that if the destroy_value is /after/ the consuming use of the + // operand of copy_value, we may have normal uses of the copy_value's operand + // that would become use-after-frees since we would be shrinking the lifetime + // of the object potentially. Consider the following SIL: + // + // %0 = ... + // %1 = copy_value %0 + // apply %cviConsumer(%1) + // apply %guaranteedUser(%0) + // destroy_value %0 + // + // Easily, if we were to eliminate the copy_value, destroy_value, the object's + // lifetime could potentially be shrunk before guaranteedUser is executed, + // causing guaranteedUser to be a use-after-free. + // + // As an extra wrinkle, until all interior pointer constructs (e.x.: + // project_box) are guaranteed to be guaranted by a begin_borrow, we can not + // in general safely shrink lifetimes. So even if we think we can prove that + // all non-consuming uses of %0 are before apply %cviConsumer, we may miss + // implicit uses that are not guarded yet by a begin_borrow, resulting in + // use-after-frees. + // + // With that in mind, we only handle cases today where we can prove that + // destroy_value is strictly before the consuming use of the operand. This + // guarantees that we are not shrinking the lifetime of the underlying object. + // + // First we handle the simple case: where the cviConsumer is a return inst. In + // such a case, we know for sure that cviConsumer post-dominates the + // destroy_value. + auto cviConsumerIter = cviConsumer->getUser()->getIterator(); + if (isa(cviConsumerIter)) { + return true; + } + + // Then see if our cviConsumer is in the same block as a return inst and the + // destroy_value is not. In that case, we know that the cviConsumer must + // post-dominate the destroy_value. + auto *cviConsumingBlock = cviConsumerIter->getParent(); + if (isa(cviConsumingBlock->getTerminator()) && + cviConsumingBlock != cviOperandDestroy->getParent()) { + return true; + } + + // Otherwise, we only support joining live ranges where the cvi and the cvi's + // operand's destroy are in the same block with the destroy_value of cvi + // operand needing to be strictly after the copy_value. This analysis can be + // made significantly stronger by using LiveRanges, but this is simple for + // now. + auto cviOperandDestroyIter = cviOperandDestroy->getIterator(); + if (cviConsumingBlock != cviOperandDestroyIter->getParent()) { + return false; + } + + // TODO: This should really be llvm::find, but for some reason, the templates + // do not match up given the current state of the iterators. This impl works + // in a pinch though. + return llvm::any_of( + llvm::make_range(cviOperandDestroyIter, + cviOperandDestroyIter->getParent()->end()), + [&](const SILInstruction &val) { return &*cviConsumerIter == &val; }); +} + +// # The Problem We Are Solving +// +// The main idea here is that we are trying to eliminate the simplest, easiest +// form of live range joining. Consider the following SIL: +// +// ``` +// %cviOperand = ... // @owned value +// %cvi = copy_value %cviOperand // copy of @owned value +// ... +// destroy_value %cviOperandDestroy // destruction of @owned value +// ... +// apply %consumingUser(%cvi) // destruction of copy of @owned value +// ``` +// +// We want to reduce reference count traffic by eliminating the middle +// copy/destroy yielding: +// +// ``` +// %cviOperand = ... // @owned value +// // *eliminated copy_value* +// ... +// // *eliminated destroy_value* +// ... +// apply %consumingUser(%cviOperand) // destruction of copy of @owned +// value +// ``` +// +// # Safety +// +// In order to do this safely, we need to take the union of the two objects +// lifetimes since we are only joining lifetimes. This ensures that we can rely +// on SILGen's correctness on inserting safe lifetimes. To keep this simple +// today we only optimize if the destroy_value and consuming user are in the +// same block and the consuming user is later in the block than the +// destroy_value. +// +// DISCUSSION: The reason why we do not shrink lifetimes today is that all +// interior pointers (e.x. project_box) are properly guarded by +// begin_borrow. Because of that we can not shrink lifetimes and instead rely on +// SILGen's correctness. +bool SemanticARCOptVisitor::tryJoiningCopyValueLiveRangeWithOperand( + CopyValueInst *cvi) { + // First do a quick check if our operand is owned. If it is not owned, we can + // not join live ranges. + SILValue operand = cvi->getOperand(); + if (operand.getOwnershipKind() != ValueOwnershipKind::Owned) { + return false; + } + + // Then check if our operand has a single destroy_value. If it does and that + // destroy_value is strictly before the consumer of our copy_value in the same + // block as the consumer of said copy_value then we can always join the live + // ranges. + // + // Example: + // + // ``` + // %1 = copy_value %0 + // ... + // destroy_value %0 + // apply %consumingUser(%1) + // ``` + // -> + // + // ``` + // apply %consumingUser(%0) + // ``` + // + // DISCUSSION: We need to ensure that the consuming use of the copy_value is + // strictly after the destroy_value to ensure that we do not shrink the live + // range of the operand if the operand has any normal uses beyond our copy + // value. Otherwise, we could have normal uses /after/ the consuming use of + // our copy_value. + if (auto *dvi = operand->getSingleConsumingUserOfType()) { + if (canSafelyJoinSimpleRange(operand, dvi, cvi)) { + eraseInstruction(dvi); + eraseAndRAUWSingleValueInstruction(cvi, operand); + return true; + } + } + + // Otherwise, we couldn't handle this case, so return false. + // + // NOTE: We would generally do a more complex analysis here to handle the more + // general case. That would most likely /not/ be a guaranteed optimization + // until we investigate/measure. + return false; +} + +//===----------------------------------------------------------------------===// +// Top Level Entrypoint +//===----------------------------------------------------------------------===// + +bool SemanticARCOptVisitor::visitCopyValueInst(CopyValueInst *cvi) { + // If our copy value inst has only destroy_value users, it is a dead live + // range. Try to eliminate them. + if (eliminateDeadLiveRangeCopyValue(cvi)) { + return true; + } + + // Then see if copy_value operand's lifetime ends after our copy_value via a + // destroy_value. If so, we can join their lifetimes. + if (tryJoiningCopyValueLiveRangeWithOperand(cvi)) { + return true; + } + + // Then try to perform the guaranteed copy value optimization. + if (performGuaranteedCopyValueOptimization(cvi)) { + return true; + } + + return false; +} diff --git a/lib/SILOptimizer/SemanticARC/LoadCopyToLoadBorrowOpt.cpp b/lib/SILOptimizer/SemanticARC/LoadCopyToLoadBorrowOpt.cpp new file mode 100644 index 0000000000000..2ea47e47c8315 --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/LoadCopyToLoadBorrowOpt.cpp @@ -0,0 +1,491 @@ +//===--- LoadCopyToLoadBorrowOpt.cpp --------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Defines the main optimization that converts load [copy] -> load_borrow if we +/// can prove that the +1 is not actually needed and the memory loaded from is +/// never written to while the load [copy]'s object value is being used. +/// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sil-semantic-arc-opts" + +#include "OwnershipLiveRange.h" +#include "SemanticARCOptVisitor.h" +#include "swift/SIL/LinearLifetimeChecker.h" +#include "swift/SIL/MemAccessUtils.h" +#include "swift/SIL/OwnershipUtils.h" +#include "swift/SIL/Projection.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILValue.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" +#include "llvm/Support/CommandLine.h" + +using namespace swift; +using namespace swift::semanticarc; + +//===----------------------------------------------------------------------===// +// Well Behaved Write Analysis +//===----------------------------------------------------------------------===// + +/// Returns true if we were able to ascertain that either the initialValue has +/// no write uses or all of the write uses were writes that we could understand. +bool swift::semanticarc::constructCacheValue( + SILValue initialValue, + SmallVectorImpl &wellBehavedWriteAccumulator) { + SmallVector worklist(initialValue->getUses()); + + while (!worklist.empty()) { + auto *op = worklist.pop_back_val(); + SILInstruction *user = op->getUser(); + + if (Projection::isAddressProjection(user) || + isa(user)) { + for (SILValue r : user->getResults()) { + llvm::copy(r->getUses(), std::back_inserter(worklist)); + } + continue; + } + + if (auto *oeai = dyn_cast(user)) { + // Mutable access! + if (oeai->getAccessKind() != OpenedExistentialAccess::Immutable) { + wellBehavedWriteAccumulator.push_back(op); + } + + // Otherwise, look through it and continue. + llvm::copy(oeai->getUses(), std::back_inserter(worklist)); + continue; + } + + if (auto *si = dyn_cast(user)) { + // We must be the dest since addresses can not be stored. + assert(si->getDest() == op->get()); + wellBehavedWriteAccumulator.push_back(op); + continue; + } + + // Add any destroy_addrs to the resultAccumulator. + if (isa(user)) { + wellBehavedWriteAccumulator.push_back(op); + continue; + } + + // load_borrow and incidental uses are fine as well. + if (isa(user) || isIncidentalUse(user)) { + continue; + } + + // Look through begin_access and mark them/their end_borrow as users. + if (auto *bai = dyn_cast(user)) { + // If we do not have a read, mark this as a write. Also, insert our + // end_access as well. + if (bai->getAccessKind() != SILAccessKind::Read) { + wellBehavedWriteAccumulator.push_back(op); + transform(bai->getUsersOfType(), + std::back_inserter(wellBehavedWriteAccumulator), + [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); + } + + // And then add the users to the worklist and continue. + llvm::copy(bai->getUses(), std::back_inserter(worklist)); + continue; + } + + // If we have a load, we just need to mark the load [take] as a write. + if (auto *li = dyn_cast(user)) { + if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take) { + wellBehavedWriteAccumulator.push_back(op); + } + continue; + } + + // If we have a FullApplySite, we need to do per convention/inst logic. + if (auto fas = FullApplySite::isa(user)) { + // Begin by seeing if we have an in_guaranteed use. If we do, we are done. + if (fas.getArgumentConvention(*op) == + SILArgumentConvention::Indirect_In_Guaranteed) { + continue; + } + + // Then see if we have an apply site that is not a coroutine apply + // site. In such a case, without further analysis, we can treat it like an + // instantaneous write and validate that it doesn't overlap with our load + // [copy]. + if (!fas.beginsCoroutineEvaluation() && + fas.getArgumentConvention(*op).isInoutConvention()) { + wellBehavedWriteAccumulator.push_back(op); + continue; + } + + // Otherwise, be conservative and return that we had a write that we did + // not understand. + LLVM_DEBUG(llvm::dbgs() + << "Function: " << user->getFunction()->getName() << "\n"); + LLVM_DEBUG(llvm::dbgs() << "Value: " << op->get()); + LLVM_DEBUG(llvm::dbgs() << "Unhandled apply site!: " << *user); + + return false; + } + + // Copy addr that read are just loads. + if (auto *cai = dyn_cast(user)) { + // If our value is the destination, this is a write. + if (cai->getDest() == op->get()) { + wellBehavedWriteAccumulator.push_back(op); + continue; + } + + // Ok, so we are Src by process of elimination. Make sure we are not being + // taken. + if (cai->isTakeOfSrc()) { + wellBehavedWriteAccumulator.push_back(op); + continue; + } + + // Otherwise, we are safe and can continue. + continue; + } + + // If we did not recognize the user, just return conservatively that it was + // written to in a way we did not understand. + LLVM_DEBUG(llvm::dbgs() + << "Function: " << user->getFunction()->getName() << "\n"); + LLVM_DEBUG(llvm::dbgs() << "Value: " << op->get()); + LLVM_DEBUG(llvm::dbgs() << "Unknown instruction!: " << *user); + return false; + } + + // Ok, we finished our worklist and this address is not being written to. + return true; +} + +//===----------------------------------------------------------------------===// +// Memory Analysis +//===----------------------------------------------------------------------===// + +namespace { + +/// A class that computes in a flow insensitive way if we can prove that our +/// storage is either never written to, or is initialized exactly once and never +/// written to again. In both cases, we can convert load [copy] -> load_borrow +/// safely. +class StorageGuaranteesLoadVisitor + : public AccessUseDefChainVisitor { + // The outer SemanticARCOptVisitor. + SemanticARCOptVisitor &ARCOpt; + + // The live range of the original load. + const OwnershipLiveRange &liveRange; + + // The current address being visited. + SILValue currentAddress; + + Optional isWritten; + +public: + StorageGuaranteesLoadVisitor(SemanticARCOptVisitor &arcOpt, LoadInst *load, + const OwnershipLiveRange &liveRange) + : ARCOpt(arcOpt), liveRange(liveRange), + currentAddress(load->getOperand()) {} + + void answer(bool written) { + currentAddress = nullptr; + isWritten = written; + } + + void next(SILValue address) { currentAddress = address; } + + void visitNestedAccess(BeginAccessInst *access) { + // First see if we have read/modify. If we do not, just look through the + // nested access. + switch (access->getAccessKind()) { + case SILAccessKind::Init: + case SILAccessKind::Deinit: + return next(access->getOperand()); + case SILAccessKind::Read: + case SILAccessKind::Modify: + break; + } + + // Next check if our live range is completely in the begin/end access + // scope. If so, we may be able to use a load_borrow here! + SmallVector endScopeUses; + transform(access->getEndAccesses(), std::back_inserter(endScopeUses), + [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); + SmallPtrSet visitedBlocks; + LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); + if (!checker.validateLifetime(access, endScopeUses, + liveRange.getAllConsumingUses())) { + // If we fail the linear lifetime check, then just recur: + return next(access->getOperand()); + } + + // Otherwise, if we have read, then we are done! + if (access->getAccessKind() == SILAccessKind::Read) { + return answer(false); + } + + // If we have a modify, check if our value is /ever/ written to. If it is + // never actually written to, then we convert to a load_borrow. + auto result = ARCOpt.addressToExhaustiveWriteListCache.get(access); + if (!result.hasValue()) { + return answer(true); + } + + if (result.getValue().empty()) { + return answer(false); + } + + return answer(true); + } + + void visitArgumentAccess(SILFunctionArgument *arg) { + // If this load_copy is from an indirect in_guaranteed argument, then we + // know for sure that it will never be written to. + if (arg->hasConvention(SILArgumentConvention::Indirect_In_Guaranteed)) { + return answer(false); + } + + // If we have an inout parameter that isn't ever actually written to, return + // false. + if (arg->getKnownParameterInfo().isIndirectMutating()) { + auto wellBehavedWrites = + ARCOpt.addressToExhaustiveWriteListCache.get(arg); + if (!wellBehavedWrites.hasValue()) { + return answer(true); + } + + // No writes. + if (wellBehavedWrites->empty()) { + return answer(false); + } + + // Ok, we have some writes. See if any of them are within our live + // range. If any are, we definitely can not promote to load_borrow. + SmallPtrSet visitedBlocks; + SmallVector foundBeginAccess; + LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); + SILValue introducerValue = liveRange.getIntroducer().value; + if (!checker.usesNotContainedWithinLifetime(introducerValue, + liveRange.getDestroyingUses(), + *wellBehavedWrites)) { + return answer(true); + } + + // Finally, check if our live range is strictly contained within any of + // our scoped writes. + SmallVector endAccessList; + for (Operand *use : *wellBehavedWrites) { + auto *bai = dyn_cast(use->getUser()); + if (!bai) { + continue; + } + + endAccessList.clear(); + llvm::transform( + bai->getUsersOfType(), + std::back_inserter(endAccessList), + [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); + visitedBlocks.clear(); + + // We know that our live range is based on a load [copy], so we know + // that our value must have a defining inst. + auto *definingInst = + cast(introducerValue->getDefiningInstruction()); + + // Then if our defining inst is not in our bai, endAccessList region, we + // know that the two ranges must be disjoint, so continue. + if (!checker.validateLifetime(bai, endAccessList, + &definingInst->getAllOperands()[0])) { + continue; + } + + // Otherwise, we do have an overlap, return true. + return answer(true); + } + + // Otherwise, there isn't an overlap, so we don't write to it. + return answer(false); + } + + // TODO: This should be extended: + // + // 1. We should be able to analyze in arguments and see if they are only + // ever destroyed at the end of the function. In such a case, we may be + // able to also to promote load [copy] from such args to load_borrow. + return answer(true); + } + + void visitGlobalAccess(SILValue global) { + return answer(!AccessedStorage(global, AccessedStorage::Global) + .isLetAccess(&ARCOpt.F)); + } + + void visitClassAccess(RefElementAddrInst *field) { + currentAddress = nullptr; + + // We know a let property won't be written to if the base object is + // guaranteed for the duration of the access. + // For non-let properties conservatively assume they may be written to. + if (!field->getField()->isLet()) { + return answer(true); + } + + // The lifetime of the `let` is guaranteed if it's dominated by the + // guarantee on the base. See if we can find a single borrow introducer for + // this object. If we could not find a single such borrow introducer, assume + // that our property is conservatively written to. + SILValue baseObject = field->getOperand(); + auto value = getSingleBorrowIntroducingValue(baseObject); + if (!value) { + return answer(true); + } + + // Ok, we have a single borrow introducing value. First do a quick check if + // we have a non-local scope that is a function argument. In such a case, we + // know statically that our let can not be written to in the current + // function. To be conservative, assume that all other non-local scopes + // write to memory. + if (!value->isLocalScope()) { + if (value->kind == BorrowedValueKind::SILFunctionArgument) { + return answer(false); + } + + // TODO: Once we model Coroutine results as non-local scopes, we should be + // able to return false here for them as well. + return answer(true); + } + + // TODO: This is disabled temporarily for guaranteed phi args just for + // staging purposes. Thus be conservative and assume true in these cases. + if (value->kind == BorrowedValueKind::Phi) { + return answer(true); + } + + // Ok, we now know that we have a local scope whose lifetime we need to + // analyze. With that in mind, gather up the lifetime ending uses of our + // borrow scope introducing value and then use the linear lifetime checker + // to check whether the copied value is dominated by the lifetime of the + // borrow it's based on. + SmallVector endScopeInsts; + value->visitLocalScopeEndingUses( + [&](Operand *use) { endScopeInsts.push_back(use); }); + + SmallPtrSet visitedBlocks; + LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); + + // Returns true on success. So we invert. + bool foundError = !checker.validateLifetime( + baseObject, endScopeInsts, liveRange.getAllConsumingUses()); + return answer(foundError); + } + + // TODO: Handle other access kinds? + void visitBase(SILValue base, AccessedStorage::Kind kind) { + return answer(true); + } + + void visitNonAccess(SILValue addr) { return answer(true); } + + void visitCast(SingleValueInstruction *cast, Operand *parentAddr) { + return next(parentAddr->get()); + } + + void visitPathComponent(SingleValueInstruction *projectedAddr, + Operand *parentAddr) { + return next(parentAddr->get()); + } + + void visitPhi(SILPhiArgument *phi) { + // We shouldn't have address phis in OSSA SIL, so we don't need to recur + // through the predecessors here. + return answer(true); + } + + /// See if we have an alloc_stack that is only written to once by an + /// initializing instruction. + void visitStackAccess(AllocStackInst *stack) { + SmallVector destroyAddrOperands; + bool initialAnswer = isSingleInitAllocStack(stack, destroyAddrOperands); + if (!initialAnswer) + return answer(true); + + // Then make sure that all of our load [copy] uses are within the + // destroy_addr. + SmallPtrSet visitedBlocks; + LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); + // Returns true on success. So we invert. + bool foundError = !checker.validateLifetime( + stack, destroyAddrOperands /*consuming users*/, + liveRange.getAllConsumingUses() /*non consuming users*/); + return answer(foundError); + } + + bool doIt() { + while (currentAddress) { + visit(currentAddress); + } + return *isWritten; + } +}; + +} // namespace + +bool SemanticARCOptVisitor::isWrittenTo(LoadInst *load, + const OwnershipLiveRange &lr) { + StorageGuaranteesLoadVisitor visitor(*this, load, lr); + return visitor.doIt(); +} + +//===----------------------------------------------------------------------===// +// Top Level Entrypoint +//===----------------------------------------------------------------------===// + +// Convert a load [copy] from unique storage [read] that has all uses that can +// accept a guaranteed parameter to a load_borrow. +bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) { + // This optimization can use more complex analysis. We should do some + // experiments before enabling this by default as a guaranteed optimization. + if (onlyGuaranteedOpts) + return false; + + if (li->getOwnershipQualifier() != LoadOwnershipQualifier::Copy) + return false; + + // Ok, we have our load [copy]. Make sure its value is truly a dead live range + // implying it is only ever consumed by destroy_value instructions. If it is + // consumed, we need to pass off a +1 value, so bail. + // + // FIXME: We should consider if it is worth promoting a load [copy] + // -> load_borrow if we can put a copy_value on a cold path and thus + // eliminate RR traffic on a hot path. + OwnershipLiveRange lr(li); + if (bool(lr.hasUnknownConsumingUse())) + return false; + + // Then check if our address is ever written to. If it is, then we cannot use + // the load_borrow because the stored value may be released during the loaded + // value's live range. + if (isWrittenTo(li, lr)) + return false; + + // Ok, we can perform our optimization. Convert the load [copy] into a + // load_borrow. + auto *lbi = + SILBuilderWithScope(li).createLoadBorrow(li->getLoc(), li->getOperand()); + + lr.insertEndBorrowsAtDestroys(lbi, getDeadEndBlocks(), lifetimeFrontier); + std::move(lr).convertToGuaranteedAndRAUW(lbi, getCallbacks()); + return true; +} diff --git a/lib/SILOptimizer/SemanticARC/OwnedToGuaranteedPhiOpt.cpp b/lib/SILOptimizer/SemanticARC/OwnedToGuaranteedPhiOpt.cpp new file mode 100644 index 0000000000000..b2740a0ce47ab --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/OwnedToGuaranteedPhiOpt.cpp @@ -0,0 +1,257 @@ +//===--- OwnedToGuaranteedPhiOpt.cpp --------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Late optimization that eliminates webs of owned phi nodes. +/// +//===----------------------------------------------------------------------===// + +#include "OwnershipPhiOperand.h" +#include "SemanticARCOptVisitor.h" + +using namespace swift; +using namespace swift::semanticarc; + +static bool canEliminatePhi( + SemanticARCOptVisitor::FrozenMultiMapRange optimizableIntroducerRange, + ArrayRef incomingValueOperandList, + SmallVectorImpl &ownedValueIntroducerAccumulator) { + for (auto incomingValueOperand : incomingValueOperandList) { + SILValue incomingValue = incomingValueOperand.getValue(); + + // Before we do anything, see if we have an incoming value with trivial + // ownership. This can occur in the case where we are working with enums due + // to trivial non-payloaded cases. Skip that. + if (incomingValue.getOwnershipKind() == ValueOwnershipKind::None) { + continue; + } + + // Then see if this is an introducer that we actually saw as able to be + // optimized if we could flip this joined live range. + // + // NOTE: If this linear search is too slow, we can change the multimap to + // sort the mapped to list by pointer instead of insertion order. In such a + // case, we could then bisect. + if (llvm::find(optimizableIntroducerRange, + incomingValueOperand.getOperand()) == + optimizableIntroducerRange.end()) { + return false; + } + + // Now that we know it is an owned value that we saw before, check for + // introducers of the owned value which are the copies that we may be able + // to eliminate. Since we do not look through joined live ranges, we must + // only have a single introducer. So look for that one and if not, bail. + auto singleIntroducer = getSingleOwnedValueIntroducer(incomingValue); + if (!singleIntroducer.hasValue()) { + return false; + } + + // Then make sure that our owned value introducer is able to be converted to + // guaranteed and that we found it to have a LiveRange that we could have + // eliminated /if/ we were to get rid of this phi. + if (!singleIntroducer->isConvertableToGuaranteed()) { + return false; + } + + // Otherwise, add the introducer to our result array. + ownedValueIntroducerAccumulator.push_back(*singleIntroducer); + } + +#ifndef NDEBUG + // Other parts of the pass ensure that we only add values to the list if their + // owned value introducer is not used by multiple live ranges. That being + // said, lets assert that. + { + SmallVector uniqueCheck; + llvm::copy(ownedValueIntroducerAccumulator, + std::back_inserter(uniqueCheck)); + sortUnique(uniqueCheck); + assert( + uniqueCheck.size() == ownedValueIntroducerAccumulator.size() && + "multiple joined live range operands are from the same live range?!"); + } +#endif + + return true; +} + +static bool getIncomingJoinedLiveRangeOperands( + SILValue joinedLiveRange, + SmallVectorImpl &resultingOperands) { + if (auto *phi = dyn_cast(joinedLiveRange)) { + return phi->visitIncomingPhiOperands([&](Operand *op) { + if (auto phiOp = OwnershipPhiOperand::get(op)) { + resultingOperands.push_back(*phiOp); + return true; + } + return false; + }); + } + + if (auto *svi = dyn_cast(joinedLiveRange)) { + return llvm::all_of(svi->getAllOperands(), [&](const Operand &op) { + // skip type dependent operands. + if (op.isTypeDependent()) + return true; + + auto phiOp = OwnershipPhiOperand::get(&op); + if (!phiOp) + return false; + resultingOperands.push_back(*phiOp); + return true; + }); + } + + llvm_unreachable("Unhandled joined live range?!"); +} + +//===----------------------------------------------------------------------===// +// Top Level Entrypoint +//===----------------------------------------------------------------------===// + +bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() { + bool madeChange = false; + + // First freeze our multi-map so we can use it for map queries. Also, setup a + // defer of the reset so we do not forget to reset the map when we are done. + joinedOwnedIntroducerToConsumedOperands.setFrozen(); + SWIFT_DEFER { joinedOwnedIntroducerToConsumedOperands.reset(); }; + + // Now for each phi argument that we have in our multi-map... + SmallVector incomingValueOperandList; + SmallVector ownedValueIntroducers; + for (auto pair : joinedOwnedIntroducerToConsumedOperands.getRange()) { + SWIFT_DEFER { + incomingValueOperandList.clear(); + ownedValueIntroducers.clear(); + }; + + // First compute the LiveRange for ownershipPhi value. For simplicity, we + // only handle cases now where the result does not have any additional + // ownershipPhi uses. + SILValue joinedIntroducer = pair.first; + OwnershipLiveRange joinedLiveRange(joinedIntroducer); + if (bool(joinedLiveRange.hasUnknownConsumingUse())) { + continue; + } + + // Ok, we know that our phi argument /could/ be converted to guaranteed if + // our incoming values are able to be converted to guaranteed. Now for each + // incoming value, compute the incoming values ownership roots and see if + // all of the ownership roots are in our owned incoming value array. + if (!getIncomingJoinedLiveRangeOperands(joinedIntroducer, + incomingValueOperandList)) { + continue; + } + + // Grab our list of introducer values paired with this SILArgument. See if + // all of these introducer values were ones that /could/ have been + // eliminated if it was not for the given phi. If all of them are, we can + // optimize! + { + auto rawFoundOptimizableIntroducerArray = pair.second; + if (!canEliminatePhi(rawFoundOptimizableIntroducerArray, + incomingValueOperandList, ownedValueIntroducers)) { + continue; + } + } + + // Ok, at this point we know that we can eliminate this phi. First go + // through the list of incomingValueOperandList and stash the value/set the + // operand's stored value to undef. We will hook them back up later. + SmallVector originalIncomingValues; + for (auto &incomingValueOperand : incomingValueOperandList) { + originalIncomingValues.push_back(incomingValueOperand.getValue()); + incomingValueOperand.markUndef(); + } + + // Then go through all of our owned value introducers, compute their live + // ranges, and eliminate them. We know it is safe to remove them from our + // previous proofs. + // + // NOTE: If our introducer is a copy_value that is one of our + // originalIncomingValues, we need to update the originalIncomingValue array + // with that value since we are going to delete the copy_value here. This + // creates a complication since we want to binary_search on + // originalIncomingValues to detect this same condition! So, we create a + // list of updates that we apply after we no longer need to perform + // binary_search, but before we start RAUWing things. + SmallVector, 8> incomingValueUpdates; + for (auto introducer : ownedValueIntroducers) { + SILValue v = introducer.value; + OwnershipLiveRange lr(v); + + // For now, we only handle copy_value for simplicity. + // + // TODO: Add support for load [copy]. + if (introducer.kind == OwnedValueIntroducerKind::Copy) { + auto *cvi = cast(v); + // Before we convert from owned to guaranteed, we need to first see if + // cvi is one of our originalIncomingValues. If so, we need to set + // originalIncomingValues to be cvi->getOperand(). Otherwise, weirdness + // results since we are deleting one of our stashed values. + auto iter = find(originalIncomingValues, cvi); + if (iter != originalIncomingValues.end()) { + // We use an auxillary array here so we can continue to bisect on + // original incoming values. Once we are done processing here, we will + // not need that property anymore. + unsigned updateOffset = + std::distance(originalIncomingValues.begin(), iter); + incomingValueUpdates.emplace_back(cvi->getOperand(), updateOffset); + } + std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), + getCallbacks()); + continue; + } + llvm_unreachable("Unhandled optimizable introducer!"); + } + + // Now go through and update our original incoming value array now that we + // do not need it to be sorted for bisection purposes. + while (!incomingValueUpdates.empty()) { + auto pair = incomingValueUpdates.pop_back_val(); + originalIncomingValues[pair.second] = pair.first; + } + + // Then convert the phi's live range to be guaranteed. + std::move(joinedLiveRange) + .convertJoinedLiveRangePhiToGuaranteed( + getDeadEndBlocks(), lifetimeFrontier, getCallbacks()); + + // Now if our phi operand consumes/forwards its guaranteed input, insert a + // begin_borrow along the incoming value edges. We have to do this after + // converting the incoming values to be guaranteed to avoid tripping + // SILBuilder checks around simple ownership invariants (namely that def/use + // line up) when creating instructions. + assert(incomingValueOperandList.size() == originalIncomingValues.size()); + while (!incomingValueOperandList.empty()) { + auto incomingValueOperand = incomingValueOperandList.pop_back_val(); + SILValue originalValue = originalIncomingValues.pop_back_val(); + if (incomingValueOperand.isGuaranteedConsuming() && + originalValue.getOwnershipKind() != ValueOwnershipKind::None) { + auto loc = RegularLocation::getAutoGeneratedLocation(); + SILBuilderWithScope builder(incomingValueOperand.getInst()); + originalValue = builder.createBeginBorrow(loc, originalValue); + } + incomingValueOperand.getOperand()->set(originalValue); + } + + madeChange = true; + if (VerifyAfterTransform) { + F.verify(); + } + } + + return madeChange; +} diff --git a/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp b/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp new file mode 100644 index 0000000000000..187b28e68c27b --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp @@ -0,0 +1,354 @@ +//===--- OwnershipLiveRange.cpp -------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "OwnershipLiveRange.h" +#include "OwnershipPhiOperand.h" + +using namespace swift; +using namespace swift::semanticarc; + +OwnershipLiveRange::OwnershipLiveRange(SILValue value) + : introducer(*OwnedValueIntroducer::get(value)), destroyingUses(), + ownershipForwardingUses(), unknownConsumingUses() { + assert(introducer.value.getOwnershipKind() == ValueOwnershipKind::Owned); + + SmallVector tmpDestroyingUses; + SmallVector tmpForwardingConsumingUses; + SmallVector tmpUnknownConsumingUses; + + // We know that our silvalue produces an @owned value. Look through all of our + // uses and classify them as either consuming or not. + SmallVector worklist(introducer.value->getUses()); + while (!worklist.empty()) { + auto *op = worklist.pop_back_val(); + + // Skip type dependent operands. + if (op->isTypeDependent()) + continue; + + // Do a quick check that we did not add ValueOwnershipKind that are not + // owned to the worklist. + assert(op->get().getOwnershipKind() == ValueOwnershipKind::Owned && + "Added non-owned value to worklist?!"); + + auto *user = op->getUser(); + + // Ok, this constraint can take something owned as live. Assert that it + // can also accept something that is guaranteed. Any non-consuming use of + // an owned value should be able to take a guaranteed parameter as well + // (modulo bugs). We assert to catch these. + if (!op->isConsumingUse()) { + continue; + } + + // Ok, we know now that we have a consuming use. See if we have a destroy + // value, quickly up front. If we do have one, stash it and continue. + if (isa(user)) { + tmpDestroyingUses.push_back(op); + continue; + } + + // Otherwise, see if we have a forwarding value that has a single + // non-trivial operand that can accept a guaranteed value. If not, we can + // not recursively process it, so be conservative and assume that we /may + // consume/ the value, so the live range must not be eliminated. + // + // DISCUSSION: For now we do not support forwarding instructions with + // multiple non-trivial arguments since we would need to optimize all of + // the non-trivial arguments at the same time. + // + // NOTE: Today we do not support TermInsts for simplicity... we /could/ + // support it though if we need to. + auto *ti = dyn_cast(user); + if ((ti && !ti->isTransformationTerminator()) || + !isGuaranteedForwardingInst(user) || + 1 != count_if(user->getOperandValues( + true /*ignore type dependent operands*/), + [&](SILValue v) { + return v.getOwnershipKind() == + ValueOwnershipKind::Owned; + })) { + tmpUnknownConsumingUses.push_back(op); + continue; + } + + // Ok, this is a forwarding instruction whose ownership we can flip from + // owned -> guaranteed. + tmpForwardingConsumingUses.push_back(op); + + // If we have a non-terminator, just visit its users recursively to see if + // the the users force the live range to be alive. + if (!ti) { + for (SILValue v : user->getResults()) { + if (v.getOwnershipKind() != ValueOwnershipKind::Owned) + continue; + llvm::copy(v->getUses(), std::back_inserter(worklist)); + } + continue; + } + + // Otherwise, we know that we have no only a terminator, but a + // transformation terminator, so we should add the users of its results to + // the worklist. + for (auto &succ : ti->getSuccessors()) { + auto *succBlock = succ.getBB(); + + // If we do not have any arguments, then continue. + if (succBlock->args_empty()) + continue; + + for (auto *succArg : succBlock->getSILPhiArguments()) { + // If we have an any value, just continue. + if (succArg->getOwnershipKind() == ValueOwnershipKind::None) + continue; + + // Otherwise add all users of this BBArg to the worklist to visit + // recursively. + llvm::copy(succArg->getUses(), std::back_inserter(worklist)); + } + } + } + + // The order in which we append these to consumingUses matters since we assume + // their order as an invariant. This is done to ensure that we can pass off + // all of our uses or individual sub-arrays of our users without needing to + // move around memory. + llvm::copy(tmpDestroyingUses, std::back_inserter(consumingUses)); + llvm::copy(tmpForwardingConsumingUses, std::back_inserter(consumingUses)); + llvm::copy(tmpUnknownConsumingUses, std::back_inserter(consumingUses)); + + auto cUseArrayRef = llvm::makeArrayRef(consumingUses); + destroyingUses = cUseArrayRef.take_front(tmpDestroyingUses.size()); + ownershipForwardingUses = cUseArrayRef.slice( + tmpDestroyingUses.size(), tmpForwardingConsumingUses.size()); + unknownConsumingUses = cUseArrayRef.take_back(tmpUnknownConsumingUses.size()); +} + +void OwnershipLiveRange::insertEndBorrowsAtDestroys( + SILValue newGuaranteedValue, DeadEndBlocks &deadEndBlocks, + ValueLifetimeAnalysis::Frontier &scratch) { + assert(scratch.empty() && "Expected scratch to be initially empty?!"); + + // Since we are looking through forwarding uses that can accept guaranteed + // parameters, we can have multiple destroy_value along the same path. We need + // to find the post-dominating block set of these destroy value to ensure that + // we do not insert multiple end_borrow. + // + // TODO: Hoist this out? + SILInstruction *inst = introducer.value->getDefiningInstruction(); + Optional analysis; + if (!inst) { + analysis.emplace(cast(introducer.value), + getAllConsumingInsts()); + } else { + analysis.emplace(inst, getAllConsumingInsts()); + } + + // Use all consuming uses in our value lifetime analysis to ensure correctness + // in the face of unreachable code. + bool foundCriticalEdges = !analysis->computeFrontier( + scratch, ValueLifetimeAnalysis::DontModifyCFG, &deadEndBlocks); + (void)foundCriticalEdges; + assert(!foundCriticalEdges); + auto loc = RegularLocation::getAutoGeneratedLocation(); + while (!scratch.empty()) { + auto *insertPoint = scratch.pop_back_val(); + SILBuilderWithScope builder(insertPoint); + builder.createEndBorrow(loc, newGuaranteedValue); + } +} + +static void convertInstructionOwnership(SILInstruction *i, + ValueOwnershipKind oldOwnership, + ValueOwnershipKind newOwnership) { + // If this is a term inst, just convert all of its incoming values that are + // owned to be guaranteed. + if (auto *ti = dyn_cast(i)) { + for (auto &succ : ti->getSuccessors()) { + auto *succBlock = succ.getBB(); + + // If we do not have any arguments, then continue. + if (succBlock->args_empty()) + continue; + + for (auto *succArg : succBlock->getSILPhiArguments()) { + // If we have an any value, just continue. + if (succArg->getOwnershipKind() == oldOwnership) { + succArg->setOwnershipKind(newOwnership); + } + } + } + return; + } + + assert(i->hasResults()); + for (SILValue result : i->getResults()) { + if (auto *svi = dyn_cast(result)) { + if (svi->getOwnershipKind() == oldOwnership) { + svi->setOwnershipKind(newOwnership); + } + continue; + } + + if (auto *ofci = dyn_cast(result)) { + if (ofci->getOwnershipKind() == oldOwnership) { + ofci->setOwnershipKind(newOwnership); + } + continue; + } + + if (auto *sei = dyn_cast(result)) { + if (sei->getOwnershipKind() == oldOwnership) { + sei->setOwnershipKind(newOwnership); + } + continue; + } + + if (auto *mvir = dyn_cast(result)) { + if (mvir->getOwnershipKind() == oldOwnership) { + mvir->setOwnershipKind(newOwnership); + } + continue; + } + + llvm_unreachable("unhandled forwarding instruction?!"); + } +} + +void OwnershipLiveRange::convertOwnedGeneralForwardingUsesToGuaranteed() && { + while (!ownershipForwardingUses.empty()) { + auto *i = ownershipForwardingUses.back()->getUser(); + ownershipForwardingUses = ownershipForwardingUses.drop_back(); + convertInstructionOwnership(i, ValueOwnershipKind::Owned, + ValueOwnershipKind::Guaranteed); + } +} + +void OwnershipLiveRange::convertToGuaranteedAndRAUW( + SILValue newGuaranteedValue, InstModCallbacks callbacks) && { + auto *value = cast(introducer.value); + while (!destroyingUses.empty()) { + auto *d = destroyingUses.back(); + destroyingUses = destroyingUses.drop_back(); + callbacks.deleteInst(d->getUser()); + } + + callbacks.eraseAndRAUWSingleValueInst(value, newGuaranteedValue); + + // Then change all of our guaranteed forwarding insts to have guaranteed + // ownership kind instead of what ever they previously had (ignoring trivial + // results); + std::move(*this).convertOwnedGeneralForwardingUsesToGuaranteed(); +} + +// TODO: If this is useful, move onto OwnedValueIntroducer itself? +static SILValue convertIntroducerToGuaranteed(OwnedValueIntroducer introducer) { + switch (introducer.kind) { + case OwnedValueIntroducerKind::Phi: { + auto *phiArg = cast(introducer.value); + phiArg->setOwnershipKind(ValueOwnershipKind::Guaranteed); + return phiArg; + } + case OwnedValueIntroducerKind::Struct: { + auto *si = cast(introducer.value); + si->setOwnershipKind(ValueOwnershipKind::Guaranteed); + return si; + } + case OwnedValueIntroducerKind::Tuple: { + auto *ti = cast(introducer.value); + ti->setOwnershipKind(ValueOwnershipKind::Guaranteed); + return ti; + } + case OwnedValueIntroducerKind::Copy: + case OwnedValueIntroducerKind::LoadCopy: + case OwnedValueIntroducerKind::Apply: + case OwnedValueIntroducerKind::BeginApply: + case OwnedValueIntroducerKind::TryApply: + case OwnedValueIntroducerKind::LoadTake: + case OwnedValueIntroducerKind::FunctionArgument: + case OwnedValueIntroducerKind::PartialApplyInit: + case OwnedValueIntroducerKind::AllocBoxInit: + case OwnedValueIntroducerKind::AllocRefInit: + return SILValue(); + } +} + +void OwnershipLiveRange::convertJoinedLiveRangePhiToGuaranteed( + DeadEndBlocks &deadEndBlocks, ValueLifetimeAnalysis::Frontier &scratch, + InstModCallbacks callbacks) && { + + // First convert the phi value itself to be guaranteed. + SILValue phiValue = convertIntroducerToGuaranteed(introducer); + + // Then insert end_borrows at each of our destroys if we are consuming. We + // have to convert the phi to guaranteed first since otherwise, the ownership + // check when we create the end_borrows will trigger. + if (introducer.hasConsumingGuaranteedOperands()) { + insertEndBorrowsAtDestroys(phiValue, deadEndBlocks, scratch); + } + + // Then eliminate all of the destroys... + while (!destroyingUses.empty()) { + auto *d = destroyingUses.back(); + destroyingUses = destroyingUses.drop_back(); + callbacks.deleteInst(d->getUser()); + } + + // and change all of our guaranteed forwarding insts to have guaranteed + // ownership kind instead of what ever they previously had (ignoring trivial + // results); + std::move(*this).convertOwnedGeneralForwardingUsesToGuaranteed(); +} + +OwnershipLiveRange::HasConsumingUse_t +OwnershipLiveRange::hasUnknownConsumingUse(bool assumingAtFixPoint) const { + // First do a quick check if we have /any/ unknown consuming + // uses. If we do not have any, return false early. + if (unknownConsumingUses.empty()) { + return HasConsumingUse_t::No; + } + + // Ok, we do have some unknown consuming uses. If we aren't assuming we are at + // the fixed point yet, just bail. + if (!assumingAtFixPoint) { + return HasConsumingUse_t::Yes; + } + + // We do not know how to handle yet cases where an owned value is used by + // multiple phi nodes. So we bail early if unknown consuming uses is > 1. + // + // TODO: Build up phi node web. + auto *op = getSingleUnknownConsumingUse(); + if (!op) { + return HasConsumingUse_t::Yes; + } + + // Make sure our single unknown consuming use is a branch inst. If not, bail, + // this is a /real/ unknown consuming use. + if (!OwnershipPhiOperand::get(op)) { + return HasConsumingUse_t::Yes; + } + + // Otherwise, setup the phi to incoming value map mapping the block arguments + // to our introducer. + return HasConsumingUse_t::YesButAllPhiArgs; +} + +OwnershipLiveRange::DestroyingInstsRange +OwnershipLiveRange::getDestroyingInsts() const { + return DestroyingInstsRange(getDestroyingUses(), OperandToUser()); +} + +OwnershipLiveRange::ConsumingInstsRange +OwnershipLiveRange::getAllConsumingInsts() const { + return ConsumingInstsRange(consumingUses, OperandToUser()); +} diff --git a/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.h b/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.h new file mode 100644 index 0000000000000..c9be71b479a3b --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.h @@ -0,0 +1,210 @@ +//===--- OwnershipLiveRange.h ---------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPLIVERANGE_H +#define SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPLIVERANGE_H + +#include "swift/SIL/OwnershipUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" + +namespace swift { +namespace semanticarc { + +/// This class represents an "extended live range" of an owned value. Such a +/// representation includes: +/// +/// 1. The owned introducing value. +/// 2. Any forwarding instructions that consume the introduced value +/// (transitively) and then propagate a new owned value. +/// 3. Transitive destroys on the forwarding instructions/destroys on the owned +/// introducing value. +/// 4. Any unknown consuming uses that are not understood by this code. +/// +/// This allows for this to be used to convert such a set of uses from using +/// owned ownership to using guaranteed ownership by converting the +/// destroy_value -> end_borrow and "flipping" the ownership of individual +/// forwarding instructions. +/// +/// NOTE: We do not look through "phi nodes" in the ownership graph (e.x.: real +/// phi arguments, struct, tuple). Instead we represent those as nodes in a +/// larger phi ownership web, connected via individual OwnershipLiveRange. +class LLVM_LIBRARY_VISIBILITY OwnershipLiveRange { + /// The value that we are computing the LiveRange for. Expected to be an owned + /// introducer and not to be forwarding. + OwnedValueIntroducer introducer; + + /// A vector that we store all of our uses into. + /// + /// Some properties of this array are: + /// + /// 1. It is only mutated in the constructor of LiveRange. + /// + /// 2. destroyingUses, ownershipForwardingUses, and unknownConsumingUses are + /// views into this array. We store the respective uses in the aforementioned + /// order. This is why it is important not to mutate consumingUses after we + /// construct the LiveRange since going from small -> large could invalidate + /// the uses. + SmallVector consumingUses; + + /// A list of destroy_values of the live range. + /// + /// This is just a view into consuming uses. + ArrayRef destroyingUses; + + /// A list of forwarding instructions that forward owned ownership, but that + /// are also able to be converted to guaranteed ownership. + /// + /// If we are able to eliminate this LiveRange due to it being from a + /// guaranteed value, we must flip the ownership of all of these instructions + /// to guaranteed from owned. + /// + /// NOTE: Normally only destroying or consuming uses end the live range. We + /// copy these transitive uses as well into the consumingUses array since + /// transitive uses can extend a live range up to an unreachable block without + /// ultimately being consuming. In such a situation if we did not also store + /// this into consuming uses, we would not be able to ascertain just using the + /// "consumingUses" array the true lifetime of the OwnershipLiveRange. + /// + /// Corresponds to isOwnershipForwardingInst(...). + ArrayRef ownershipForwardingUses; + + /// Consuming uses that we were not able to understand as a forwarding + /// instruction or a destroy_value. These must be passed a strongly control + /// equivalent +1 value. + ArrayRef unknownConsumingUses; + +public: + OwnershipLiveRange(SILValue value); + OwnershipLiveRange(const OwnershipLiveRange &) = delete; + OwnershipLiveRange &operator=(const OwnershipLiveRange &) = delete; + + enum class HasConsumingUse_t { + No = 0, + YesButAllPhiArgs = 1, + Yes = 2, + }; + + /// Return true if v only has invalidating uses that are destroy_value. Such + /// an owned value is said to represent a dead "live range". + /// + /// Semantically this implies that a value is never passed off as +1 to memory + /// or another function implying it can be used everywhere at +0. + HasConsumingUse_t + hasUnknownConsumingUse(bool assumingFixedPoint = false) const; + + /// Return an array ref to /all/ consuming uses. Will include all 3 sorts of + /// consuming uses: destroying uses, forwarding consuming uses, and unknown + /// forwarding instruction. + ArrayRef getAllConsumingUses() const { return consumingUses; } + + ArrayRef getDestroyingUses() const { return destroyingUses; } + +private: + struct OperandToUser; + +public: + using DestroyingInstsRange = + TransformRange, OperandToUser>; + DestroyingInstsRange getDestroyingInsts() const; + + using ConsumingInstsRange = + TransformRange, OperandToUser>; + ConsumingInstsRange getAllConsumingInsts() const; + + /// If this LiveRange has a single destroying use, return that use. Otherwise, + /// return nullptr. + Operand *getSingleDestroyingUse() const { + if (destroyingUses.size() != 1) { + return nullptr; + } + return destroyingUses.front(); + } + + /// If this LiveRange has a single unknown destroying use, return that + /// use. Otherwise, return nullptr. + Operand *getSingleUnknownConsumingUse() const { + if (unknownConsumingUses.size() != 1) { + return nullptr; + } + return unknownConsumingUses.front(); + } + + OwnedValueIntroducer getIntroducer() const { return introducer; } + + ArrayRef getOwnershipForwardingUses() const { + return ownershipForwardingUses; + } + + void convertOwnedGeneralForwardingUsesToGuaranteed() &&; + + /// A consuming operation that: + /// + /// 1. If \p insertEndBorrows is true inserts end borrows at all + /// destroying insts locations. + /// + /// 2. Deletes all destroy_values. + /// + /// 3. RAUW value with newGuaranteedValue. + /// + /// 4. Convert all of the general forwarding instructions from + /// @owned -> @guaranteed. "Like Dominoes". + /// + /// 5. Leaves all of the unknown consuming users alone. It is up to + /// the caller to handle converting their ownership. + void convertToGuaranteedAndRAUW(SILValue newGuaranteedValue, + InstModCallbacks callbacks) &&; + + /// A consuming operation that in order: + /// + /// 1. Converts the phi argument to be guaranteed via setOwnership. + /// + /// 2. If this consumes a borrow, insert end_borrows at the relevant + /// destroy_values. + /// + /// 3. Deletes all destroy_values. + /// + /// 4. Converts all of the general forwarding instructions from @owned -> + /// @guaranteed. "Like Dominoes". + /// + /// NOTE: This leaves all of the unknown consuming users alone. It is up to + /// the caller to handle converting their ownership. + /// + /// NOTE: This routine leaves inserting begin_borrows for the incoming values + /// to the caller since those are not part of the LiveRange itself. + void convertJoinedLiveRangePhiToGuaranteed( + DeadEndBlocks &deadEndBlocks, ValueLifetimeAnalysis::Frontier &scratch, + InstModCallbacks callbacks) &&; + + /// Given a new guaranteed value, insert end_borrow for the newGuaranteedValue + /// at all of our destroy_values in prepration for converting from owned to + /// guaranteed. + /// + /// This is used when converting load [copy] -> load_borrow. + void insertEndBorrowsAtDestroys(SILValue newGuaranteedValue, + DeadEndBlocks &deadEndBlocks, + ValueLifetimeAnalysis::Frontier &scratch); +}; + +struct OwnershipLiveRange::OperandToUser { + OperandToUser() {} + + SILInstruction *operator()(const Operand *use) const { + auto *nonConstUse = const_cast(use); + return nonConstUse->getUser(); + } +}; + +} // namespace semanticarc +} // namespace swift + +#endif // SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPLIVERANGE_H diff --git a/lib/SILOptimizer/SemanticARC/OwnershipPhiOperand.h b/lib/SILOptimizer/SemanticARC/OwnershipPhiOperand.h new file mode 100644 index 0000000000000..169eb9859bea8 --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/OwnershipPhiOperand.h @@ -0,0 +1,122 @@ +//===--- OwnershipPhiOperand.h --------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPPHIOPERAND_H +#define SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPPHIOPERAND_H + +#include "swift/Basic/STLExtras.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBasicBlock.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILUndef.h" +#include "swift/SIL/SILValue.h" + +namespace swift { +namespace semanticarc { + +/// The operand of a "phi" in the induced ownership graph of a def-use graph. +/// +/// Some examples: br, struct, tuple. +class LLVM_LIBRARY_VISIBILITY OwnershipPhiOperand { +public: + enum Kind { + Branch, + Struct, + Tuple, + }; + +private: + Operand *op; + + OwnershipPhiOperand(Operand *op) : op(op) {} + +public: + static Optional get(const Operand *op) { + switch (op->getUser()->getKind()) { + case SILInstructionKind::BranchInst: + case SILInstructionKind::StructInst: + case SILInstructionKind::TupleInst: + return {{const_cast(op)}}; + default: + return None; + } + } + + Kind getKind() const { + switch (op->getUser()->getKind()) { + case SILInstructionKind::BranchInst: + return Kind::Branch; + case SILInstructionKind::StructInst: + return Kind::Struct; + case SILInstructionKind::TupleInst: + return Kind::Tuple; + default: + llvm_unreachable("unhandled case?!"); + } + } + + Operand *getOperand() const { return op; } + SILValue getValue() const { return op->get(); } + SILType getType() const { return op->get()->getType(); } + + unsigned getOperandNumber() const { return op->getOperandNumber(); } + + void markUndef() & { + op->set(SILUndef::get(getType(), *op->getUser()->getFunction())); + } + + SILInstruction *getInst() const { return op->getUser(); } + + /// Return true if this phi consumes a borrow. + /// + /// If so, we may need to insert an extra begin_borrow to balance the +1 when + /// converting owned ownership phis to guaranteed ownership phis. + bool isGuaranteedConsuming() const { + switch (getKind()) { + case Kind::Branch: + return true; + case Kind::Tuple: + case Kind::Struct: + return false; + } + } + + bool operator<(const OwnershipPhiOperand &other) const { + return op < other.op; + } + + bool operator==(const OwnershipPhiOperand &other) const { + return op == other.op; + } + + bool visitResults(function_ref visitor) const { + switch (getKind()) { + case Kind::Struct: + return visitor(cast(getInst())); + case Kind::Tuple: + return visitor(cast(getInst())); + case Kind::Branch: { + auto *br = cast(getInst()); + unsigned opNum = getOperandNumber(); + return llvm::all_of( + br->getSuccessorBlocks(), [&](SILBasicBlock *succBlock) { + return visitor(succBlock->getSILPhiArguments()[opNum]); + }); + } + } + } +}; + +} // namespace semanticarc +} // namespace swift + +#endif // SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPPHIOPERAND_H diff --git a/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h b/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h new file mode 100644 index 0000000000000..038ca712fce8e --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h @@ -0,0 +1,256 @@ +//===--- SemanticARCOptVisitor.h ------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_SEMANTICARC_SEMANTICARCOPTVISITOR_H +#define SWIFT_SILOPTIMIZER_SEMANTICARC_SEMANTICARCOPTVISITOR_H + +#include "OwnershipLiveRange.h" + +#include "swift/Basic/BlotSetVector.h" +#include "swift/Basic/FrozenMultiMap.h" +#include "swift/Basic/MultiMapCache.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SIL/OwnershipUtils.h" +#include "swift/SIL/SILVisitor.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" + +namespace swift { +namespace semanticarc { + +extern bool VerifyAfterTransform; + +bool constructCacheValue( + SILValue initialValue, + SmallVectorImpl &wellBehavedWriteAccumulator); + +/// A visitor that optimizes ownership instructions and eliminates any trivially +/// dead code that results after optimization. It uses an internal worklist that +/// is initialized on construction with targets to avoid iterator invalidation +/// issues. Rather than revisit the entire CFG like SILCombine and other +/// visitors do, we maintain a visitedSinceLastMutation list to ensure that we +/// revisit all interesting instructions in between mutations. +struct LLVM_LIBRARY_VISIBILITY SemanticARCOptVisitor + : SILInstructionVisitor { + /// Our main worklist. We use this after an initial run through. + SmallBlotSetVector worklist; + + /// A set of values that we have visited since the last mutation. We use this + /// to ensure that we do not visit values twice without mutating. + /// + /// This is specifically to ensure that we do not go into an infinite loop + /// when visiting phi nodes. + SmallBlotSetVector visitedSinceLastMutation; + + SILFunction &F; + Optional TheDeadEndBlocks; + ValueLifetimeAnalysis::Frontier lifetimeFrontier; + SmallMultiMapCache addressToExhaustiveWriteListCache; + + /// Are we assuming that we reached a fix point and are re-processing to + /// prepare to use the phiToIncomingValueMultiMap. + bool assumingAtFixedPoint = false; + + /// A map from a value that acts as a "joined owned introducer" in the def-use + /// graph. + /// + /// A "joined owned introducer" is a value with owned ownership whose + /// ownership is derived from multiple non-trivial owned operands of a related + /// instruction. Some examples are phi arguments, tuples, structs. Naturally, + /// all of these instructions must be non-unary instructions and only have + /// this property if they have multiple operands that are non-trivial. + /// + /// In such a case, we can not just treat them like normal forwarding concepts + /// since we can only eliminate optimize such a value if we are able to reason + /// about all of its operands together jointly. This is not amenable to a + /// small peephole analysis. + /// + /// Instead, as we perform the peephole analysis, using the multimap, we map + /// each joined owned value introducer to the set of its @owned operands that + /// we thought we could convert to guaranteed only if we could do the same to + /// the joined owned value introducer. Then once we finish performing + /// peepholes, we iterate through the map and see if any of our joined phi + /// ranges had all of their operand's marked with this property by iterating + /// over the multimap. Since we are dealing with owned values and we know that + /// our LiveRange can not see through joined live ranges, we know that we + /// should only be able to have a single owned value introducer for each + /// consumed operand. + FrozenMultiMap joinedOwnedIntroducerToConsumedOperands; + + /// If set to true, then we should only run cheap optimizations that do not + /// build up data structures or analyze code in depth. + /// + /// As an example, we do not do load [copy] optimizations here since they + /// generally involve more complex analysis, but simple peepholes of + /// copy_values we /do/ allow. + bool onlyGuaranteedOpts; + + using FrozenMultiMapRange = + decltype(joinedOwnedIntroducerToConsumedOperands)::PairToSecondEltRange; + + explicit SemanticARCOptVisitor(SILFunction &F, bool onlyGuaranteedOpts) + : F(F), addressToExhaustiveWriteListCache(constructCacheValue), + onlyGuaranteedOpts(onlyGuaranteedOpts) {} + + DeadEndBlocks &getDeadEndBlocks() { + if (!TheDeadEndBlocks) + TheDeadEndBlocks.emplace(&F); + return *TheDeadEndBlocks; + } + + /// Given a single value instruction, RAUW it with newValue, add newValue to + /// the worklist, and then call eraseInstruction on i. + void eraseAndRAUWSingleValueInstruction(SingleValueInstruction *i, + SILValue newValue) { + worklist.insert(newValue); + for (auto *use : i->getUses()) { + for (SILValue result : use->getUser()->getResults()) { + worklist.insert(result); + } + } + i->replaceAllUsesWith(newValue); + eraseInstructionAndAddOperandsToWorklist(i); + } + + /// Add all operands of i to the worklist and then call eraseInstruction on + /// i. Assumes that the instruction doesnt have users. + void eraseInstructionAndAddOperandsToWorklist(SILInstruction *i) { + // Then copy all operands into the worklist for future processing. + for (SILValue v : i->getOperandValues()) { + worklist.insert(v); + } + eraseInstruction(i); + } + + /// Pop values off of visitedSinceLastMutation, adding .some values to the + /// worklist. + void drainVisitedSinceLastMutationIntoWorklist() { + while (!visitedSinceLastMutation.empty()) { + Optional nextValue = visitedSinceLastMutation.pop_back_val(); + if (!nextValue.hasValue()) { + continue; + } + worklist.insert(*nextValue); + } + } + + /// Remove all results of the given instruction from the worklist and then + /// erase the instruction. Assumes that the instruction does not have any + /// users left. + void eraseInstruction(SILInstruction *i) { + // Remove all SILValues of the instruction from the worklist and then erase + // the instruction. + for (SILValue result : i->getResults()) { + worklist.erase(result); + visitedSinceLastMutation.erase(result); + } + i->eraseFromParent(); + + // Add everything else from visitedSinceLastMutation to the worklist. + drainVisitedSinceLastMutationIntoWorklist(); + } + + InstModCallbacks getCallbacks() { + return InstModCallbacks( + [this](SILInstruction *inst) { eraseInstruction(inst); }, + [](SILInstruction *) {}, [](SILValue, SILValue) {}, + [this](SingleValueInstruction *i, SILValue value) { + eraseAndRAUWSingleValueInstruction(i, value); + }); + } + + /// The default visitor. + bool visitSILInstruction(SILInstruction *i) { + assert(!isGuaranteedForwardingInst(i) && + "Should have forwarding visitor for all ownership forwarding " + "instructions"); + return false; + } + + bool visitCopyValueInst(CopyValueInst *cvi); + bool visitBeginBorrowInst(BeginBorrowInst *bbi); + bool visitLoadInst(LoadInst *li); + static bool shouldVisitInst(SILInstruction *i) { + switch (i->getKind()) { + default: + return false; + case SILInstructionKind::CopyValueInst: + case SILInstructionKind::BeginBorrowInst: + case SILInstructionKind::LoadInst: + return true; + } + } + +#define FORWARDING_INST(NAME) \ + bool visit##NAME##Inst(NAME##Inst *cls) { \ + for (SILValue v : cls->getResults()) { \ + worklist.insert(v); \ + } \ + return false; \ + } + FORWARDING_INST(Tuple) + FORWARDING_INST(Struct) + FORWARDING_INST(Enum) + FORWARDING_INST(OpenExistentialRef) + FORWARDING_INST(Upcast) + FORWARDING_INST(UncheckedRefCast) + FORWARDING_INST(ConvertFunction) + FORWARDING_INST(RefToBridgeObject) + FORWARDING_INST(BridgeObjectToRef) + FORWARDING_INST(UnconditionalCheckedCast) + FORWARDING_INST(UncheckedEnumData) + FORWARDING_INST(MarkUninitialized) + FORWARDING_INST(SelectEnum) + FORWARDING_INST(DestructureStruct) + FORWARDING_INST(DestructureTuple) + FORWARDING_INST(TupleExtract) + FORWARDING_INST(StructExtract) + FORWARDING_INST(OpenExistentialValue) + FORWARDING_INST(OpenExistentialBoxValue) + FORWARDING_INST(MarkDependence) + FORWARDING_INST(InitExistentialRef) + FORWARDING_INST(DifferentiableFunction) + FORWARDING_INST(LinearFunction) + FORWARDING_INST(DifferentiableFunctionExtract) + FORWARDING_INST(LinearFunctionExtract) +#undef FORWARDING_INST + +#define FORWARDING_TERM(NAME) \ + bool visit##NAME##Inst(NAME##Inst *cls) { \ + for (auto succValues : cls->getSuccessorBlockArgumentLists()) { \ + for (SILValue v : succValues) { \ + worklist.insert(v); \ + } \ + } \ + return false; \ + } + + FORWARDING_TERM(SwitchEnum) + FORWARDING_TERM(CheckedCastBranch) + FORWARDING_TERM(Branch) +#undef FORWARDING_TERM + + bool isWrittenTo(LoadInst *li, const OwnershipLiveRange &lr); + + bool processWorklist(); + bool optimize(); + + bool performGuaranteedCopyValueOptimization(CopyValueInst *cvi); + bool eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi); + bool tryJoiningCopyValueLiveRangeWithOperand(CopyValueInst *cvi); + bool performPostPeepholeOwnedArgElimination(); +}; + +} // namespace semanticarc +} // namespace swift + +#endif // SWIFT_SILOPTIMIZER_SEMANTICARC_SEMANTICARCOPTVISITOR_H diff --git a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp new file mode 100644 index 0000000000000..ba60b34bf9982 --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp @@ -0,0 +1,210 @@ +//===--- SemanticARCOpts.cpp ----------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sil-semantic-arc-opts" + +#include "swift/Basic/LLVM.h" + +#include "OwnershipLiveRange.h" +#include "OwnershipPhiOperand.h" +#include "SemanticARCOptVisitor.h" + +#include "swift/Basic/BlotSetVector.h" +#include "swift/Basic/FrozenMultiMap.h" +#include "swift/Basic/MultiMapCache.h" +#include "swift/Basic/STLExtras.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SIL/DebugUtils.h" +#include "swift/SIL/LinearLifetimeChecker.h" +#include "swift/SIL/MemAccessUtils.h" +#include "swift/SIL/OwnershipUtils.h" +#include "swift/SIL/Projection.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILVisitor.h" +#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/CommandLine.h" + +using namespace swift; +using namespace swift::semanticarc; + +//===----------------------------------------------------------------------===// +// Implementation +//===----------------------------------------------------------------------===// + +bool swift::semanticarc::VerifyAfterTransform; + +static llvm::cl::opt VerifyAfterTransformOption( + "sil-semantic-arc-opts-verify-after-transform", llvm::cl::Hidden, + llvm::cl::location(VerifyAfterTransform), llvm::cl::init(false)); + +bool SemanticARCOptVisitor::optimize() { + bool madeChange = false; + + // First process the worklist until we reach a fixed point. + madeChange |= processWorklist(); + + { + // If we made a change, set that we assume we are at fixed point and then + // re-run the worklist so that we can + // properly seeded the ARC peephole map. + assumingAtFixedPoint = true; + SWIFT_DEFER { assumingAtFixedPoint = false; }; + + // Add everything in visitedSinceLastMutation to the worklist so we + // recompute our fixed point. + drainVisitedSinceLastMutationIntoWorklist(); + + // Then re-run the worklist. We shouldn't modify anything since we are at a + // fixed point and are just using this to seed the + // joinedOwnedIntroducerToConsumedOperands after we have finished changing + // things. If we did change something, we did something weird, so assert! + bool madeAdditionalChanges = processWorklist(); + (void)madeAdditionalChanges; + assert(!madeAdditionalChanges && "Should be at the fixed point"); + } + + // Then use the newly seeded peephole map to + madeChange |= performPostPeepholeOwnedArgElimination(); + + return madeChange; +} + +bool SemanticARCOptVisitor::processWorklist() { + // NOTE: The madeChange here is not strictly necessary since we only have + // items added to the worklist today if we have already made /some/ sort of + // change. That being said, I think there is a low cost to including this here + // and makes the algorithm more correct, visually and in the face of potential + // refactoring. + bool madeChange = false; + + while (!worklist.empty()) { + // Pop the last element off the list. If we were returned None, we blotted + // this element, so skip it. + SILValue next = worklist.pop_back_val().getValueOr(SILValue()); + if (!next) + continue; + + // First check if this is a value that we have visited since the last time + // we erased an instruction. If we have visited it, skip it. Every time we + // modify something, we should be deleting an instruction, so we have not + // found any further information. + if (!visitedSinceLastMutation.insert(next).second) { + continue; + } + + // First check if this is an instruction that is trivially dead. This can + // occur if we eliminate rr traffic resulting in dead projections and the + // like. + // + // If we delete, we first add all of our deleted instructions operands to + // the worklist and then remove all results (since we are going to delete + // the instruction). + if (auto *defInst = next->getDefiningInstruction()) { + if (isInstructionTriviallyDead(defInst)) { + assert(!assumingAtFixedPoint && + "Assumed was at fixed point and recomputing state?!"); + deleteAllDebugUses(defInst); + eraseInstruction(defInst); + madeChange = true; + if (VerifyAfterTransform) { + F.verify(); + } + continue; + } + } + + // Otherwise, if we have a single value instruction (to be expanded later + // perhaps), try to visit that value recursively. + if (auto *svi = dyn_cast(next)) { + bool madeSingleChange = visit(svi); + assert((!madeSingleChange || !assumingAtFixedPoint) && + "Assumed was at fixed point and modified state?!"); + madeChange |= madeSingleChange; + if (VerifyAfterTransform && madeSingleChange) { + F.verify(); + } + continue; + } + } + + return madeChange; +} + +//===----------------------------------------------------------------------===// +// Top Level Entrypoint +//===----------------------------------------------------------------------===// + +namespace { + +// Even though this is a mandatory pass, it is rerun after deserialization in +// case DiagnosticConstantPropagation exposed anything new in this assert +// configuration. +struct SemanticARCOpts : SILFunctionTransform { + bool guaranteedOptsOnly; + + SemanticARCOpts(bool guaranteedOptsOnly) + : guaranteedOptsOnly(guaranteedOptsOnly) {} + + void run() override { + SILFunction &f = *getFunction(); + + // Return early if we are not performing OSSA optimizations. + if (!f.getModule().getOptions().EnableOSSAOptimizations) + return; + + // Make sure we are running with ownership verification enabled. + assert(f.getModule().getOptions().VerifySILOwnership && + "Can not perform semantic arc optimization unless ownership " + "verification is enabled"); + + SemanticARCOptVisitor visitor(f, guaranteedOptsOnly); + + // Add all the results of all instructions that we want to visit to the + // worklist. + for (auto &block : f) { + for (auto &inst : block) { + if (SemanticARCOptVisitor::shouldVisitInst(&inst)) { + for (SILValue v : inst.getResults()) { + visitor.worklist.insert(v); + } + } + } + } + + // Then process the worklist. We only destroy instructions, so invalidate + // that. Once we modify the ownership of block arguments, we will need to + // perhaps invalidate branches as well. + if (visitor.optimize()) { + invalidateAnalysis( + SILAnalysis::InvalidationKind::BranchesAndInstructions); + } + } +}; + +} // end anonymous namespace + +SILTransform *swift::createSemanticARCOpts() { + return new SemanticARCOpts(false /*guaranteed*/); +} + +SILTransform *swift::createGuaranteedARCOpts() { + return new SemanticARCOpts(true /*guaranteed*/); +} diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp index ef4777e1441d6..88e4ed0588e96 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp @@ -1020,7 +1020,7 @@ static bool mergeAccesses( info.id = 0; for (auto sccIt = scc_begin(F); !sccIt.isAtEnd(); ++sccIt) { ++info.id; - info.hasLoop = sccIt.hasLoop(); + info.hasLoop = sccIt.hasCycle(); for (auto *bb : *sccIt) { blockToSCCMap.insert(std::make_pair(bb, info)); } diff --git a/lib/SILOptimizer/Transforms/CMakeLists.txt b/lib/SILOptimizer/Transforms/CMakeLists.txt index c51043a1910c3..ac3718b6cf20f 100644 --- a/lib/SILOptimizer/Transforms/CMakeLists.txt +++ b/lib/SILOptimizer/Transforms/CMakeLists.txt @@ -31,7 +31,6 @@ target_sources(swiftSILOptimizer PRIVATE RedundantLoadElimination.cpp RedundantOverflowCheckRemoval.cpp ReleaseDevirtualizer.cpp - SemanticARCOpts.cpp SILCodeMotion.cpp SILLowerAggregateInstrs.cpp SILMem2Reg.cpp diff --git a/lib/SILOptimizer/Transforms/CSE.cpp b/lib/SILOptimizer/Transforms/CSE.cpp index af2cef2882e4a..1e1f6bbd74827 100644 --- a/lib/SILOptimizer/Transforms/CSE.cpp +++ b/lib/SILOptimizer/Transforms/CSE.cpp @@ -428,9 +428,6 @@ bool llvm::DenseMapInfo::isEqual(SimpleValue LHS, return false; // ... and other constraints are equal. - if (LHSArchetypeTy->requiresClass() != RHSArchetypeTy->requiresClass()) - return false; - if (LHSArchetypeTy->getSuperclass().getPointer() != RHSArchetypeTy->getSuperclass().getPointer()) return false; @@ -834,6 +831,14 @@ static bool isLazyPropertyGetter(ApplyInst *ai) { !callee->isLazyPropertyGetter()) return false; + // Only handle classes, but not structs. + // Lazy property getters of structs have an indirect inout self parameter. + // We don't know if the whole struct is overwritten between two getter calls. + // In such a case, the lazy property could be reset to an Optional.none. + // TODO: We could check this case with AliasAnalysis. + if (ai->getArgument(0)->getType().isAddress()) + return false; + // Check if the first block has a switch_enum of an Optional. // We don't handle getters of generic types, which have a switch_enum_addr. // This will be obsolete with opaque values anyway. diff --git a/lib/SILOptimizer/Transforms/CopyForwarding.cpp b/lib/SILOptimizer/Transforms/CopyForwarding.cpp index f930a10dc92e0..ad7a41d52f5ad 100644 --- a/lib/SILOptimizer/Transforms/CopyForwarding.cpp +++ b/lib/SILOptimizer/Transforms/CopyForwarding.cpp @@ -537,7 +537,7 @@ class CopyForwarding { public: CopySrcUserVisitor(CopyForwarding &CPF) : CPF(CPF) {} - virtual bool visitNormalUse(SILInstruction *user) { + virtual bool visitNormalUse(SILInstruction *user) override { if (isa(user)) CPF.IsSrcLoadedFrom = true; @@ -549,18 +549,18 @@ class CopyForwarding { // Bail on multiple uses in the same instruction to avoid complexity. return CPF.SrcUserInsts.insert(user).second; } - virtual bool visitTake(CopyAddrInst *take) { + virtual bool visitTake(CopyAddrInst *take) override { if (take->getSrc() == take->getDest()) return false; CPF.TakePoints.push_back(take); return true; } - virtual bool visitDestroy(DestroyAddrInst *destroy) { + virtual bool visitDestroy(DestroyAddrInst *destroy) override { CPF.DestroyPoints.push_back(destroy); return true; } - virtual bool visitDebugValue(DebugValueAddrInst *debugValue) { + virtual bool visitDebugValue(DebugValueAddrInst *debugValue) override { return CPF.SrcDebugValueInsts.insert(debugValue).second; } }; @@ -635,17 +635,17 @@ class CopyDestUserVisitor : public AddressUserVisitor { CopyDestUserVisitor(SmallPtrSetImpl &DestUsers) : DestUsers(DestUsers) {} - virtual bool visitNormalUse(SILInstruction *user) { + virtual bool visitNormalUse(SILInstruction *user) override { // Bail on multiple uses in the same instruction to avoid complexity. return DestUsers.insert(user).second; } - virtual bool visitTake(CopyAddrInst *take) { + virtual bool visitTake(CopyAddrInst *take) override { return DestUsers.insert(take).second; } - virtual bool visitDestroy(DestroyAddrInst *destroy) { + virtual bool visitDestroy(DestroyAddrInst *destroy) override { return DestUsers.insert(destroy).second; } - virtual bool visitDebugValue(DebugValueAddrInst *debugValue) { + virtual bool visitDebugValue(DebugValueAddrInst *debugValue) override { return DestUsers.insert(debugValue).second; } }; diff --git a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp index b20890a6b1cfd..b1e98ba58ef38 100644 --- a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp +++ b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp @@ -30,12 +30,28 @@ #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" using namespace swift; +static llvm::cl::opt ForceVisitImplicitAutogeneratedFunctions( + "optremarkgen-visit-implicit-autogen-funcs", llvm::cl::Hidden, + llvm::cl::desc( + "Emit opt remarks even on implicit and autogenerated functions"), + llvm::cl::init(false)); + +static llvm::cl::opt DecllessDebugValueUseSILDebugInfo( + "optremarkgen-declless-debugvalue-use-sildebugvar-info", llvm::cl::Hidden, + llvm::cl::desc( + "If a debug_value does not have a decl, infer a value with a name from " + "that info that has a loc set to the loc of the debug_value " + "instruction itself. This is for testing purposes so it is easier to " + "write SIL test cases for this pass"), + llvm::cl::init(false)); + //===----------------------------------------------------------------------===// -// Utility +// Value To Decl Inferrer //===----------------------------------------------------------------------===// namespace { @@ -46,6 +62,7 @@ struct ValueToDeclInferrer { RCIdentityFunctionInfo &rcfi; SmallVector, 32> accessPath; + SmallVector rcIdenticalSecondaryUseSearch; ValueToDeclInferrer(RCIdentityFunctionInfo &rcfi) : rcfi(rcfi) {} @@ -54,17 +71,74 @@ struct ValueToDeclInferrer { bool infer(ArgumentKeyKind keyKind, SILValue value, SmallVectorImpl &resultingInferredDecls); - /// Print out a note to \p stream that beings at decl and then consumes the - /// accessPath we computed for decl producing a segmented access path, e.x.: - /// "of 'x.lhs.ivar'". - void printNote(llvm::raw_string_ostream &stream, const ValueDecl *decl); + /// Print out a note to \p stream that beings at decl and then if + /// useProjectionPath is set to true iterates the accessPath we computed for + /// decl producing a segmented access path, e.x.: "of 'x.lhs.ivar'". + /// + /// The reason why one may not want to emit a projection path note here is if + /// one found an debug_value on a value that is rc-identical to the actual + /// value associated with the current projection path. Consider the following + /// SIL: + /// + /// struct KlassPair { + /// var lhs: Klass + /// var rhs: Klass + /// } + /// + /// struct StateWithOwningPointer { + /// var state: TrivialState + /// var owningPtr: Klass + /// } + /// + /// sil @theFunction : $@convention(thin) () -> () { + /// bb0: + /// %0 = apply %getKlassPair() : $@convention(thin) () -> @owned KlassPair + /// // This debug_value's name can be combined... + /// debug_value %0 : $KlassPair, name "myPair" + /// // ... with the access path from the struct_extract here... + /// %1 = struct_extract %0 : $KlassPair, #KlassPair.lhs + /// // ... to emit a nice diagnostic that 'myPair.lhs' is being retained. + /// strong_retain %1 : $Klass + /// + /// // In contrast in this case, we rely on looking through rc-identity + /// // uses to find the debug_value. In this case, the source info + /// // associated with the debug_value (%2) is no longer associated with + /// // the underlying access path we have been tracking upwards (%1 is in + /// // our access path list). Instead, we know that the debug_value is + /// // rc-identical to whatever value we were originally tracking up (%1) + /// // and thus the correct identifier to use is the direct name of the + /// // identifier alone since that source identifier must be some value + /// // in the source that by itself is rc-identical to whatever is being + /// // manipulated. + /// // + /// // The reason why we must do this is due to the behavior of the late + /// // optimizer and how it forms these patterns in the code. + /// %0a = apply %getStateWithOwningPointer() : $@convention(thin) () -> @owned StateWithOwningPointer + /// %1 = struct_extract %0a : $StateWithOwningPointer, #StateWithOwningPointer.owningPtr + /// strong_retain %1 : $Klass + /// %2 = struct $Array(%0 : $Builtin.NativeObject, ...) + /// debug_value %2 : $Array, ... + /// } + void printNote(llvm::raw_string_ostream &stream, StringRef name, + bool shouldPrintAccessPath = true); + + /// Convenience overload that calls: + /// + /// printNote(stream, decl->getBaseName().userFacingName(), shouldPrintAccessPath). + void printNote(llvm::raw_string_ostream &stream, const ValueDecl *decl, + bool shouldPrintAccessPath = true) { + printNote(stream, decl->getBaseName().userFacingName(), + shouldPrintAccessPath); + } + + /// Print out non-destructively the current access path we have found to + /// stream. + void printAccessPath(llvm::raw_string_ostream &stream); }; } // anonymous namespace -void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream, - const ValueDecl *decl) { - stream << "of '" << decl->getBaseName(); +void ValueToDeclInferrer::printAccessPath(llvm::raw_string_ostream &stream) { for (auto &pair : accessPath) { auto baseType = pair.first; auto &proj = pair.second; @@ -101,8 +175,14 @@ void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream, llvm_unreachable("Covered switch is not covered?!"); } +} - accessPath.clear(); +void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream, + StringRef name, + bool shouldPrintAccessPath) { + stream << "of '" << name; + if (shouldPrintAccessPath) + printAccessPath(stream); stream << "'"; } @@ -126,9 +206,21 @@ static SingleValueInstruction *isSupportedProjection(Projection p, SILValue v) { llvm_unreachable("Covered switch is not covered?!"); } +static bool hasNonInlinedDebugScope(SILInstruction *i) { + if (auto *scope = i->getDebugScope()) + return !scope->InlinedCallSite; + return false; +} + bool ValueToDeclInferrer::infer( ArgumentKeyKind keyKind, SILValue value, SmallVectorImpl &resultingInferredDecls) { + // Clear the stored access path at end of scope. + SWIFT_DEFER { + accessPath.clear(); + }; + SmallPtrSet visitedDebugValueInsts; + // This is a linear IR traversal using a 'falling while loop'. That means // every time through the loop we are trying to handle a case before we hit // the bottom of the while loop where we always return true (since we did not @@ -160,36 +252,117 @@ bool ValueToDeclInferrer::infer( return true; } - // Then visit our users and see if we can find a debug_value that provides - // us with a decl we can use to construct an argument. + if (auto *ari = dyn_cast(value)) { + if (auto *decl = ari->getDecl()) { + std::string msg; + { + llvm::raw_string_ostream stream(msg); + printNote(stream, decl); + } + resultingInferredDecls.push_back( + Argument({keyKind, "InferredValue"}, std::move(msg), decl)); + return true; + } + } + + if (auto *abi = dyn_cast(value)) { + if (auto *decl = abi->getDecl()) { + std::string msg; + { + llvm::raw_string_ostream stream(msg); + printNote(stream, decl); + } + + resultingInferredDecls.push_back( + Argument({keyKind, "InferredValue"}, std::move(msg), decl)); + return true; + } + } + + if (auto *asi = dyn_cast(value)) { + if (auto *decl = asi->getDecl()) { + std::string msg; + { + llvm::raw_string_ostream stream(msg); + printNote(stream, decl); + } + resultingInferredDecls.push_back( + Argument({keyKind, "InferredValue"}, std::move(msg), decl)); + return true; + } + } + + // Then visit our users (ignoring rc identical transformations) and see if + // we can find a debug_value that provides us with a decl we can use to + // construct an argument. + // + // The reason why we do this is that sometimes we reform a struct from its + // constituant parts and then construct the debug_value from that. For + // instance, if we FSOed. bool foundDeclFromUse = false; - for (auto *use : value->getUses()) { + rcfi.visitRCUses(value, [&](Operand *use) { // Skip type dependent uses. if (use->isTypeDependent()) - continue; + return; + + // Then see if we have a debug_value that is associated with a non-inlined + // debug scope. Such an instruction is an instruction that is from the + // current function. + auto *dvi = dyn_cast(use->getUser()); + if (!dvi || !hasNonInlinedDebugScope(dvi)) + return; - if (auto *dvi = dyn_cast(use->getUser())) { - if (auto *decl = dvi->getDecl()) { - std::string msg; - { - llvm::raw_string_ostream stream(msg); - printNote(stream, decl); - } - resultingInferredDecls.push_back( - Argument({keyKind, "InferredValue"}, std::move(msg), decl)); - foundDeclFromUse = true; + // See if we have already inferred this debug_value as a potential source + // for this instruction. In such a case, just return. + if (!visitedDebugValueInsts.insert(dvi).second) + return; + + if (auto *decl = dvi->getDecl()) { + std::string msg; + { + llvm::raw_string_ostream stream(msg); + // If we are not a top level use, we must be a rc-identical transitive + // use. In such a case, we just print out the rc identical value + // without a projection path. This is because we now have a better + // name and the name is rc-identical to whatever was at the end of the + // projection path but is not at the end of that projection path. + printNote(stream, decl, + use->get() == value /*print projection path*/); } + resultingInferredDecls.emplace_back( + OptRemark::ArgumentKey{keyKind, "InferredValue"}, std::move(msg), + decl); + foundDeclFromUse = true; + return; } - } - if (foundDeclFromUse) - return true; - // At this point, we could not infer any argument. See if we can look - // through loads. - // - // TODO: Add GEPs to construct a ProjectionPath. + // If we did not have a decl, see if we were asked for testing + // purposes to use SILDebugInfo to create a placeholder inferred + // value. + if (!DecllessDebugValueUseSILDebugInfo) + return; + + auto varInfo = dvi->getVarInfo(); + if (!varInfo) + return; - // Finally, see if we can look through a load... + auto name = varInfo->Name; + if (name.empty()) + return; + + std::string msg; + { + llvm::raw_string_ostream stream(msg); + printNote(stream, name, use->get() == value /*print projection path*/); + } + resultingInferredDecls.push_back( + Argument({keyKind, "InferredValue"}, std::move(msg), dvi->getLoc())); + foundDeclFromUse = true; + }); + + // At this point, we could not infer any argument. See if we can look up the + // def-use graph and come up with a good location after looking through + // loads and projections. if (auto *li = dyn_cast(value)) { value = stripAccessMarkers(li->getOperand()); continue; @@ -203,9 +376,12 @@ bool ValueToDeclInferrer::infer( } } + // TODO: We could emit at this point a msg for temporary allocations. + // If we reached this point, we finished falling through the loop and return - // true. - return true; + // if we found any decls from uses. We always process everything so we /can/ + // potentially emit multiple diagnostics. + return foundDeclFromUse; } } @@ -232,6 +408,8 @@ struct OptRemarkGeneratorInstructionVisitor void visitStrongReleaseInst(StrongReleaseInst *sri); void visitRetainValueInst(RetainValueInst *rvi); void visitReleaseValueInst(ReleaseValueInst *rvi); + void visitAllocRefInst(AllocRefInst *ari); + void visitAllocBoxInst(AllocBoxInst *abi); void visitSILInstruction(SILInstruction *) {} }; @@ -247,10 +425,11 @@ void OptRemarkGeneratorInstructionVisitor::visitStrongRetainInst( (void)foundArgs; // Retains begin a lifetime scope so we infer scan forward. - auto remark = RemarkMissed("memory", *sri, - SourceLocInferenceBehavior::ForwardScanOnly) - << "retain of type '" - << NV("ValueType", sri->getOperand()->getType()) << "'"; + auto remark = + RemarkMissed("memory", *sri, + SourceLocInferenceBehavior::ForwardScanAlwaysInfer) + << "retain of type '" << NV("ValueType", sri->getOperand()->getType()) + << "'"; for (auto arg : inferredArgs) { remark << arg; } @@ -268,10 +447,11 @@ void OptRemarkGeneratorInstructionVisitor::visitStrongReleaseInst( sri->getOperand(), inferredArgs); (void)foundArgs; - auto remark = RemarkMissed("memory", *sri, - SourceLocInferenceBehavior::BackwardScanOnly) - << "release of type '" - << NV("ValueType", sri->getOperand()->getType()) << "'"; + auto remark = + RemarkMissed("memory", *sri, + SourceLocInferenceBehavior::BackwardScanAlwaysInfer) + << "release of type '" << NV("ValueType", sri->getOperand()->getType()) + << "'"; for (auto arg : inferredArgs) { remark << arg; } @@ -288,10 +468,11 @@ void OptRemarkGeneratorInstructionVisitor::visitRetainValueInst( rvi->getOperand(), inferredArgs); (void)foundArgs; // Retains begin a lifetime scope, so we infer scan forwards. - auto remark = RemarkMissed("memory", *rvi, - SourceLocInferenceBehavior::ForwardScanOnly) - << "retain of type '" - << NV("ValueType", rvi->getOperand()->getType()) << "'"; + auto remark = + RemarkMissed("memory", *rvi, + SourceLocInferenceBehavior::ForwardScanAlwaysInfer) + << "retain of type '" << NV("ValueType", rvi->getOperand()->getType()) + << "'"; for (auto arg : inferredArgs) { remark << arg; } @@ -309,10 +490,11 @@ void OptRemarkGeneratorInstructionVisitor::visitReleaseValueInst( (void)foundArgs; // Releases end a lifetime scope so we infer scan backward. - auto remark = RemarkMissed("memory", *rvi, - SourceLocInferenceBehavior::BackwardScanOnly) - << "release of type '" - << NV("ValueType", rvi->getOperand()->getType()) << "'"; + auto remark = + RemarkMissed("memory", *rvi, + SourceLocInferenceBehavior::BackwardScanAlwaysInfer) + << "release of type '" << NV("ValueType", rvi->getOperand()->getType()) + << "'"; for (auto arg : inferredArgs) { remark << arg; } @@ -320,6 +502,61 @@ void OptRemarkGeneratorInstructionVisitor::visitReleaseValueInst( }); } +void OptRemarkGeneratorInstructionVisitor::visitAllocRefInst( + AllocRefInst *ari) { + if (ari->canAllocOnStack()) { + return ORE.emit([&]() { + using namespace OptRemark; + SmallVector inferredArgs; + bool foundArgs = + valueToDeclInferrer.infer(ArgumentKeyKind::Note, ari, inferredArgs); + (void)foundArgs; + auto resultRemark = + RemarkPassed("memory", *ari, SourceLocInferenceBehavior::ForwardScan) + << "stack allocated ref of type '" << NV("ValueType", ari->getType()) + << "'"; + for (auto &arg : inferredArgs) + resultRemark << arg; + return resultRemark; + }); + } + + return ORE.emit([&]() { + using namespace OptRemark; + SmallVector inferredArgs; + bool foundArgs = + valueToDeclInferrer.infer(ArgumentKeyKind::Note, ari, inferredArgs); + (void)foundArgs; + + auto resultRemark = + RemarkMissed("memory", *ari, SourceLocInferenceBehavior::ForwardScan) + << "heap allocated ref of type '" << NV("ValueType", ari->getType()) + << "'"; + for (auto &arg : inferredArgs) + resultRemark << arg; + return resultRemark; + }); +} + +void OptRemarkGeneratorInstructionVisitor::visitAllocBoxInst( + AllocBoxInst *abi) { + return ORE.emit([&]() { + using namespace OptRemark; + SmallVector inferredArgs; + bool foundArgs = + valueToDeclInferrer.infer(ArgumentKeyKind::Note, abi, inferredArgs); + (void)foundArgs; + + auto resultRemark = + RemarkMissed("memory", *abi, SourceLocInferenceBehavior::ForwardScan) + << "heap allocated box of type '" << NV("ValueType", abi->getType()) + << "'"; + for (auto &arg : inferredArgs) + resultRemark << arg; + return resultRemark; + }); +} + //===----------------------------------------------------------------------===// // Top Level Entrypoint //===----------------------------------------------------------------------===// @@ -347,6 +584,21 @@ class OptRemarkGenerator : public SILFunctionTransform { return; auto *fn = getFunction(); + + // Skip top level implicit functions and top level autogenerated functions, + // unless we were asked by the user to emit them. + if (!ForceVisitImplicitAutogeneratedFunctions) { + // Skip implicit functions generated by Sema. + if (auto *ctx = fn->getDeclContext()) + if (auto *decl = ctx->getAsDecl()) + if (decl->isImplicit()) + return; + // Skip autogenerated functions generated by SILGen. + if (auto loc = fn->getDebugScope()->getLoc()) + if (loc.isAutoGenerated()) + return; + } + LLVM_DEBUG(llvm::dbgs() << "Visiting: " << fn->getName() << "\n"); auto &rcfi = *getAnalysis()->get(fn); OptRemarkGeneratorInstructionVisitor visitor(*fn, rcfi); diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp index e052a6b000f3c..b5a89537fbe0e 100644 --- a/lib/SILOptimizer/Transforms/Outliner.cpp +++ b/lib/SILOptimizer/Transforms/Outliner.cpp @@ -298,7 +298,7 @@ CanSILFunctionType BridgedProperty::getOutlinedFunctionType(SILModule &M) { auto ExtInfo = SILFunctionType::ExtInfoBuilder( SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, /*noescape*/ false, - DifferentiabilityKind::NonDifferentiable, + /*async*/ false, DifferentiabilityKind::NonDifferentiable, /*clangFunctionType*/ nullptr) .build(); auto FunctionType = SILFunctionType::get( @@ -1181,6 +1181,7 @@ CanSILFunctionType ObjCMethodCall::getOutlinedFunctionType(SILModule &M) { SILFunctionType::ExtInfoBuilder(SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, /*noescape*/ false, + /*async*/ false, DifferentiabilityKind::NonDifferentiable, /*clangFunctionType*/ nullptr) .build(); diff --git a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp index e07553e784ef4..ce3a00e413754 100644 --- a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp +++ b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp @@ -559,6 +559,15 @@ static bool returnsClosure(SILFunction *F) { return false; } +static bool isInlineAlwaysCallSite(SILFunction *Callee) { + if (Callee->isTransparent()) + return true; + if (Callee->getInlineStrategy() == AlwaysInline) + if (!Callee->getModule().getOptions().IgnoreAlwaysInline) + return true; + return false; +} + /// Checks if a given generic apply should be inlined unconditionally, i.e. /// without any complex analysis using e.g. a cost model. /// It returns true if a function should be inlined. @@ -585,7 +594,7 @@ static Optional shouldInlineGeneric(FullApplySite AI) { // Always inline generic functions which are marked as // AlwaysInline or transparent. - if (Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent()) + if (isInlineAlwaysCallSite(Callee)) return true; // If all substitutions are concrete, then there is no need to perform the @@ -632,7 +641,7 @@ bool SILPerformanceInliner::decideInWarmBlock( SILFunction *Callee = AI.getReferencedFunctionOrNull(); - if (Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent()) { + if (isInlineAlwaysCallSite(Callee)) { LLVM_DEBUG(dumpCaller(AI.getFunction()); llvm::dbgs() << " always-inline decision " << Callee->getName() << '\n'); @@ -655,7 +664,7 @@ bool SILPerformanceInliner::decideInColdBlock(FullApplySite AI, return false; } - if (Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent()) { + if (isInlineAlwaysCallSite(Callee)) { LLVM_DEBUG(dumpCaller(AI.getFunction()); llvm::dbgs() << " always-inline decision " << Callee->getName() << '\n'); @@ -717,10 +726,6 @@ addToBBCounts(llvm::DenseMap &BBToWeightMap, } } -static bool isInlineAlwaysCallSite(SILFunction *Callee) { - return Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent(); -} - static void calculateBBWeights(SILFunction *Caller, DominanceInfo *DT, llvm::DenseMap &BBToWeightMap) { diff --git a/lib/SILOptimizer/Transforms/PruneVTables.cpp b/lib/SILOptimizer/Transforms/PruneVTables.cpp index 18543900f921e..f1c37c892c8c9 100644 --- a/lib/SILOptimizer/Transforms/PruneVTables.cpp +++ b/lib/SILOptimizer/Transforms/PruneVTables.cpp @@ -27,10 +27,16 @@ using namespace swift; namespace { class PruneVTables : public SILModuleTransform { - void runOnVTable(SILModule *M, - SILVTable *vtable) { + void runOnVTable(SILModule *M, SILVTable *vtable) { LLVM_DEBUG(llvm::dbgs() << "PruneVTables inspecting table:\n"; vtable->print(llvm::dbgs())); + if (!M->isWholeModule() && + vtable->getClass()->getEffectiveAccess() >= AccessLevel::FilePrivate) { + LLVM_DEBUG(llvm::dbgs() << "Ignoring visible table: "; + vtable->print(llvm::dbgs())); + return; + } + for (auto &entry : vtable->getMutableEntries()) { // We don't need to worry about entries that are overridden, diff --git a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp b/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp deleted file mode 100644 index 45a05e6c0db3c..0000000000000 --- a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp +++ /dev/null @@ -1,2243 +0,0 @@ -//===--- SemanticARCOpts.cpp ----------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "sil-semantic-arc-opts" -#include "swift/Basic/BlotSetVector.h" -#include "swift/Basic/FrozenMultiMap.h" -#include "swift/Basic/MultiMapCache.h" -#include "swift/Basic/STLExtras.h" -#include "swift/SIL/BasicBlockUtils.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SIL/LinearLifetimeChecker.h" -#include "swift/SIL/MemAccessUtils.h" -#include "swift/SIL/OwnershipUtils.h" -#include "swift/SIL/Projection.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILInstruction.h" -#include "swift/SIL/SILVisitor.h" -#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" -#include "swift/SILOptimizer/PassManager/Passes.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/InstOptUtils.h" -#include "swift/SILOptimizer/Utils/ValueLifetime.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/CommandLine.h" - -using namespace swift; - -STATISTIC(NumEliminatedInsts, "number of removed instructions"); -STATISTIC(NumLoadCopyConvertedToLoadBorrow, - "number of load_copy converted to load_borrow"); - -//===----------------------------------------------------------------------===// -// Ownership Phi Operand -//===----------------------------------------------------------------------===// - -namespace { - -/// The operand of a "phi" in the induced ownership graph of a def-use graph. -/// -/// Some examples: br, struct, tuple. -class OwnershipPhiOperand { -public: - enum Kind { - Branch, - Struct, - Tuple, - }; - -private: - Operand *op; - - OwnershipPhiOperand(Operand *op) : op(op) {} - -public: - static Optional get(const Operand *op) { - switch (op->getUser()->getKind()) { - case SILInstructionKind::BranchInst: - case SILInstructionKind::StructInst: - case SILInstructionKind::TupleInst: - return {{const_cast(op)}}; - default: - return None; - } - } - - Kind getKind() const { - switch (op->getUser()->getKind()) { - case SILInstructionKind::BranchInst: - return Kind::Branch; - case SILInstructionKind::StructInst: - return Kind::Struct; - case SILInstructionKind::TupleInst: - return Kind::Tuple; - default: - llvm_unreachable("unhandled case?!"); - } - } - - Operand *getOperand() const { return op; } - SILValue getValue() const { return op->get(); } - SILType getType() const { return op->get()->getType(); } - - unsigned getOperandNumber() const { return op->getOperandNumber(); } - - void markUndef() & { - op->set(SILUndef::get(getType(), *op->getUser()->getFunction())); - } - - SILInstruction *getInst() const { return op->getUser(); } - - /// Return true if this phi consumes a borrow. - /// - /// If so, we may need to insert an extra begin_borrow to balance the +1 when - /// converting owned ownership phis to guaranteed ownership phis. - bool isGuaranteedConsuming() const { - switch (getKind()) { - case Kind::Branch: - return true; - case Kind::Tuple: - case Kind::Struct: - return false; - } - } - - bool operator<(const OwnershipPhiOperand &other) const { - return op < other.op; - } - - bool operator==(const OwnershipPhiOperand &other) const { - return op == other.op; - } - - bool visitResults(function_ref visitor) const { - switch (getKind()) { - case Kind::Struct: - return visitor(cast(getInst())); - case Kind::Tuple: - return visitor(cast(getInst())); - case Kind::Branch: { - auto *br = cast(getInst()); - unsigned opNum = getOperandNumber(); - return llvm::all_of( - br->getSuccessorBlocks(), [&](SILBasicBlock *succBlock) { - return visitor(succBlock->getSILPhiArguments()[opNum]); - }); - } - } - } -}; - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// Live Range Modeling -//===----------------------------------------------------------------------===// - -namespace { - -/// This class represents an "extended live range" of an owned value. Such a -/// representation includes: -/// -/// 1. The owned introducing value. -/// 2. Any forwarding instructions that consume the introduced value -/// (transitively) and then propagate a new owned value. -/// 3. Transitive destroys on the forwarding instructions/destroys on the owned -/// introducing value. -/// 4. Any unknown consuming uses that are not understood by this code. -/// -/// This allows for this to be used to convert such a set of uses from using -/// owned ownership to using guaranteed ownership by converting the -/// destroy_value -> end_borrow and "flipping" the ownership of individual -/// forwarding instructions. -/// -/// NOTE: We do not look through "phi nodes" in the ownership graph (e.x.: real -/// phi arguments, struct, tuple). Instead we represent those as nodes in a -/// larger phi ownership web, connected via individual OwnershipLiveRange. -class OwnershipLiveRange { - /// The value that we are computing the LiveRange for. Expected to be an owned - /// introducer and not to be forwarding. - OwnedValueIntroducer introducer; - - /// A vector that we store all of our uses into. - /// - /// Some properties of this array are: - /// - /// 1. It is only mutated in the constructor of LiveRange. - /// - /// 2. destroyingUses, ownershipForwardingUses, and unknownConsumingUses are - /// views into this array. We store the respective uses in the aforementioned - /// order. This is why it is important not to mutate consumingUses after we - /// construct the LiveRange since going from small -> large could invalidate - /// the uses. - SmallVector consumingUses; - - /// A list of destroy_values of the live range. - /// - /// This is just a view into consuming uses. - ArrayRef destroyingUses; - - /// A list of forwarding instructions that forward owned ownership, but that - /// are also able to be converted to guaranteed ownership. - /// - /// If we are able to eliminate this LiveRange due to it being from a - /// guaranteed value, we must flip the ownership of all of these instructions - /// to guaranteed from owned. - /// - /// NOTE: Normally only destroying or consuming uses end the live range. We - /// copy these transitive uses as well into the consumingUses array since - /// transitive uses can extend a live range up to an unreachable block without - /// ultimately being consuming. In such a situation if we did not also store - /// this into consuming uses, we would not be able to ascertain just using the - /// "consumingUses" array the true lifetime of the OwnershipLiveRange. - /// - /// Corresponds to isOwnershipForwardingInst(...). - ArrayRef ownershipForwardingUses; - - /// Consuming uses that we were not able to understand as a forwarding - /// instruction or a destroy_value. These must be passed a strongly control - /// equivalent +1 value. - ArrayRef unknownConsumingUses; - -public: - OwnershipLiveRange(SILValue value); - OwnershipLiveRange(const OwnershipLiveRange &) = delete; - OwnershipLiveRange &operator=(const OwnershipLiveRange &) = delete; - - enum class HasConsumingUse_t { - No = 0, - YesButAllPhiArgs = 1, - Yes = 2, - }; - - /// Return true if v only has invalidating uses that are destroy_value. Such - /// an owned value is said to represent a dead "live range". - /// - /// Semantically this implies that a value is never passed off as +1 to memory - /// or another function implying it can be used everywhere at +0. - HasConsumingUse_t - hasUnknownConsumingUse(bool assumingFixedPoint = false) const; - - /// Return an array ref to /all/ consuming uses. Will include all 3 sorts of - /// consuming uses: destroying uses, forwarding consuming uses, and unknown - /// forwarding instruction. - ArrayRef getAllConsumingUses() const { return consumingUses; } - - ArrayRef getDestroyingUses() const { return destroyingUses; } - -private: - struct OperandToUser; - -public: - using DestroyingInstsRange = - TransformRange, OperandToUser>; - DestroyingInstsRange getDestroyingInsts() const; - - /// If this LiveRange has a single destroying use, return that use. Otherwise, - /// return nullptr. - Operand *getSingleDestroyingUse() const { - if (destroyingUses.size() != 1) { - return nullptr; - } - return destroyingUses.front(); - } - - /// If this LiveRange has a single unknown destroying use, return that - /// use. Otherwise, return nullptr. - Operand *getSingleUnknownConsumingUse() const { - if (unknownConsumingUses.size() != 1) { - return nullptr; - } - return unknownConsumingUses.front(); - } - - OwnedValueIntroducer getIntroducer() const { return introducer; } - - ArrayRef getOwnershipForwardingUses() const { - return ownershipForwardingUses; - } - - void convertOwnedGeneralForwardingUsesToGuaranteed() &&; - - /// A consuming operation that: - /// - /// 1. If \p insertEndBorrows is true inserts end borrows at all - /// destroying insts locations. - /// - /// 2. Deletes all destroy_values. - /// - /// 3. RAUW value with newGuaranteedValue. - /// - /// 4. Convert all of the general forwarding instructions from - /// @owned -> @guaranteed. "Like Dominoes". - /// - /// 5. Leaves all of the unknown consuming users alone. It is up to - /// the caller to handle converting their ownership. - void convertToGuaranteedAndRAUW(SILValue newGuaranteedValue, - InstModCallbacks callbacks) &&; - - /// A consuming operation that in order: - /// - /// 1. Converts the phi argument to be guaranteed via setOwnership. - /// - /// 2. If this consumes a borrow, insert end_borrows at the relevant - /// destroy_values. - /// - /// 3. Deletes all destroy_values. - /// - /// 4. Converts all of the general forwarding instructions from @owned -> - /// @guaranteed. "Like Dominoes". - /// - /// NOTE: This leaves all of the unknown consuming users alone. It is up to - /// the caller to handle converting their ownership. - /// - /// NOTE: This routine leaves inserting begin_borrows for the incoming values - /// to the caller since those are not part of the LiveRange itself. - void convertJoinedLiveRangePhiToGuaranteed( - DeadEndBlocks &deadEndBlocks, ValueLifetimeAnalysis::Frontier &scratch, - InstModCallbacks callbacks) &&; - - /// Given a new guaranteed value, insert end_borrow for the newGuaranteedValue - /// at all of our destroy_values in prepration for converting from owned to - /// guaranteed. - /// - /// This is used when converting load [copy] -> load_borrow. - void insertEndBorrowsAtDestroys(SILValue newGuaranteedValue, - DeadEndBlocks &deadEndBlocks, - ValueLifetimeAnalysis::Frontier &scratch); -}; - -} // end anonymous namespace - -struct OwnershipLiveRange::OperandToUser { - OperandToUser() {} - - SILInstruction *operator()(const Operand *use) const { - auto *nonConstUse = const_cast(use); - return nonConstUse->getUser(); - } -}; - -OwnershipLiveRange::DestroyingInstsRange -OwnershipLiveRange::getDestroyingInsts() const { - return DestroyingInstsRange(getDestroyingUses(), OperandToUser()); -} - -OwnershipLiveRange::OwnershipLiveRange(SILValue value) - : introducer(*OwnedValueIntroducer::get(value)), destroyingUses(), - ownershipForwardingUses(), unknownConsumingUses() { - assert(introducer.value.getOwnershipKind() == ValueOwnershipKind::Owned); - - SmallVector tmpDestroyingUses; - SmallVector tmpForwardingConsumingUses; - SmallVector tmpUnknownConsumingUses; - - // We know that our silvalue produces an @owned value. Look through all of our - // uses and classify them as either consuming or not. - SmallVector worklist(introducer.value->getUses()); - while (!worklist.empty()) { - auto *op = worklist.pop_back_val(); - - // Skip type dependent operands. - if (op->isTypeDependent()) - continue; - - // Do a quick check that we did not add ValueOwnershipKind that are not - // owned to the worklist. - assert(op->get().getOwnershipKind() == ValueOwnershipKind::Owned && - "Added non-owned value to worklist?!"); - - auto *user = op->getUser(); - - // Ok, this constraint can take something owned as live. Assert that it - // can also accept something that is guaranteed. Any non-consuming use of - // an owned value should be able to take a guaranteed parameter as well - // (modulo bugs). We assert to catch these. - if (!op->isConsumingUse()) { - continue; - } - - // Ok, we know now that we have a consuming use. See if we have a destroy - // value, quickly up front. If we do have one, stash it and continue. - if (isa(user)) { - tmpDestroyingUses.push_back(op); - continue; - } - - // Otherwise, see if we have a forwarding value that has a single - // non-trivial operand that can accept a guaranteed value. If not, we can - // not recursively process it, so be conservative and assume that we /may - // consume/ the value, so the live range must not be eliminated. - // - // DISCUSSION: For now we do not support forwarding instructions with - // multiple non-trivial arguments since we would need to optimize all of - // the non-trivial arguments at the same time. - // - // NOTE: Today we do not support TermInsts for simplicity... we /could/ - // support it though if we need to. - auto *ti = dyn_cast(user); - if ((ti && !ti->isTransformationTerminator()) || - !isGuaranteedForwardingInst(user) || - 1 != count_if(user->getOperandValues( - true /*ignore type dependent operands*/), - [&](SILValue v) { - return v.getOwnershipKind() == - ValueOwnershipKind::Owned; - })) { - tmpUnknownConsumingUses.push_back(op); - continue; - } - - // Ok, this is a forwarding instruction whose ownership we can flip from - // owned -> guaranteed. - tmpForwardingConsumingUses.push_back(op); - - // If we have a non-terminator, just visit its users recursively to see if - // the the users force the live range to be alive. - if (!ti) { - for (SILValue v : user->getResults()) { - if (v.getOwnershipKind() != ValueOwnershipKind::Owned) - continue; - llvm::copy(v->getUses(), std::back_inserter(worklist)); - } - continue; - } - - // Otherwise, we know that we have no only a terminator, but a - // transformation terminator, so we should add the users of its results to - // the worklist. - for (auto &succ : ti->getSuccessors()) { - auto *succBlock = succ.getBB(); - - // If we do not have any arguments, then continue. - if (succBlock->args_empty()) - continue; - - for (auto *succArg : succBlock->getSILPhiArguments()) { - // If we have an any value, just continue. - if (succArg->getOwnershipKind() == ValueOwnershipKind::None) - continue; - - // Otherwise add all users of this BBArg to the worklist to visit - // recursively. - llvm::copy(succArg->getUses(), std::back_inserter(worklist)); - } - } - } - - // The order in which we append these to consumingUses matters since we assume - // their order as an invariant. This is done to ensure that we can pass off - // all of our uses or individual sub-arrays of our users without needing to - // move around memory. - llvm::copy(tmpDestroyingUses, std::back_inserter(consumingUses)); - llvm::copy(tmpForwardingConsumingUses, std::back_inserter(consumingUses)); - llvm::copy(tmpUnknownConsumingUses, std::back_inserter(consumingUses)); - - auto cUseArrayRef = llvm::makeArrayRef(consumingUses); - destroyingUses = cUseArrayRef.take_front(tmpDestroyingUses.size()); - ownershipForwardingUses = cUseArrayRef.slice( - tmpDestroyingUses.size(), tmpForwardingConsumingUses.size()); - unknownConsumingUses = cUseArrayRef.take_back(tmpUnknownConsumingUses.size()); -} - -void OwnershipLiveRange::insertEndBorrowsAtDestroys( - SILValue newGuaranteedValue, DeadEndBlocks &deadEndBlocks, - ValueLifetimeAnalysis::Frontier &scratch) { - assert(scratch.empty() && "Expected scratch to be initially empty?!"); - - // Since we are looking through forwarding uses that can accept guaranteed - // parameters, we can have multiple destroy_value along the same path. We need - // to find the post-dominating block set of these destroy value to ensure that - // we do not insert multiple end_borrow. - // - // TODO: Hoist this out? - SILInstruction *inst = introducer.value->getDefiningInstruction(); - if (!inst) { - // If our introducer was not for an inst, it should be from an arg. In such - // a case, we handle one of two cases: - // - // 1. If we have one destroy and that destroy is the initial instruction in - // the arguments block, we just insert the end_borrow here before the - // destroy_value and bail. If the destroy is not the initial instruction in - // the arg block, we delegate to the ValueLifetimeAnalysis code. - // - // 2. If we have multiple destroys, by the properties of owned values having - // a linear lifetime, we know that the destroys can not both be first in the - // args block since the only way that we could have two such destroys in the - // arg's block is if we destructured the arg. In such a case, the - // destructure instruction would have to be between the argument and any - // destroy meaning the destroys could not be first. In such a case, we - // delegate to the ValueLifetimeAnalysis code. - auto *arg = cast(introducer.value); - auto *beginInst = &*arg->getParent()->begin(); - if (auto *singleDestroyingUse = getSingleDestroyingUse()) { - if (singleDestroyingUse->getUser() == beginInst) { - auto loc = RegularLocation::getAutoGeneratedLocation(); - SILBuilderWithScope builder(beginInst); - builder.createEndBorrow(loc, newGuaranteedValue); - return; - } - } - inst = beginInst; - } - ValueLifetimeAnalysis analysis(inst, getDestroyingInsts()); - bool foundCriticalEdges = !analysis.computeFrontier( - scratch, ValueLifetimeAnalysis::DontModifyCFG, &deadEndBlocks); - (void)foundCriticalEdges; - assert(!foundCriticalEdges); - auto loc = RegularLocation::getAutoGeneratedLocation(); - while (!scratch.empty()) { - auto *insertPoint = scratch.pop_back_val(); - SILBuilderWithScope builder(insertPoint); - builder.createEndBorrow(loc, newGuaranteedValue); - } -} - -static void convertInstructionOwnership(SILInstruction *i, - ValueOwnershipKind oldOwnership, - ValueOwnershipKind newOwnership) { - // If this is a term inst, just convert all of its incoming values that are - // owned to be guaranteed. - if (auto *ti = dyn_cast(i)) { - for (auto &succ : ti->getSuccessors()) { - auto *succBlock = succ.getBB(); - - // If we do not have any arguments, then continue. - if (succBlock->args_empty()) - continue; - - for (auto *succArg : succBlock->getSILPhiArguments()) { - // If we have an any value, just continue. - if (succArg->getOwnershipKind() == oldOwnership) { - succArg->setOwnershipKind(newOwnership); - } - } - } - return; - } - - assert(i->hasResults()); - for (SILValue result : i->getResults()) { - if (auto *svi = dyn_cast(result)) { - if (svi->getOwnershipKind() == oldOwnership) { - svi->setOwnershipKind(newOwnership); - } - continue; - } - - if (auto *ofci = dyn_cast(result)) { - if (ofci->getOwnershipKind() == oldOwnership) { - ofci->setOwnershipKind(newOwnership); - } - continue; - } - - if (auto *sei = dyn_cast(result)) { - if (sei->getOwnershipKind() == oldOwnership) { - sei->setOwnershipKind(newOwnership); - } - continue; - } - - if (auto *mvir = dyn_cast(result)) { - if (mvir->getOwnershipKind() == oldOwnership) { - mvir->setOwnershipKind(newOwnership); - } - continue; - } - - llvm_unreachable("unhandled forwarding instruction?!"); - } -} - -void OwnershipLiveRange::convertOwnedGeneralForwardingUsesToGuaranteed() && { - while (!ownershipForwardingUses.empty()) { - auto *i = ownershipForwardingUses.back()->getUser(); - ownershipForwardingUses = ownershipForwardingUses.drop_back(); - convertInstructionOwnership(i, ValueOwnershipKind::Owned, - ValueOwnershipKind::Guaranteed); - } -} - -void OwnershipLiveRange::convertToGuaranteedAndRAUW( - SILValue newGuaranteedValue, InstModCallbacks callbacks) && { - auto *value = cast(introducer.value); - while (!destroyingUses.empty()) { - auto *d = destroyingUses.back(); - destroyingUses = destroyingUses.drop_back(); - callbacks.deleteInst(d->getUser()); - ++NumEliminatedInsts; - } - - callbacks.eraseAndRAUWSingleValueInst(value, newGuaranteedValue); - - // Then change all of our guaranteed forwarding insts to have guaranteed - // ownership kind instead of what ever they previously had (ignoring trivial - // results); - std::move(*this).convertOwnedGeneralForwardingUsesToGuaranteed(); -} - -// TODO: If this is useful, move onto OwnedValueIntroducer itself? -static SILValue convertIntroducerToGuaranteed(OwnedValueIntroducer introducer) { - switch (introducer.kind) { - case OwnedValueIntroducerKind::Phi: { - auto *phiArg = cast(introducer.value); - phiArg->setOwnershipKind(ValueOwnershipKind::Guaranteed); - return phiArg; - } - case OwnedValueIntroducerKind::Struct: { - auto *si = cast(introducer.value); - si->setOwnershipKind(ValueOwnershipKind::Guaranteed); - return si; - } - case OwnedValueIntroducerKind::Tuple: { - auto *ti = cast(introducer.value); - ti->setOwnershipKind(ValueOwnershipKind::Guaranteed); - return ti; - } - case OwnedValueIntroducerKind::Copy: - case OwnedValueIntroducerKind::LoadCopy: - case OwnedValueIntroducerKind::Apply: - case OwnedValueIntroducerKind::BeginApply: - case OwnedValueIntroducerKind::TryApply: - case OwnedValueIntroducerKind::LoadTake: - case OwnedValueIntroducerKind::FunctionArgument: - case OwnedValueIntroducerKind::PartialApplyInit: - case OwnedValueIntroducerKind::AllocBoxInit: - case OwnedValueIntroducerKind::AllocRefInit: - return SILValue(); - } -} - -void OwnershipLiveRange::convertJoinedLiveRangePhiToGuaranteed( - DeadEndBlocks &deadEndBlocks, ValueLifetimeAnalysis::Frontier &scratch, - InstModCallbacks callbacks) && { - - // First convert the phi value itself to be guaranteed. - SILValue phiValue = convertIntroducerToGuaranteed(introducer); - - // Then insert end_borrows at each of our destroys if we are consuming. We - // have to convert the phi to guaranteed first since otherwise, the ownership - // check when we create the end_borrows will trigger. - if (introducer.hasConsumingGuaranteedOperands()) { - insertEndBorrowsAtDestroys(phiValue, deadEndBlocks, scratch); - } - - // Then eliminate all of the destroys... - while (!destroyingUses.empty()) { - auto *d = destroyingUses.back(); - destroyingUses = destroyingUses.drop_back(); - callbacks.deleteInst(d->getUser()); - ++NumEliminatedInsts; - } - - // and change all of our guaranteed forwarding insts to have guaranteed - // ownership kind instead of what ever they previously had (ignoring trivial - // results); - std::move(*this).convertOwnedGeneralForwardingUsesToGuaranteed(); -} - -OwnershipLiveRange::HasConsumingUse_t -OwnershipLiveRange::hasUnknownConsumingUse(bool assumingAtFixPoint) const { - // First do a quick check if we have /any/ unknown consuming - // uses. If we do not have any, return false early. - if (unknownConsumingUses.empty()) { - return HasConsumingUse_t::No; - } - - // Ok, we do have some unknown consuming uses. If we aren't assuming we are at - // the fixed point yet, just bail. - if (!assumingAtFixPoint) { - return HasConsumingUse_t::Yes; - } - - // We do not know how to handle yet cases where an owned value is used by - // multiple phi nodes. So we bail early if unknown consuming uses is > 1. - // - // TODO: Build up phi node web. - auto *op = getSingleUnknownConsumingUse(); - if (!op) { - return HasConsumingUse_t::Yes; - } - - // Make sure our single unknown consuming use is a branch inst. If not, bail, - // this is a /real/ unknown consuming use. - if (!OwnershipPhiOperand::get(op)) { - return HasConsumingUse_t::Yes; - } - - // Otherwise, setup the phi to incoming value map mapping the block arguments - // to our introducer. - return HasConsumingUse_t::YesButAllPhiArgs; -} - -//===----------------------------------------------------------------------===// -// Address Written To Analysis -//===----------------------------------------------------------------------===// - -/// Returns true if we were able to ascertain that either the initialValue has -/// no write uses or all of the write uses were writes that we could understand. -static bool -constructCacheValue(SILValue initialValue, - SmallVectorImpl &wellBehavedWriteAccumulator) { - SmallVector worklist(initialValue->getUses()); - - while (!worklist.empty()) { - auto *op = worklist.pop_back_val(); - SILInstruction *user = op->getUser(); - - if (Projection::isAddressProjection(user) || - isa(user)) { - for (SILValue r : user->getResults()) { - llvm::copy(r->getUses(), std::back_inserter(worklist)); - } - continue; - } - - if (auto *oeai = dyn_cast(user)) { - // Mutable access! - if (oeai->getAccessKind() != OpenedExistentialAccess::Immutable) { - wellBehavedWriteAccumulator.push_back(op); - } - - // Otherwise, look through it and continue. - llvm::copy(oeai->getUses(), std::back_inserter(worklist)); - continue; - } - - if (auto *si = dyn_cast(user)) { - // We must be the dest since addresses can not be stored. - assert(si->getDest() == op->get()); - wellBehavedWriteAccumulator.push_back(op); - continue; - } - - // Add any destroy_addrs to the resultAccumulator. - if (isa(user)) { - wellBehavedWriteAccumulator.push_back(op); - continue; - } - - // load_borrow and incidental uses are fine as well. - if (isa(user) || isIncidentalUse(user)) { - continue; - } - - // Look through begin_access and mark them/their end_borrow as users. - if (auto *bai = dyn_cast(user)) { - // If we do not have a read, mark this as a write. Also, insert our - // end_access as well. - if (bai->getAccessKind() != SILAccessKind::Read) { - wellBehavedWriteAccumulator.push_back(op); - transform(bai->getUsersOfType(), - std::back_inserter(wellBehavedWriteAccumulator), - [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); - } - - // And then add the users to the worklist and continue. - llvm::copy(bai->getUses(), std::back_inserter(worklist)); - continue; - } - - // If we have a load, we just need to mark the load [take] as a write. - if (auto *li = dyn_cast(user)) { - if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take) { - wellBehavedWriteAccumulator.push_back(op); - } - continue; - } - - // If we have a FullApplySite, we need to do per convention/inst logic. - if (auto fas = FullApplySite::isa(user)) { - // Begin by seeing if we have an in_guaranteed use. If we do, we are done. - if (fas.getArgumentConvention(*op) == - SILArgumentConvention::Indirect_In_Guaranteed) { - continue; - } - - // Then see if we have an apply site that is not a coroutine apply - // site. In such a case, without further analysis, we can treat it like an - // instantaneous write and validate that it doesn't overlap with our load - // [copy]. - if (!fas.beginsCoroutineEvaluation() && - fas.getArgumentConvention(*op).isInoutConvention()) { - wellBehavedWriteAccumulator.push_back(op); - continue; - } - - // Otherwise, be conservative and return that we had a write that we did - // not understand. - LLVM_DEBUG(llvm::dbgs() - << "Function: " << user->getFunction()->getName() << "\n"); - LLVM_DEBUG(llvm::dbgs() << "Value: " << op->get()); - LLVM_DEBUG(llvm::dbgs() << "Unhandled apply site!: " << *user); - - return false; - } - - // Copy addr that read are just loads. - if (auto *cai = dyn_cast(user)) { - // If our value is the destination, this is a write. - if (cai->getDest() == op->get()) { - wellBehavedWriteAccumulator.push_back(op); - continue; - } - - // Ok, so we are Src by process of elimination. Make sure we are not being - // taken. - if (cai->isTakeOfSrc()) { - wellBehavedWriteAccumulator.push_back(op); - continue; - } - - // Otherwise, we are safe and can continue. - continue; - } - - // If we did not recognize the user, just return conservatively that it was - // written to in a way we did not understand. - LLVM_DEBUG(llvm::dbgs() - << "Function: " << user->getFunction()->getName() << "\n"); - LLVM_DEBUG(llvm::dbgs() << "Value: " << op->get()); - LLVM_DEBUG(llvm::dbgs() << "Unknown instruction!: " << *user); - return false; - } - - // Ok, we finished our worklist and this address is not being written to. - return true; -} - -//===----------------------------------------------------------------------===// -// Implementation -//===----------------------------------------------------------------------===// - -namespace { - -/// A visitor that optimizes ownership instructions and eliminates any trivially -/// dead code that results after optimization. It uses an internal worklist that -/// is initialized on construction with targets to avoid iterator invalidation -/// issues. Rather than revisit the entire CFG like SILCombine and other -/// visitors do, we maintain a visitedSinceLastMutation list to ensure that we -/// revisit all interesting instructions in between mutations. -struct SemanticARCOptVisitor - : SILInstructionVisitor { - /// Our main worklist. We use this after an initial run through. - SmallBlotSetVector worklist; - - /// A set of values that we have visited since the last mutation. We use this - /// to ensure that we do not visit values twice without mutating. - /// - /// This is specifically to ensure that we do not go into an infinite loop - /// when visiting phi nodes. - SmallBlotSetVector visitedSinceLastMutation; - - SILFunction &F; - Optional TheDeadEndBlocks; - ValueLifetimeAnalysis::Frontier lifetimeFrontier; - SmallMultiMapCache addressToExhaustiveWriteListCache; - - /// Are we assuming that we reached a fix point and are re-processing to - /// prepare to use the phiToIncomingValueMultiMap. - bool assumingAtFixedPoint = false; - - /// A map from a value that acts as a "joined owned introducer" in the def-use - /// graph. - /// - /// A "joined owned introducer" is a value with owned ownership whose - /// ownership is derived from multiple non-trivial owned operands of a related - /// instruction. Some examples are phi arguments, tuples, structs. Naturally, - /// all of these instructions must be non-unary instructions and only have - /// this property if they have multiple operands that are non-trivial. - /// - /// In such a case, we can not just treat them like normal forwarding concepts - /// since we can only eliminate optimize such a value if we are able to reason - /// about all of its operands together jointly. This is not amenable to a - /// small peephole analysis. - /// - /// Instead, as we perform the peephole analysis, using the multimap, we map - /// each joined owned value introducer to the set of its @owned operands that - /// we thought we could convert to guaranteed only if we could do the same to - /// the joined owned value introducer. Then once we finish performing - /// peepholes, we iterate through the map and see if any of our joined phi - /// ranges had all of their operand's marked with this property by iterating - /// over the multimap. Since we are dealing with owned values and we know that - /// our LiveRange can not see through joined live ranges, we know that we - /// should only be able to have a single owned value introducer for each - /// consumed operand. - FrozenMultiMap joinedOwnedIntroducerToConsumedOperands; - - /// If set to true, then we should only run cheap optimizations that do not - /// build up data structures or analyze code in depth. - /// - /// As an example, we do not do load [copy] optimizations here since they - /// generally involve more complex analysis, but simple peepholes of - /// copy_values we /do/ allow. - bool onlyGuaranteedOpts; - - using FrozenMultiMapRange = - decltype(joinedOwnedIntroducerToConsumedOperands)::PairToSecondEltRange; - - explicit SemanticARCOptVisitor(SILFunction &F, bool onlyGuaranteedOpts) - : F(F), addressToExhaustiveWriteListCache(constructCacheValue), - onlyGuaranteedOpts(onlyGuaranteedOpts) {} - - DeadEndBlocks &getDeadEndBlocks() { - if (!TheDeadEndBlocks) - TheDeadEndBlocks.emplace(&F); - return *TheDeadEndBlocks; - } - - /// Given a single value instruction, RAUW it with newValue, add newValue to - /// the worklist, and then call eraseInstruction on i. - void eraseAndRAUWSingleValueInstruction(SingleValueInstruction *i, SILValue newValue) { - worklist.insert(newValue); - for (auto *use : i->getUses()) { - for (SILValue result : use->getUser()->getResults()) { - worklist.insert(result); - } - } - i->replaceAllUsesWith(newValue); - eraseInstructionAndAddOperandsToWorklist(i); - } - - /// Add all operands of i to the worklist and then call eraseInstruction on - /// i. Assumes that the instruction doesnt have users. - void eraseInstructionAndAddOperandsToWorklist(SILInstruction *i) { - // Then copy all operands into the worklist for future processing. - for (SILValue v : i->getOperandValues()) { - worklist.insert(v); - } - eraseInstruction(i); - } - - /// Pop values off of visitedSinceLastMutation, adding .some values to the - /// worklist. - void drainVisitedSinceLastMutationIntoWorklist() { - while (!visitedSinceLastMutation.empty()) { - Optional nextValue = visitedSinceLastMutation.pop_back_val(); - if (!nextValue.hasValue()) { - continue; - } - worklist.insert(*nextValue); - } - } - - /// Remove all results of the given instruction from the worklist and then - /// erase the instruction. Assumes that the instruction does not have any - /// users left. - void eraseInstruction(SILInstruction *i) { - // Remove all SILValues of the instruction from the worklist and then erase - // the instruction. - for (SILValue result : i->getResults()) { - worklist.erase(result); - visitedSinceLastMutation.erase(result); - } - i->eraseFromParent(); - - // Add everything else from visitedSinceLastMutation to the worklist. - drainVisitedSinceLastMutationIntoWorklist(); - } - - InstModCallbacks getCallbacks() { - return InstModCallbacks( - [this](SILInstruction *inst) { eraseInstruction(inst); }, - [](SILInstruction *) {}, [](SILValue, SILValue) {}, - [this](SingleValueInstruction *i, SILValue value) { - eraseAndRAUWSingleValueInstruction(i, value); - }); - } - - /// The default visitor. - bool visitSILInstruction(SILInstruction *i) { - assert(!isGuaranteedForwardingInst(i) && - "Should have forwarding visitor for all ownership forwarding " - "instructions"); - return false; - } - - bool visitCopyValueInst(CopyValueInst *cvi); - bool visitBeginBorrowInst(BeginBorrowInst *bbi); - bool visitLoadInst(LoadInst *li); - static bool shouldVisitInst(SILInstruction *i) { - switch (i->getKind()) { - default: - return false; - case SILInstructionKind::CopyValueInst: - case SILInstructionKind::BeginBorrowInst: - case SILInstructionKind::LoadInst: - return true; - } - } - -#define FORWARDING_INST(NAME) \ - bool visit##NAME##Inst(NAME##Inst *cls) { \ - for (SILValue v : cls->getResults()) { \ - worklist.insert(v); \ - } \ - return false; \ - } - FORWARDING_INST(Tuple) - FORWARDING_INST(Struct) - FORWARDING_INST(Enum) - FORWARDING_INST(OpenExistentialRef) - FORWARDING_INST(Upcast) - FORWARDING_INST(UncheckedRefCast) - FORWARDING_INST(ConvertFunction) - FORWARDING_INST(RefToBridgeObject) - FORWARDING_INST(BridgeObjectToRef) - FORWARDING_INST(UnconditionalCheckedCast) - FORWARDING_INST(UncheckedEnumData) - FORWARDING_INST(MarkUninitialized) - FORWARDING_INST(SelectEnum) - FORWARDING_INST(DestructureStruct) - FORWARDING_INST(DestructureTuple) - FORWARDING_INST(TupleExtract) - FORWARDING_INST(StructExtract) - FORWARDING_INST(OpenExistentialValue) - FORWARDING_INST(OpenExistentialBoxValue) - FORWARDING_INST(MarkDependence) - FORWARDING_INST(InitExistentialRef) - FORWARDING_INST(DifferentiableFunction) - FORWARDING_INST(LinearFunction) - FORWARDING_INST(DifferentiableFunctionExtract) - FORWARDING_INST(LinearFunctionExtract) -#undef FORWARDING_INST - -#define FORWARDING_TERM(NAME) \ - bool visit##NAME##Inst(NAME##Inst *cls) { \ - for (auto succValues : cls->getSuccessorBlockArgumentLists()) { \ - for (SILValue v : succValues) { \ - worklist.insert(v); \ - } \ - } \ - return false; \ - } - - FORWARDING_TERM(SwitchEnum) - FORWARDING_TERM(CheckedCastBranch) - FORWARDING_TERM(Branch) -#undef FORWARDING_TERM - - bool isWrittenTo(LoadInst *li, const OwnershipLiveRange &lr); - - bool processWorklist(); - bool optimize(); - - bool performGuaranteedCopyValueOptimization(CopyValueInst *cvi); - bool eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi); - bool tryJoiningCopyValueLiveRangeWithOperand(CopyValueInst *cvi); - bool performPostPeepholeOwnedArgElimination(); -}; - -} // end anonymous namespace - -static llvm::cl::opt -VerifyAfterTransform("sil-semantic-arc-opts-verify-after-transform", - llvm::cl::init(false), llvm::cl::Hidden); - -static bool canEliminatePhi( - SemanticARCOptVisitor::FrozenMultiMapRange optimizableIntroducerRange, - ArrayRef incomingValueOperandList, - SmallVectorImpl &ownedValueIntroducerAccumulator) { - for (auto incomingValueOperand : incomingValueOperandList) { - SILValue incomingValue = incomingValueOperand.getValue(); - - // Before we do anything, see if we have an incoming value with trivial - // ownership. This can occur in the case where we are working with enums due - // to trivial non-payloaded cases. Skip that. - if (incomingValue.getOwnershipKind() == ValueOwnershipKind::None) { - continue; - } - - // Then see if this is an introducer that we actually saw as able to be - // optimized if we could flip this joined live range. - // - // NOTE: If this linear search is too slow, we can change the multimap to - // sort the mapped to list by pointer instead of insertion order. In such a - // case, we could then bisect. - if (llvm::find(optimizableIntroducerRange, - incomingValueOperand.getOperand()) == - optimizableIntroducerRange.end()) { - return false; - } - - // Now that we know it is an owned value that we saw before, check for - // introducers of the owned value which are the copies that we may be able - // to eliminate. Since we do not look through joined live ranges, we must - // only have a single introducer. So look for that one and if not, bail. - auto singleIntroducer = getSingleOwnedValueIntroducer(incomingValue); - if (!singleIntroducer.hasValue()) { - return false; - } - - // Then make sure that our owned value introducer is able to be converted to - // guaranteed and that we found it to have a LiveRange that we could have - // eliminated /if/ we were to get rid of this phi. - if (!singleIntroducer->isConvertableToGuaranteed()) { - return false; - } - - // Otherwise, add the introducer to our result array. - ownedValueIntroducerAccumulator.push_back(*singleIntroducer); - } - -#ifndef NDEBUG - // Other parts of the pass ensure that we only add values to the list if their - // owned value introducer is not used by multiple live ranges. That being - // said, lets assert that. - { - SmallVector uniqueCheck; - llvm::copy(ownedValueIntroducerAccumulator, - std::back_inserter(uniqueCheck)); - sortUnique(uniqueCheck); - assert( - uniqueCheck.size() == ownedValueIntroducerAccumulator.size() && - "multiple joined live range operands are from the same live range?!"); - } -#endif - - return true; -} - -static bool getIncomingJoinedLiveRangeOperands( - SILValue joinedLiveRange, - SmallVectorImpl &resultingOperands) { - if (auto *phi = dyn_cast(joinedLiveRange)) { - return phi->visitIncomingPhiOperands([&](Operand *op) { - if (auto phiOp = OwnershipPhiOperand::get(op)) { - resultingOperands.push_back(*phiOp); - return true; - } - return false; - }); - } - - if (auto *svi = dyn_cast(joinedLiveRange)) { - return llvm::all_of(svi->getAllOperands(), [&](const Operand &op) { - // skip type dependent operands. - if (op.isTypeDependent()) - return true; - - auto phiOp = OwnershipPhiOperand::get(&op); - if (!phiOp) - return false; - resultingOperands.push_back(*phiOp); - return true; - }); - } - - llvm_unreachable("Unhandled joined live range?!"); -} - -bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() { - bool madeChange = false; - - // First freeze our multi-map so we can use it for map queries. Also, setup a - // defer of the reset so we do not forget to reset the map when we are done. - joinedOwnedIntroducerToConsumedOperands.setFrozen(); - SWIFT_DEFER { joinedOwnedIntroducerToConsumedOperands.reset(); }; - - // Now for each phi argument that we have in our multi-map... - SmallVector incomingValueOperandList; - SmallVector ownedValueIntroducers; - for (auto pair : joinedOwnedIntroducerToConsumedOperands.getRange()) { - SWIFT_DEFER { - incomingValueOperandList.clear(); - ownedValueIntroducers.clear(); - }; - - // First compute the LiveRange for ownershipPhi value. For simplicity, we - // only handle cases now where the result does not have any additional - // ownershipPhi uses. - SILValue joinedIntroducer = pair.first; - OwnershipLiveRange joinedLiveRange(joinedIntroducer); - if (bool(joinedLiveRange.hasUnknownConsumingUse())) { - continue; - } - - // Ok, we know that our phi argument /could/ be converted to guaranteed if - // our incoming values are able to be converted to guaranteed. Now for each - // incoming value, compute the incoming values ownership roots and see if - // all of the ownership roots are in our owned incoming value array. - if (!getIncomingJoinedLiveRangeOperands(joinedIntroducer, - incomingValueOperandList)) { - continue; - } - - // Grab our list of introducer values paired with this SILArgument. See if - // all of these introducer values were ones that /could/ have been - // eliminated if it was not for the given phi. If all of them are, we can - // optimize! - { - auto rawFoundOptimizableIntroducerArray = pair.second; - if (!canEliminatePhi(rawFoundOptimizableIntroducerArray, - incomingValueOperandList, ownedValueIntroducers)) { - continue; - } - } - - // Ok, at this point we know that we can eliminate this phi. First go - // through the list of incomingValueOperandList and stash the value/set the - // operand's stored value to undef. We will hook them back up later. - SmallVector originalIncomingValues; - for (auto &incomingValueOperand : incomingValueOperandList) { - originalIncomingValues.push_back(incomingValueOperand.getValue()); - incomingValueOperand.markUndef(); - } - - // Then go through all of our owned value introducers, compute their live - // ranges, and eliminate them. We know it is safe to remove them from our - // previous proofs. - // - // NOTE: If our introducer is a copy_value that is one of our - // originalIncomingValues, we need to update the originalIncomingValue array - // with that value since we are going to delete the copy_value here. This - // creates a complication since we want to binary_search on - // originalIncomingValues to detect this same condition! So, we create a - // list of updates that we apply after we no longer need to perform - // binary_search, but before we start RAUWing things. - SmallVector, 8> incomingValueUpdates; - for (auto introducer : ownedValueIntroducers) { - SILValue v = introducer.value; - OwnershipLiveRange lr(v); - - // For now, we only handle copy_value for simplicity. - // - // TODO: Add support for load [copy]. - if (introducer.kind == OwnedValueIntroducerKind::Copy) { - auto *cvi = cast(v); - // Before we convert from owned to guaranteed, we need to first see if - // cvi is one of our originalIncomingValues. If so, we need to set - // originalIncomingValues to be cvi->getOperand(). Otherwise, weirdness - // results since we are deleting one of our stashed values. - auto iter = find(originalIncomingValues, cvi); - if (iter != originalIncomingValues.end()) { - // We use an auxillary array here so we can continue to bisect on - // original incoming values. Once we are done processing here, we will - // not need that property anymore. - unsigned updateOffset = - std::distance(originalIncomingValues.begin(), iter); - incomingValueUpdates.emplace_back(cvi->getOperand(), updateOffset); - } - std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), - getCallbacks()); - continue; - } - llvm_unreachable("Unhandled optimizable introducer!"); - } - - // Now go through and update our original incoming value array now that we - // do not need it to be sorted for bisection purposes. - while (!incomingValueUpdates.empty()) { - auto pair = incomingValueUpdates.pop_back_val(); - originalIncomingValues[pair.second] = pair.first; - } - - // Then convert the phi's live range to be guaranteed. - std::move(joinedLiveRange) - .convertJoinedLiveRangePhiToGuaranteed( - getDeadEndBlocks(), lifetimeFrontier, getCallbacks()); - - // Now if our phi operand consumes/forwards its guaranteed input, insert a - // begin_borrow along the incoming value edges. We have to do this after - // converting the incoming values to be guaranteed to avoid tripping - // SILBuilder checks around simple ownership invariants (namely that def/use - // line up) when creating instructions. - assert(incomingValueOperandList.size() == originalIncomingValues.size()); - while (!incomingValueOperandList.empty()) { - auto incomingValueOperand = incomingValueOperandList.pop_back_val(); - SILValue originalValue = originalIncomingValues.pop_back_val(); - if (incomingValueOperand.isGuaranteedConsuming() && - originalValue.getOwnershipKind() != ValueOwnershipKind::None) { - auto loc = RegularLocation::getAutoGeneratedLocation(); - SILBuilderWithScope builder(incomingValueOperand.getInst()); - originalValue = builder.createBeginBorrow(loc, originalValue); - } - incomingValueOperand.getOperand()->set(originalValue); - } - - madeChange = true; - if (VerifyAfterTransform) { - F.verify(); - } - } - - return madeChange; -} - -bool SemanticARCOptVisitor::optimize() { - bool madeChange = false; - - // First process the worklist until we reach a fixed point. - madeChange |= processWorklist(); - - { - // If we made a change, set that we assume we are at fixed point and then - // re-run the worklist so that we can - // properly seeded the ARC peephole map. - assumingAtFixedPoint = true; - SWIFT_DEFER { assumingAtFixedPoint = false; }; - - // Add everything in visitedSinceLastMutation to the worklist so we - // recompute our fixed point. - drainVisitedSinceLastMutationIntoWorklist(); - - // Then re-run the worklist. We shouldn't modify anything since we are at a - // fixed point and are just using this to seed the - // joinedOwnedIntroducerToConsumedOperands after we have finished changing - // things. If we did change something, we did something weird, so assert! - bool madeAdditionalChanges = processWorklist(); - (void)madeAdditionalChanges; - assert(!madeAdditionalChanges && "Should be at the fixed point"); - } - - // Then use the newly seeded peephole map to - madeChange |= performPostPeepholeOwnedArgElimination(); - - return madeChange; -} - -bool SemanticARCOptVisitor::processWorklist() { - // NOTE: The madeChange here is not strictly necessary since we only have - // items added to the worklist today if we have already made /some/ sort of - // change. That being said, I think there is a low cost to including this here - // and makes the algorithm more correct, visually and in the face of potential - // refactoring. - bool madeChange = false; - - while (!worklist.empty()) { - // Pop the last element off the list. If we were returned None, we blotted - // this element, so skip it. - SILValue next = worklist.pop_back_val().getValueOr(SILValue()); - if (!next) - continue; - - // First check if this is a value that we have visited since the last time - // we erased an instruction. If we have visited it, skip it. Every time we - // modify something, we should be deleting an instruction, so we have not - // found any further information. - if (!visitedSinceLastMutation.insert(next).second) { - continue; - } - - // First check if this is an instruction that is trivially dead. This can - // occur if we eliminate rr traffic resulting in dead projections and the - // like. - // - // If we delete, we first add all of our deleted instructions operands to - // the worklist and then remove all results (since we are going to delete - // the instruction). - if (auto *defInst = next->getDefiningInstruction()) { - if (isInstructionTriviallyDead(defInst)) { - assert(!assumingAtFixedPoint && - "Assumed was at fixed point and recomputing state?!"); - deleteAllDebugUses(defInst); - eraseInstruction(defInst); - madeChange = true; - if (VerifyAfterTransform) { - F.verify(); - } - continue; - } - } - - // Otherwise, if we have a single value instruction (to be expanded later - // perhaps), try to visit that value recursively. - if (auto *svi = dyn_cast(next)) { - bool madeSingleChange = visit(svi); - assert((!madeSingleChange || !assumingAtFixedPoint) && - "Assumed was at fixed point and modified state?!"); - madeChange |= madeSingleChange; - if (VerifyAfterTransform && madeSingleChange) { - F.verify(); - } - continue; - } - } - - return madeChange; -} - -//===----------------------------------------------------------------------===// -// Redundant Borrow Scope Elimination -//===----------------------------------------------------------------------===// - -bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) { - auto kind = bbi->getOperand().getOwnershipKind(); - SmallVector endBorrows; - for (auto *op : bbi->getUses()) { - if (!op->isConsumingUse()) { - // Make sure that this operand can accept our arguments kind. - auto map = op->getOwnershipKindMap(); - if (map.canAcceptKind(kind)) - continue; - return false; - } - - // Otherwise, this borrow is being consumed. See if our consuming inst is an - // end_borrow. If it isn't, then return false, this scope is - // needed. Otherwise, add the end_borrow to our list of end borrows. - auto *ebi = dyn_cast(op->getUser()); - if (!ebi) { - return false; - } - endBorrows.push_back(ebi); - } - - // At this point, we know that the begin_borrow's operand can be - // used as an argument to all non-end borrow uses. Eliminate the - // begin borrow and end borrows. - while (!endBorrows.empty()) { - auto *ebi = endBorrows.pop_back_val(); - eraseInstruction(ebi); - ++NumEliminatedInsts; - } - - eraseAndRAUWSingleValueInstruction(bbi, bbi->getOperand()); - ++NumEliminatedInsts; - return true; -} - -//===----------------------------------------------------------------------===// -// CopyValue Optimizations Elimination -//===----------------------------------------------------------------------===// - -// Eliminate a copy of a borrowed value, if: -// -// 1. All of the copies users do not consume the copy (and thus can accept a -// borrowed value instead). -// 2. The copies's non-destroy_value users are strictly contained within the -// scope of the borrowed value. -// -// Example: -// -// %0 = @guaranteed (argument or instruction) -// %1 = copy_value %0 -// apply %f(%1) : $@convention(thin) (@guaranteed ...) ... -// other_non_consuming_use %1 -// destroy_value %1 -// end_borrow %0 (if an instruction) -// -// => -// -// %0 = @guaranteed (argument or instruction) -// apply %f(%0) : $@convention(thin) (@guaranteed ...) ... -// other_non_consuming_use %0 -// end_borrow %0 (if an instruction) -// -// NOTE: This means that the destroy_value technically can be after the -// end_borrow. In practice, this will not be the case but we use this to avoid -// having to reason about the ordering of the end_borrow and destroy_value. -// -// NOTE: Today we only perform this for guaranteed parameters since this enables -// us to avoid doing the linear lifetime check to make sure that all destroys -// are within the borrow scope. -// -// TODO: This needs a better name. -bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst *cvi) { - // For now, do not run this optimization. This is just to be careful. - if (onlyGuaranteedOpts) - return false; - - SmallVector borrowScopeIntroducers; - - // Find all borrow introducers for our copy operand. If we are unable to find - // all of the reproducers (due to pattern matching failure), conservatively - // return false. We can not optimize. - // - // NOTE: We can get multiple introducers if our copy_value's operand - // value runs through a phi or an aggregate forming instruction. - if (!getAllBorrowIntroducingValues(cvi->getOperand(), borrowScopeIntroducers)) - return false; - - // Then go over all of our uses and see if the value returned by our copy - // value forms a dead live range or a live range that would be dead if it was - // not consumed by phi nodes. If we do not have such a live range, there must - // be some consuming use that we either do not understand is /actually/ - // forwarding or a user that truly represents a necessary consume of the value - // (e.x. storing into memory). - OwnershipLiveRange lr(cvi); - auto hasUnknownConsumingUseState = - lr.hasUnknownConsumingUse(assumingAtFixedPoint); - if (hasUnknownConsumingUseState == - OwnershipLiveRange::HasConsumingUse_t::Yes) { - return false; - } - - // Next check if we do not have any destroys of our copy_value and are - // processing a local borrow scope. In such a case, due to the way we ignore - // dead end blocks, we may eliminate the copy_value, creating a use of the - // borrowed value after the end_borrow. To avoid this, in such cases we - // bail. In contrast, a non-local borrow scope does not have any end scope - // instructions, implying we can avoid this hazard and still optimize in such - // a case. - // - // DISCUSSION: Consider the following SIL: - // - // ``` - // %1 = begin_borrow %0 : $KlassPair (1) - // %2 = struct_extract %1 : $KlassPair, #KlassPair.firstKlass - // %3 = copy_value %2 : $Klass - // ... - // end_borrow %1 : $LintCommand (2) - // cond_br ..., bb1, bb2 - // - // ... - // - // bbN: - // // Never return type implies dead end block. - // apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> Never (3) - // unreachable - // ``` - // - // For simplicity, note that if bbN post-dominates %3, given that when we - // compute linear lifetime errors we ignore dead end blocks, we would not - // register that the copy_values only use is outside of the begin_borrow - // region defined by (1), (2) and thus would eliminate the copy. This would - // result in %2 being used by %f, causing the linear lifetime checker to - // error. - // - // Naively one may assume that the solution to this is to just check if %3 has - // /any/ destroy_values at all and if it doesn't have any reachable - // destroy_values, then we are in this case. But is this correct in - // general. We prove this below: - // - // The only paths along which the copy_value can not be destroyed or consumed - // is along paths to dead end blocks. Trivially, we know that such a dead end - // block, can not be reachable from the end_borrow since by their nature dead - // end blocks end in unreachables. - // - // So we know that we can only run into this bug if we have a dead end block - // reachable from the end_borrow, meaning that the bug can not occur if we - // branch before the end_borrow since in that case, the borrow scope would - // last over the dead end block's no return meaning that we will not use the - // borrowed value after its lifetime is ended by the end_borrow. - // - // With that in hand, we note again that if we have exactly one consumed, - // destroy_value /after/ the end_borrow we will not optimize here. This means - // that this bug can only occur if the copy_value is only post-dominated by - // dead end blocks that use the value in a non-consuming way. - // - // TODO: There may be some way of sinking this into the loop below. - bool haveAnyLocalScopes = - llvm::any_of(borrowScopeIntroducers, [](BorrowedValue borrowScope) { - return borrowScope.isLocalScope(); - }); - - auto destroys = lr.getDestroyingUses(); - if (destroys.empty() && haveAnyLocalScopes) { - return false; - } - - // If we reached this point, then we know that all of our users can accept a - // guaranteed value and our owned value is destroyed only by a set of - // destroy_values. Check if: - // - // 1. All of our destroys are joint post-dominated by our end borrow scope - // set. If they do not, then the copy_value is lifetime extending the - // guaranteed value, we can not eliminate it. - // - // 2. If all of our destroy_values are dead end. In such a case, the linear - // lifetime checker will not perform any checks since it assumes that dead - // end destroys can be ignored. Since we are going to end the program - // anyways, we want to be conservative here and optimize only if we do not - // need to insert an end_borrow since all of our borrow introducers are - // non-local scopes. - { - bool foundNonDeadEnd = false; - for (auto *d : destroys) { - foundNonDeadEnd |= !getDeadEndBlocks().isDeadEnd(d->getParentBlock()); - } - if (!foundNonDeadEnd && haveAnyLocalScopes) - return false; - SmallVector scratchSpace; - SmallPtrSet visitedBlocks; - if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) { - return !borrowScope.areUsesWithinScope(lr.getAllConsumingUses(), - scratchSpace, visitedBlocks, - getDeadEndBlocks()); - })) { - return false; - } - } - - // Otherwise, we know that our copy_value/destroy_values are all completely - // within the guaranteed value scope. So we /could/ optimize it. Now check if - // we were truly dead or if we are dead if we can eliminate phi arg uses. If - // we need to handle the phi arg uses, we bail. After we reach a fixed point, - // we will try to eliminate this value then if we can find a complete set of - // all incoming values to our phi argument. - if (hasUnknownConsumingUseState == - OwnershipLiveRange::HasConsumingUse_t::YesButAllPhiArgs) { - auto opPhi = *OwnershipPhiOperand::get(lr.getSingleUnknownConsumingUse()); - SmallVector scratchSpace; - SmallPtrSet visitedBlocks; - - bool canOptimizePhi = opPhi.visitResults([&](SILValue value) { - SWIFT_DEFER { - scratchSpace.clear(); - visitedBlocks.clear(); - }; - - OwnershipLiveRange phiArgLR(value); - if (bool(phiArgLR.hasUnknownConsumingUse())) { - return false; - } - - if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) { - return !borrowScope.areUsesWithinScope( - phiArgLR.getAllConsumingUses(), scratchSpace, visitedBlocks, - getDeadEndBlocks()); - })) { - return false; - } - - return true; - }); - - if (canOptimizePhi) { - opPhi.visitResults([&](SILValue value) { - joinedOwnedIntroducerToConsumedOperands.insert(value, - opPhi.getOperand()); - return true; - }); - } - - return false; - } - - // Otherwise, our copy must truly not be needed, o RAUW and convert to - // guaranteed! - std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), getCallbacks()); - ++NumEliminatedInsts; - return true; -} - -/// If cvi only has destroy value users, then cvi is a dead live range. Lets -/// eliminate all such dead live ranges. -bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi) { - // This is a cheap optimization generally. - - // See if we are lucky and have a simple case. - if (auto *op = cvi->getSingleUse()) { - if (auto *dvi = dyn_cast(op->getUser())) { - eraseInstruction(dvi); - eraseInstructionAndAddOperandsToWorklist(cvi); - NumEliminatedInsts += 2; - return true; - } - } - - // If all of our copy_value users are destroy_value, zap all of the - // instructions. We begin by performing that check and gathering up our - // destroy_value. - SmallVector destroys; - if (!all_of(cvi->getUses(), [&](Operand *op) { - auto *dvi = dyn_cast(op->getUser()); - if (!dvi) - return false; - - // Stash dvi in destroys so we can easily eliminate it later. - destroys.push_back(dvi); - return true; - })) { - return false; - } - - // Now that we have a truly dead live range copy value, eliminate it! - while (!destroys.empty()) { - eraseInstruction(destroys.pop_back_val()); - ++NumEliminatedInsts; - } - eraseInstructionAndAddOperandsToWorklist(cvi); - ++NumEliminatedInsts; - return true; -} - -// Handle simple checking where we do not need to form live ranges and visit a -// bunch of instructions. -static bool canSafelyJoinSimpleRange(SILValue cviOperand, - DestroyValueInst *cviOperandDestroy, - CopyValueInst *cvi) { - // We only handle cases where our copy_value has a single consuming use that - // is not a forwarding use. We need to use the LiveRange functionality to - // guarantee correctness in the presence of forwarding uses. - // - // NOTE: This use may be any type of consuming use and may not be a - // destroy_value. - auto *cviConsumer = cvi->getSingleConsumingUse(); - if (!cviConsumer || isOwnedForwardingInstruction(cviConsumer->getUser())) { - return false; - } - - // Ok, we may be able to eliminate this. The main thing we need to be careful - // of here is that if the destroy_value is /after/ the consuming use of the - // operand of copy_value, we may have normal uses of the copy_value's operand - // that would become use-after-frees since we would be shrinking the lifetime - // of the object potentially. Consider the following SIL: - // - // %0 = ... - // %1 = copy_value %0 - // apply %cviConsumer(%1) - // apply %guaranteedUser(%0) - // destroy_value %0 - // - // Easily, if we were to eliminate the copy_value, destroy_value, the object's - // lifetime could potentially be shrunk before guaranteedUser is executed, - // causing guaranteedUser to be a use-after-free. - // - // As an extra wrinkle, until all interior pointer constructs (e.x.: - // project_box) are guaranteed to be guaranted by a begin_borrow, we can not - // in general safely shrink lifetimes. So even if we think we can prove that - // all non-consuming uses of %0 are before apply %cviConsumer, we may miss - // implicit uses that are not guarded yet by a begin_borrow, resulting in - // use-after-frees. - // - // With that in mind, we only handle cases today where we can prove that - // destroy_value is strictly before the consuming use of the operand. This - // guarantees that we are not shrinking the lifetime of the underlying object. - // - // First we handle the simple case: where the cviConsumer is a return inst. In - // such a case, we know for sure that cviConsumer post-dominates the - // destroy_value. - auto cviConsumerIter = cviConsumer->getUser()->getIterator(); - if (isa(cviConsumerIter)) { - return true; - } - - // Then see if our cviConsumer is in the same block as a return inst and the - // destroy_value is not. In that case, we know that the cviConsumer must - // post-dominate the destroy_value. - auto *cviConsumingBlock = cviConsumerIter->getParent(); - if (isa(cviConsumingBlock->getTerminator()) && - cviConsumingBlock != cviOperandDestroy->getParent()) { - return true; - } - - // Otherwise, we only support joining live ranges where the cvi and the cvi's - // operand's destroy are in the same block with the destroy_value of cvi - // operand needing to be strictly after the copy_value. This analysis can be - // made significantly stronger by using LiveRanges, but this is simple for - // now. - auto cviOperandDestroyIter = cviOperandDestroy->getIterator(); - if (cviConsumingBlock != cviOperandDestroyIter->getParent()) { - return false; - } - - // TODO: This should really be llvm::find, but for some reason, the templates - // do not match up given the current state of the iterators. This impl works - // in a pinch though. - return llvm::any_of( - llvm::make_range(cviOperandDestroyIter, - cviOperandDestroyIter->getParent()->end()), - [&](const SILInstruction &val) { return &*cviConsumerIter == &val; }); -} - -// # The Problem We Are Solving -// -// The main idea here is that we are trying to eliminate the simplest, easiest -// form of live range joining. Consider the following SIL: -// -// ``` -// %cviOperand = ... // @owned value -// %cvi = copy_value %cviOperand // copy of @owned value -// ... -// destroy_value %cviOperandDestroy // destruction of @owned value -// ... -// apply %consumingUser(%cvi) // destruction of copy of @owned value -// ``` -// -// We want to reduce reference count traffic by eliminating the middle -// copy/destroy yielding: -// -// ``` -// %cviOperand = ... // @owned value -// // *eliminated copy_value* -// ... -// // *eliminated destroy_value* -// ... -// apply %consumingUser(%cviOperand) // destruction of copy of @owned -// value -// ``` -// -// # Safety -// -// In order to do this safely, we need to take the union of the two objects -// lifetimes since we are only joining lifetimes. This ensures that we can rely -// on SILGen's correctness on inserting safe lifetimes. To keep this simple -// today we only optimize if the destroy_value and consuming user are in the -// same block and the consuming user is later in the block than the -// destroy_value. -// -// DISCUSSION: The reason why we do not shrink lifetimes today is that all -// interior pointers (e.x. project_box) are properly guarded by -// begin_borrow. Because of that we can not shrink lifetimes and instead rely on -// SILGen's correctness. -bool SemanticARCOptVisitor::tryJoiningCopyValueLiveRangeWithOperand( - CopyValueInst *cvi) { - // First do a quick check if our operand is owned. If it is not owned, we can - // not join live ranges. - SILValue operand = cvi->getOperand(); - if (operand.getOwnershipKind() != ValueOwnershipKind::Owned) { - return false; - } - - // Then check if our operand has a single destroy_value. If it does and that - // destroy_value is strictly before the consumer of our copy_value in the same - // block as the consumer of said copy_value then we can always join the live - // ranges. - // - // Example: - // - // ``` - // %1 = copy_value %0 - // ... - // destroy_value %0 - // apply %consumingUser(%1) - // ``` - // -> - // - // ``` - // apply %consumingUser(%0) - // ``` - // - // DISCUSSION: We need to ensure that the consuming use of the copy_value is - // strictly after the destroy_value to ensure that we do not shrink the live - // range of the operand if the operand has any normal uses beyond our copy - // value. Otherwise, we could have normal uses /after/ the consuming use of - // our copy_value. - if (auto *dvi = operand->getSingleConsumingUserOfType()) { - if (canSafelyJoinSimpleRange(operand, dvi, cvi)) { - eraseInstruction(dvi); - eraseAndRAUWSingleValueInstruction(cvi, operand); - NumEliminatedInsts += 2; - return true; - } - } - - // Otherwise, we couldn't handle this case, so return false. - // - // NOTE: We would generally do a more complex analysis here to handle the more - // general case. That would most likely /not/ be a guaranteed optimization - // until we investigate/measure. - return false; -} - -bool SemanticARCOptVisitor::visitCopyValueInst(CopyValueInst *cvi) { - // If our copy value inst has only destroy_value users, it is a dead live - // range. Try to eliminate them. - if (eliminateDeadLiveRangeCopyValue(cvi)) { - return true; - } - - // Then see if copy_value operand's lifetime ends after our copy_value via a - // destroy_value. If so, we can join their lifetimes. - if (tryJoiningCopyValueLiveRangeWithOperand(cvi)) { - return true; - } - - // Then try to perform the guaranteed copy value optimization. - if (performGuaranteedCopyValueOptimization(cvi)) { - return true; - } - - return false; -} - -//===----------------------------------------------------------------------===// -// load [copy] Optimizations -//===----------------------------------------------------------------------===// - -namespace { - -/// A class that computes in a flow insensitive way if we can prove that our -/// storage is either never written to, or is initialized exactly once and never -/// written to again. In both cases, we can convert load [copy] -> load_borrow -/// safely. -class StorageGuaranteesLoadVisitor - : public AccessUseDefChainVisitor -{ - // The outer SemanticARCOptVisitor. - SemanticARCOptVisitor &ARCOpt; - - // The live range of the original load. - const OwnershipLiveRange &liveRange; - - // The current address being visited. - SILValue currentAddress; - - Optional isWritten; - -public: - StorageGuaranteesLoadVisitor(SemanticARCOptVisitor &arcOpt, LoadInst *load, - const OwnershipLiveRange &liveRange) - : ARCOpt(arcOpt), liveRange(liveRange), - currentAddress(load->getOperand()) {} - - void answer(bool written) { - currentAddress = nullptr; - isWritten = written; - } - - void next(SILValue address) { - currentAddress = address; - } - - void visitNestedAccess(BeginAccessInst *access) { - // First see if we have read/modify. If we do not, just look through the - // nested access. - switch (access->getAccessKind()) { - case SILAccessKind::Init: - case SILAccessKind::Deinit: - return next(access->getOperand()); - case SILAccessKind::Read: - case SILAccessKind::Modify: - break; - } - - // Next check if our live range is completely in the begin/end access - // scope. If so, we may be able to use a load_borrow here! - SmallVector endScopeUses; - transform(access->getEndAccesses(), std::back_inserter(endScopeUses), - [](EndAccessInst *eai) { - return &eai->getAllOperands()[0]; - }); - SmallPtrSet visitedBlocks; - LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); - if (!checker.validateLifetime(access, endScopeUses, - liveRange.getAllConsumingUses())) { - // If we fail the linear lifetime check, then just recur: - return next(access->getOperand()); - } - - // Otherwise, if we have read, then we are done! - if (access->getAccessKind() == SILAccessKind::Read) { - return answer(false); - } - - // If we have a modify, check if our value is /ever/ written to. If it is - // never actually written to, then we convert to a load_borrow. - auto result = ARCOpt.addressToExhaustiveWriteListCache.get(access); - if (!result.hasValue()) { - return answer(true); - } - - if (result.getValue().empty()) { - return answer(false); - } - - return answer(true); - } - - void visitArgumentAccess(SILFunctionArgument *arg) { - // If this load_copy is from an indirect in_guaranteed argument, then we - // know for sure that it will never be written to. - if (arg->hasConvention(SILArgumentConvention::Indirect_In_Guaranteed)) { - return answer(false); - } - - // If we have an inout parameter that isn't ever actually written to, return - // false. - if (arg->getKnownParameterInfo().isIndirectMutating()) { - auto wellBehavedWrites = - ARCOpt.addressToExhaustiveWriteListCache.get(arg); - if (!wellBehavedWrites.hasValue()) { - return answer(true); - } - - // No writes. - if (wellBehavedWrites->empty()) { - return answer(false); - } - - // Ok, we have some writes. See if any of them are within our live - // range. If any are, we definitely can not promote to load_borrow. - SmallPtrSet visitedBlocks; - SmallVector foundBeginAccess; - LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); - SILValue introducerValue = liveRange.getIntroducer().value; - if (!checker.usesNotContainedWithinLifetime(introducerValue, - liveRange.getDestroyingUses(), - *wellBehavedWrites)) { - return answer(true); - } - - // Finally, check if our live range is strictly contained within any of - // our scoped writes. - SmallVector endAccessList; - for (Operand *use : *wellBehavedWrites) { - auto *bai = dyn_cast(use->getUser()); - if (!bai) { - continue; - } - - endAccessList.clear(); - llvm::transform( - bai->getUsersOfType(), - std::back_inserter(endAccessList), - [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); - visitedBlocks.clear(); - - // We know that our live range is based on a load [copy], so we know - // that our value must have a defining inst. - auto *definingInst = - cast(introducerValue->getDefiningInstruction()); - - // Then if our defining inst is not in our bai, endAccessList region, we - // know that the two ranges must be disjoint, so continue. - if (!checker.validateLifetime(bai, endAccessList, - &definingInst->getAllOperands()[0])) { - continue; - } - - // Otherwise, we do have an overlap, return true. - return answer(true); - } - - // Otherwise, there isn't an overlap, so we don't write to it. - return answer(false); - } - - // TODO: This should be extended: - // - // 1. We should be able to analyze in arguments and see if they are only - // ever destroyed at the end of the function. In such a case, we may be - // able to also to promote load [copy] from such args to load_borrow. - return answer(true); - } - - void visitGlobalAccess(SILValue global) { - return answer(!AccessedStorage(global, AccessedStorage::Global) - .isLetAccess(&ARCOpt.F)); - } - - void visitClassAccess(RefElementAddrInst *field) { - currentAddress = nullptr; - - // We know a let property won't be written to if the base object is - // guaranteed for the duration of the access. - // For non-let properties conservatively assume they may be written to. - if (!field->getField()->isLet()) { - return answer(true); - } - - // The lifetime of the `let` is guaranteed if it's dominated by the - // guarantee on the base. See if we can find a single borrow introducer for - // this object. If we could not find a single such borrow introducer, assume - // that our property is conservatively written to. - SILValue baseObject = field->getOperand(); - auto value = getSingleBorrowIntroducingValue(baseObject); - if (!value) { - return answer(true); - } - - // Ok, we have a single borrow introducing value. First do a quick check if - // we have a non-local scope that is a function argument. In such a case, we - // know statically that our let can not be written to in the current - // function. To be conservative, assume that all other non-local scopes - // write to memory. - if (!value->isLocalScope()) { - if (value->kind == BorrowedValueKind::SILFunctionArgument) { - return answer(false); - } - - // TODO: Once we model Coroutine results as non-local scopes, we should be - // able to return false here for them as well. - return answer(true); - } - - // TODO: This is disabled temporarily for guaranteed phi args just for - // staging purposes. Thus be conservative and assume true in these cases. - if (value->kind == BorrowedValueKind::Phi) { - return answer(true); - } - - // Ok, we now know that we have a local scope whose lifetime we need to - // analyze. With that in mind, gather up the lifetime ending uses of our - // borrow scope introducing value and then use the linear lifetime checker - // to check whether the copied value is dominated by the lifetime of the - // borrow it's based on. - SmallVector endScopeInsts; - value->visitLocalScopeEndingUses( - [&](Operand *use) { endScopeInsts.push_back(use); }); - - SmallPtrSet visitedBlocks; - LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); - - // Returns true on success. So we invert. - bool foundError = !checker.validateLifetime( - baseObject, endScopeInsts, liveRange.getAllConsumingUses()); - return answer(foundError); - } - - // TODO: Handle other access kinds? - void visitBase(SILValue base, AccessedStorage::Kind kind) { - return answer(true); - } - - void visitNonAccess(SILValue addr) { - return answer(true); - } - - void visitCast(SingleValueInstruction *cast, Operand *parentAddr) { - return next(parentAddr->get()); - } - - void visitPathComponent(SingleValueInstruction *projectedAddr, - Operand *parentAddr) { - return next(parentAddr->get()); - } - - void visitPhi(SILPhiArgument *phi) { - // We shouldn't have address phis in OSSA SIL, so we don't need to recur - // through the predecessors here. - return answer(true); - } - - /// See if we have an alloc_stack that is only written to once by an - /// initializing instruction. - void visitStackAccess(AllocStackInst *stack) { - SmallVector destroyAddrOperands; - bool initialAnswer = isSingleInitAllocStack(stack, destroyAddrOperands); - if (!initialAnswer) - return answer(true); - - // Then make sure that all of our load [copy] uses are within the - // destroy_addr. - SmallPtrSet visitedBlocks; - LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); - // Returns true on success. So we invert. - bool foundError = !checker.validateLifetime( - stack, destroyAddrOperands /*consuming users*/, - liveRange.getAllConsumingUses() /*non consuming users*/); - return answer(foundError); - } - - bool doIt() { - while (currentAddress) { - visit(currentAddress); - } - return *isWritten; - } -}; - -} // namespace - -bool SemanticARCOptVisitor::isWrittenTo(LoadInst *load, - const OwnershipLiveRange &lr) { - StorageGuaranteesLoadVisitor visitor(*this, load, lr); - return visitor.doIt(); -} - -// Convert a load [copy] from unique storage [read] that has all uses that can -// accept a guaranteed parameter to a load_borrow. -bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) { - // This optimization can use more complex analysis. We should do some - // experiments before enabling this by default as a guaranteed optimization. - if (onlyGuaranteedOpts) - return false; - - if (li->getOwnershipQualifier() != LoadOwnershipQualifier::Copy) - return false; - - // Ok, we have our load [copy]. Make sure its value is truly a dead live range - // implying it is only ever consumed by destroy_value instructions. If it is - // consumed, we need to pass off a +1 value, so bail. - // - // FIXME: We should consider if it is worth promoting a load [copy] - // -> load_borrow if we can put a copy_value on a cold path and thus - // eliminate RR traffic on a hot path. - OwnershipLiveRange lr(li); - if (bool(lr.hasUnknownConsumingUse())) - return false; - - // Then check if our address is ever written to. If it is, then we cannot use - // the load_borrow because the stored value may be released during the loaded - // value's live range. - if (isWrittenTo(li, lr)) - return false; - - // Ok, we can perform our optimization. Convert the load [copy] into a - // load_borrow. - auto *lbi = - SILBuilderWithScope(li).createLoadBorrow(li->getLoc(), li->getOperand()); - - lr.insertEndBorrowsAtDestroys(lbi, getDeadEndBlocks(), lifetimeFrontier); - std::move(lr).convertToGuaranteedAndRAUW(lbi, getCallbacks()); - ++NumEliminatedInsts; - ++NumLoadCopyConvertedToLoadBorrow; - return true; -} - -//===----------------------------------------------------------------------===// -// Top Level Entrypoint -//===----------------------------------------------------------------------===// - -namespace { - -// Even though this is a mandatory pass, it is rerun after deserialization in -// case DiagnosticConstantPropagation exposed anything new in this assert -// configuration. -struct SemanticARCOpts : SILFunctionTransform { - bool guaranteedOptsOnly; - - SemanticARCOpts(bool guaranteedOptsOnly) - : guaranteedOptsOnly(guaranteedOptsOnly) {} - - void run() override { - SILFunction &f = *getFunction(); - - // Return early if we are not performing OSSA optimizations. - if (!f.getModule().getOptions().EnableOSSAOptimizations) - return; - - // Make sure we are running with ownership verification enabled. - assert(f.getModule().getOptions().VerifySILOwnership && - "Can not perform semantic arc optimization unless ownership " - "verification is enabled"); - - SemanticARCOptVisitor visitor(f, guaranteedOptsOnly); - - // Add all the results of all instructions that we want to visit to the - // worklist. - for (auto &block : f) { - for (auto &inst : block) { - if (SemanticARCOptVisitor::shouldVisitInst(&inst)) { - for (SILValue v : inst.getResults()) { - visitor.worklist.insert(v); - } - } - } - } - - // Then process the worklist. We only destroy instructions, so invalidate - // that. Once we modify the ownership of block arguments, we will need to - // perhaps invalidate branches as well. - if (visitor.optimize()) { - invalidateAnalysis( - SILAnalysis::InvalidationKind::BranchesAndInstructions); - } - } -}; - -} // end anonymous namespace - -SILTransform *swift::createSemanticARCOpts() { - return new SemanticARCOpts(false /*guaranteed*/); -} - -SILTransform *swift::createGuaranteedARCOpts() { - return new SemanticARCOpts(true /*guaranteed*/); -} diff --git a/lib/SILOptimizer/Transforms/StringOptimization.cpp b/lib/SILOptimizer/Transforms/StringOptimization.cpp index aa737a26497b5..10c5cfd464456 100644 --- a/lib/SILOptimizer/Transforms/StringOptimization.cpp +++ b/lib/SILOptimizer/Transforms/StringOptimization.cpp @@ -198,7 +198,7 @@ bool StringOptimization::optimizeStringAppend(ApplyInst *appendCall, // Replace lhs.append(rhs) with "lhs = lhs + rhs" if both lhs and rhs are // constant. if (lhsString.isConstant() && rhsString.isConstant()) { - std::string concat = lhsString.str; + std::string concat = lhsString.str.str(); concat += rhsString.str; if (ApplyInst *stringInit = createStringInit(concat, appendCall)) { replaceAppendWith(appendCall, stringInit); @@ -235,7 +235,7 @@ bool StringOptimization::optimizeStringConcat(ApplyInst *concatCall) { // Replace lhs + rhs with "lhs + rhs" if both lhs and rhs are constant. if (lhsString.isConstant() && rhsString.isConstant()) { - std::string concat = lhsString.str; + std::string concat = lhsString.str.str(); concat += rhsString.str; if (ApplyInst *stringInit = createStringInit(concat, concatCall)) { concatCall->replaceAllUsesWith(stringInit); diff --git a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp index a8f823e584d5a..9ef7e2d70befd 100644 --- a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp +++ b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp @@ -86,7 +86,8 @@ class BugReducerTester : public SILFunctionTransform { nullptr, SILFunctionType::ExtInfoBuilder( SILFunctionType::Representation::Thin, false /*isPseudoGeneric*/, - false /*noescape*/, DifferentiabilityKind::NonDifferentiable, + false /*noescape*/, false /*async*/, + DifferentiabilityKind::NonDifferentiable, nullptr /*clangFunctionType*/) .build(), SILCoroutineKind::None, ParameterConvention::Direct_Unowned, diff --git a/lib/SILOptimizer/Utils/CastOptimizer.cpp b/lib/SILOptimizer/Utils/CastOptimizer.cpp index c1c5da4bc3fdc..3a15d568afc0a 100644 --- a/lib/SILOptimizer/Utils/CastOptimizer.cpp +++ b/lib/SILOptimizer/Utils/CastOptimizer.cpp @@ -918,25 +918,32 @@ SILInstruction *CastOptimizer::simplifyCheckedCastAddrBranchInst( return nullptr; } - // For CopyOnSuccess casts, we could insert an explicit copy here, but this - // case does not happen in practice. - // // Both TakeOnSuccess and TakeAlways can be reduced to an // UnconditionalCheckedCast, since the failure path is irrelevant. + AllocStackInst *copiedSrc = nullptr; switch (Inst->getConsumptionKind()) { case CastConsumptionKind::BorrowAlways: llvm_unreachable("checked_cast_addr_br never has BorrowAlways"); case CastConsumptionKind::CopyOnSuccess: - return nullptr; + if (!Src->getType().isTrivial(*BB->getParent())) { + copiedSrc = Builder.createAllocStack(Loc, Src->getType()); + Builder.createCopyAddr(Loc, Src, copiedSrc, IsNotTake, IsInitialization); + Src = copiedSrc; + } + break; case CastConsumptionKind::TakeAlways: case CastConsumptionKind::TakeOnSuccess: break; } - if (!emitSuccessfulIndirectUnconditionalCast(Builder, Loc, dynamicCast)) { - // No optimization was possible. - return nullptr; - } + bool result = emitSuccessfulIndirectUnconditionalCast( + Builder, Builder.getModule().getSwiftModule(), Loc, Src, + Inst->getSourceFormalType(), Dest, Inst->getTargetFormalType(), Inst); + (void)result; + assert(result && "emit cannot fail for an checked_cast_addr_br"); + + if (copiedSrc) + Builder.createDeallocStack(Loc, copiedSrc); eraseInstAction(Inst); } SILInstruction *NewI = &BB->back(); diff --git a/lib/SILOptimizer/Utils/Existential.cpp b/lib/SILOptimizer/Utils/Existential.cpp index 9092171488767..3aa840b7a3a03 100644 --- a/lib/SILOptimizer/Utils/Existential.cpp +++ b/lib/SILOptimizer/Utils/Existential.cpp @@ -433,3 +433,40 @@ ConcreteOpenedExistentialInfo::ConcreteOpenedExistentialInfo( } CEI->isConcreteValueCopied |= OAI.isOpenedValueCopied; } + +void LLVM_ATTRIBUTE_USED OpenedArchetypeInfo::dump() const { + if (!isValid()) { + llvm::dbgs() << "invalid OpenedArchetypeInfo\n"; + return; + } + llvm::dbgs() << "OpendArchetype: "; + OpenedArchetype->dump(llvm::dbgs()); + llvm::dbgs() << "OpendArchetypeValue: "; + OpenedArchetypeValue->dump(); + llvm::dbgs() << (isOpenedValueCopied ? "copied " : "") << "ExistentialValue: "; + ExistentialValue->dump(); +} + +void LLVM_ATTRIBUTE_USED ConcreteExistentialInfo::dump() const { + llvm::dbgs() << "ExistentialType: "; + ExistentialType->dump(llvm::dbgs()); + llvm::dbgs() << "ConcreteType: "; + ConcreteType->dump(llvm::dbgs()); + llvm::dbgs() << (isConcreteValueCopied ? "copied " : "") << "ConcreteValue: "; + ConcreteValue->dump(); + if (ConcreteTypeDef) { + llvm::dbgs() << "ConcreteTypeDef: "; + ConcreteTypeDef->dump(); + } + ExistentialSubs.dump(llvm::dbgs()); + llvm::dbgs() << '\n'; +} + +void LLVM_ATTRIBUTE_USED ConcreteOpenedExistentialInfo::dump() const { + OAI.dump(); + if (CEI) { + CEI->dump(); + } else { + llvm::dbgs() << "no ConcreteExistentialInfo\n"; + } +} diff --git a/lib/SILOptimizer/Utils/InstOptUtils.cpp b/lib/SILOptimizer/Utils/InstOptUtils.cpp index 312c15d6e6984..19ce86358904c 100644 --- a/lib/SILOptimizer/Utils/InstOptUtils.cpp +++ b/lib/SILOptimizer/Utils/InstOptUtils.cpp @@ -48,6 +48,27 @@ static llvm::cl::opt KeepWillThrowCall( llvm::cl::desc( "Keep calls to swift_willThrow, even if the throw is optimized away")); +// Defined here to avoid repeatedly paying the price of template instantiation. +const std::function + InstModCallbacks::defaultDeleteInst + = [](SILInstruction *inst) { + inst->eraseFromParent(); + }; +const std::function + InstModCallbacks::defaultCreatedNewInst + = [](SILInstruction *) {}; +const std::function + InstModCallbacks::defaultReplaceValueUsesWith + = [](SILValue oldValue, SILValue newValue) { + oldValue->replaceAllUsesWith(newValue); + }; +const std::function + InstModCallbacks::defaultEraseAndRAUWSingleValueInst + = [](SingleValueInstruction *i, SILValue newValue) { + i->replaceAllUsesWith(newValue); + i->eraseFromParent(); + }; + /// Creates an increment on \p Ptr before insertion point \p InsertPt that /// creates a strong_retain if \p Ptr has reference semantics itself or a /// retain_value if \p Ptr is a non-trivial value without reference-semantics. diff --git a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp index 21f4bc6f5a24c..f8bcce57b36d7 100644 --- a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp +++ b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp @@ -622,14 +622,20 @@ static bool isCallerAndCalleeLayoutConstraintsCompatible(FullApplySite AI) { // The generic parameter has a layout constraint. // Check that the substitution has the same constraint. auto AIReplacement = Type(Param).subst(AISubs); - auto AIArchetype = AIReplacement->getAs(); - if (!AIArchetype) - return false; - auto AILayout = AIArchetype->getLayoutConstraint(); - if (!AILayout) - return false; - if (AILayout != Layout) - return false; + + if (Layout->isClass()) { + if (!AIReplacement->satisfiesClassConstraint()) + return false; + } else { + auto AIArchetype = AIReplacement->getAs(); + if (!AIArchetype) + return false; + auto AILayout = AIArchetype->getLayoutConstraint(); + if (!AILayout) + return false; + if (AILayout != Layout) + return false; + } } return true; } diff --git a/lib/SILOptimizer/Utils/ValueLifetime.cpp b/lib/SILOptimizer/Utils/ValueLifetime.cpp index 5fc8b0228b62b..4f90e9cc0bd80 100644 --- a/lib/SILOptimizer/Utils/ValueLifetime.cpp +++ b/lib/SILOptimizer/Utils/ValueLifetime.cpp @@ -11,17 +11,23 @@ //===----------------------------------------------------------------------===// #include "swift/SILOptimizer/Utils/ValueLifetime.h" +#include "swift/Basic/STLExtras.h" #include "swift/SIL/BasicBlockUtils.h" #include "swift/SILOptimizer/Utils/CFGOptUtils.h" using namespace swift; void ValueLifetimeAnalysis::propagateLiveness() { + bool defIsInstruction = defValue.is(); assert(liveBlocks.empty() && "frontier computed twice"); - assert(!userSet.count(defValue) && "definition cannot be its own use"); + assert( + (!defIsInstruction || !userSet.count(defValue.get())) && + "definition cannot be its own use"); - auto defBB = defValue->getParentBlock(); - llvm::SmallVector worklist; + // Compute the def block only if we have a SILInstruction. If we have a + // SILArgument, this will be nullptr. + auto *defBB = getDefValueParentBlock(); + SmallVector worklist; int numUsersBeforeDef = 0; // Find the initial set of blocks where the value is live, because @@ -31,20 +37,28 @@ void ValueLifetimeAnalysis::propagateLiveness() { if (liveBlocks.insert(userBlock)) worklist.push_back(userBlock); - // A user in the defBB could potentially be located before the defValue. - if (userBlock == defBB) + // A user in the defBB could potentially be located before the defValue. If + // we had a SILArgument, defBB will be nullptr, so we should always have + // numUsersBeforeDef is 0. We assert this at the end of the loop. + if (defIsInstruction && userBlock == defBB) ++numUsersBeforeDef; } - // Don't count any users in the defBB which are actually located _after_ - // the defValue. - auto instIter = defValue->getIterator(); - while (numUsersBeforeDef > 0 && ++instIter != defBB->end()) { - if (userSet.count(&*instIter)) - --numUsersBeforeDef; + assert((defValue.is() || (numUsersBeforeDef == 0)) && + "Non SILInstruction defValue with users before the def?!"); + + // Don't count any users in the defBB which are actually located _after_ the + // defValue. + if (defIsInstruction) { + auto instIter = defValue.get()->getIterator(); + while (numUsersBeforeDef > 0 && ++instIter != defBB->end()) { + if (userSet.count(&*instIter)) + --numUsersBeforeDef; + } } // Initialize the hasUsersBeforeDef field. hasUsersBeforeDef = numUsersBeforeDef > 0; + assert(defIsInstruction || !hasUsersBeforeDef); // Now propagate liveness backwards until we hit the block that defines the // value. @@ -55,30 +69,31 @@ void ValueLifetimeAnalysis::propagateLiveness() { if (bb == defBB && !hasUsersBeforeDef) continue; - for (SILBasicBlock *Pred : bb->getPredecessorBlocks()) { + for (auto *predBB : bb->getPredecessorBlocks()) { // If it's already in the set, then we've already queued and/or // processed the predecessors. - if (liveBlocks.insert(Pred)) - worklist.push_back(Pred); + if (liveBlocks.insert(predBB)) + worklist.push_back(predBB); } } } SILInstruction *ValueLifetimeAnalysis::findLastUserInBlock(SILBasicBlock *bb) { // Walk backwards in bb looking for last use of the value. - for (auto ii = bb->rbegin(); ii != bb->rend(); ++ii) { - assert(defValue != &*ii && "Found def before finding use!"); + for (auto &inst : llvm::reverse(*bb)) { + assert(defValue.dyn_cast() != &inst && + "Found def before finding use!"); - if (userSet.count(&*ii)) - return &*ii; + if (userSet.count(&inst)) + return &inst; } llvm_unreachable("Expected to find use of value in block!"); } bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode, DeadEndBlocks *deBlocks) { - assert(!isAliveAtBeginOfBlock(defValue->getFunction()->getEntryBlock()) - && "Can't compute frontier for def which does not dominate all uses"); + assert(!isAliveAtBeginOfBlock(getFunction()->getEntryBlock()) && + "Can't compute frontier for def which does not dominate all uses"); bool noCriticalEdges = true; @@ -101,10 +116,16 @@ bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode, for (const SILSuccessor &succ : bb->getSuccessors()) { if (isAliveAtBeginOfBlock(succ)) { liveInSucc = true; - if (succ == defValue->getParent()) { + if (succ == getDefValueParentBlock()) { // Here, the basic block bb uses the value but also redefines the // value inside bb. The new value could be used by the successors // of succ and therefore could be live at the end of succ as well. + // + // This should never happen if we have a SILArgument since the + // SILArgument can not have any uses before it in a block. + assert(defValue.is() && + "SILArguments dominate all instructions in their defining " + "blocks"); usedAndRedefinedInSucc = true; } } else if (!deBlocks || !deBlocks->isDeadEnd(succ)) { @@ -115,7 +136,10 @@ bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode, // Here, the basic block bb uses the value and later redefines the value. // Therefore, this value's lifetime ends after its last use preceding the // re-definition of the value. - auto ii = defValue->getReverseIterator(); + // + // We know that we can not have a SILArgument here since the SILArgument + // dominates all instructions in the same block. + auto ii = defValue.get()->getReverseIterator(); for (; ii != bb->rend(); ++ii) { if (userSet.count(&*ii)) { frontier.push_back(&*std::next(ii)); @@ -245,15 +269,19 @@ bool ValueLifetimeAnalysis::isWithinLifetime(SILInstruction *inst) { // Searches \p bb backwards from the instruction before \p frontierInst // to the beginning of the list and returns true if we find a dealloc_ref // /before/ we find \p defValue (the instruction that defines our target value). -static bool blockContainsDeallocRef(SILBasicBlock *bb, SILInstruction *defValue, - SILInstruction *frontierInst) { +static bool +blockContainsDeallocRef(SILBasicBlock *bb, + PointerUnion defValue, + SILInstruction *frontierInst) { SILBasicBlock::reverse_iterator End = bb->rend(); SILBasicBlock::reverse_iterator iter = frontierInst->getReverseIterator(); for (++iter; iter != End; ++iter) { SILInstruction *inst = &*iter; if (isa(inst)) return true; - if (inst == defValue) + // We know that inst is not a nullptr, so if we have a SILArgument, this + // will always fail as we want. + if (inst == defValue.dyn_cast()) return false; } return false; @@ -281,9 +309,14 @@ bool ValueLifetimeAnalysis::containsDeallocRef(const Frontier &frontier) { } void ValueLifetimeAnalysis::dump() const { - llvm::errs() << "lifetime of def: " << *defValue; - for (SILInstruction *Use : userSet) { - llvm::errs() << " use: " << *Use; + llvm::errs() << "lifetime of def: "; + if (auto *ii = defValue.dyn_cast()) { + llvm::errs() << *ii; + } else { + llvm::errs() << *defValue.get(); + } + for (SILInstruction *use : userSet) { + llvm::errs() << " use: " << *use; } llvm::errs() << " live blocks:"; for (SILBasicBlock *bb : liveBlocks) { diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 4c976d26a0f1d..4ae60b1194ba8 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -145,28 +145,8 @@ class BuilderClosureVisitor return known->second; } - bool found = false; - for (auto decl : builder->lookupDirect(fnName)) { - if (auto func = dyn_cast(decl)) { - // Function must be static. - if (!func->isStatic()) - continue; - - // Function must have the right argument labels, if provided. - if (!argLabels.empty()) { - auto funcLabels = func->getName().getArgumentNames(); - if (argLabels.size() > funcLabels.size() || - funcLabels.slice(0, argLabels.size()) != argLabels) - continue; - } - - // Okay, it's a good-enough match. - found = true; - break; - } - } - - return supportedOps[fnName] = found; + return supportedOps[fnName] = TypeChecker::typeSupportsBuilderOp( + builderType, dc, fnName, argLabels); } /// Build an implicit variable in this context. @@ -306,10 +286,6 @@ class BuilderClosureVisitor } VarDecl *visitBraceStmt(BraceStmt *braceStmt) { - return visitBraceStmt(braceStmt, ctx.Id_buildBlock); - } - - VarDecl *visitBraceStmt(BraceStmt *braceStmt, Identifier builderFunction) { SmallVector expressions; auto addChild = [&](VarDecl *childVar) { if (!childVar) @@ -376,7 +352,7 @@ class BuilderClosureVisitor // Call Builder.buildBlock(... args ...) auto call = buildCallIfWanted(braceStmt->getStartLoc(), - builderFunction, expressions, + ctx.Id_buildBlock, expressions, /*argLabels=*/{ }); if (!call) return nullptr; @@ -391,13 +367,7 @@ class BuilderClosureVisitor } VarDecl *visitDoStmt(DoStmt *doStmt) { - if (!builderSupports(ctx.Id_buildDo)) { - if (!unhandledNode) - unhandledNode = doStmt; - return nullptr; - } - - auto childVar = visitBraceStmt(doStmt->getBody(), ctx.Id_buildDo); + auto childVar = visitBraceStmt(doStmt->getBody()); if (!childVar) return nullptr; @@ -902,6 +872,26 @@ class BuilderClosureVisitor return finalForEachVar; } + /// Visit a throw statement, which never produces a result. + VarDecl *visitThrowStmt(ThrowStmt *throwStmt) { + Type exnType = ctx.getErrorDecl()->getDeclaredInterfaceType(); + if (!exnType) { + hadError = true; + } + + if (cs) { + SolutionApplicationTarget target( + throwStmt->getSubExpr(), dc, CTP_ThrowStmt, exnType, + /*isDiscarded=*/false); + if (cs->generateConstraints(target, FreeTypeVariableBinding::Disallow)) + hadError = true; + + cs->setSolutionApplicationTarget(throwStmt, target); + } + + return nullptr; + } + CONTROL_FLOW_STMT(Guard) CONTROL_FLOW_STMT(While) CONTROL_FLOW_STMT(DoCatch) @@ -911,7 +901,6 @@ class BuilderClosureVisitor CONTROL_FLOW_STMT(Continue) CONTROL_FLOW_STMT(Fallthrough) CONTROL_FLOW_STMT(Fail) - CONTROL_FLOW_STMT(Throw) CONTROL_FLOW_STMT(PoundAssert) #undef CONTROL_FLOW_STMT @@ -1147,6 +1136,14 @@ class BuilderClosureRewriter } if (auto stmt = node.dyn_cast()) { + // "throw" statements produce no value. Transform them directly. + if (auto throwStmt = dyn_cast(stmt)) { + if (auto newStmt = visitThrowStmt(throwStmt)) { + newElements.push_back(stmt); + } + continue; + } + // Each statement turns into a (potential) temporary variable // binding followed by the statement itself. auto captured = takeCapturedStmt(stmt); @@ -1435,6 +1432,22 @@ class BuilderClosureRewriter ctx, forEachStmt->getStartLoc(), outerBodySteps, newBody->getEndLoc()); } + Stmt *visitThrowStmt(ThrowStmt *throwStmt) { + // Rewrite the error. + auto target = *solution.getConstraintSystem() + .getSolutionApplicationTarget(throwStmt); + if (auto result = rewriteTarget(target)) + throwStmt->setSubExpr(result->getAsExpr()); + else + return nullptr; + + return throwStmt; + } + + Stmt *visitThrowStmt(ThrowStmt *throwStmt, FunctionBuilderTarget target) { + llvm_unreachable("Throw statements produce no value"); + } + #define UNHANDLED_FUNCTION_BUILDER_STMT(STMT) \ Stmt *visit##STMT##Stmt(STMT##Stmt *stmt, FunctionBuilderTarget target) { \ llvm_unreachable("Function builders do not allow statement of kind " \ @@ -1452,7 +1465,6 @@ class BuilderClosureRewriter UNHANDLED_FUNCTION_BUILDER_STMT(Continue) UNHANDLED_FUNCTION_BUILDER_STMT(Fallthrough) UNHANDLED_FUNCTION_BUILDER_STMT(Fail) - UNHANDLED_FUNCTION_BUILDER_STMT(Throw) UNHANDLED_FUNCTION_BUILDER_STMT(PoundAssert) #undef UNHANDLED_FUNCTION_BUILDER_STMT }; @@ -1485,9 +1497,11 @@ Optional TypeChecker::applyFunctionBuilderBodyTransform( // If we encountered an error or there was an explicit result type, // bail out and report that to the caller. auto &ctx = func->getASTContext(); - auto request = PreCheckFunctionBuilderRequest{AnyFunctionRef(func)}; - switch (evaluateOrDefault( - ctx.evaluator, request, FunctionBuilderBodyPreCheck::Error)) { + auto request = + PreCheckFunctionBuilderRequest{{AnyFunctionRef(func), + /*SuppressDiagnostics=*/false}}; + switch (evaluateOrDefault(ctx.evaluator, request, + FunctionBuilderBodyPreCheck::Error)) { case FunctionBuilderBodyPreCheck::Okay: // If the pre-check was okay, apply the function-builder transform. break; @@ -1617,18 +1631,33 @@ ConstraintSystem::matchFunctionBuilder( assert(builder && "Bad function builder type"); assert(builder->getAttrs().hasAttribute()); + if (InvalidFunctionBuilderBodies.count(fn)) { + (void)recordFix( + IgnoreInvalidFunctionBuilderBody::duringConstraintGeneration( + *this, getConstraintLocator(fn.getBody()))); + return getTypeMatchSuccess(); + } + // Pre-check the body: pre-check any expressions in it and look // for return statements. - auto request = PreCheckFunctionBuilderRequest{fn}; + auto request = + PreCheckFunctionBuilderRequest{{fn, /*SuppressDiagnostics=*/true}}; switch (evaluateOrDefault(getASTContext().evaluator, request, FunctionBuilderBodyPreCheck::Error)) { case FunctionBuilderBodyPreCheck::Okay: // If the pre-check was okay, apply the function-builder transform. break; - case FunctionBuilderBodyPreCheck::Error: - // If the pre-check had an error, flag that. - return getTypeMatchFailure(locator); + case FunctionBuilderBodyPreCheck::Error: { + if (!shouldAttemptFixes()) + return getTypeMatchFailure(locator); + + if (recordFix(IgnoreInvalidFunctionBuilderBody::duringPreCheck( + *this, getConstraintLocator(fn.getBody())))) + return getTypeMatchFailure(locator); + + return getTypeMatchSuccess(); + } case FunctionBuilderBodyPreCheck::HasReturnStmt: // If the body has a return statement, suppress the transform but @@ -1665,9 +1694,25 @@ ConstraintSystem::matchFunctionBuilder( BuilderClosureVisitor visitor(getASTContext(), this, dc, builderType, bodyResultType); - auto applied = visitor.apply(fn.getBody()); - if (!applied) - return getTypeMatchFailure(locator); + Optional applied = None; + { + DiagnosticTransaction transaction(dc->getASTContext().Diags); + + applied = visitor.apply(fn.getBody()); + if (!applied) + return getTypeMatchFailure(locator); + + if (transaction.hasErrors()) { + InvalidFunctionBuilderBodies.insert(fn); + + if (recordFix( + IgnoreInvalidFunctionBuilderBody::duringConstraintGeneration( + *this, getConstraintLocator(fn.getBody())))) + return getTypeMatchFailure(locator); + + return getTypeMatchSuccess(); + } + } Type transformedType = getType(applied->returnExpr); assert(transformedType && "Missing type"); @@ -1705,14 +1750,17 @@ namespace { class PreCheckFunctionBuilderApplication : public ASTWalker { AnyFunctionRef Fn; bool SkipPrecheck = false; + bool SuppressDiagnostics = false; std::vector ReturnStmts; bool HasError = false; bool hasReturnStmt() const { return !ReturnStmts.empty(); } public: - PreCheckFunctionBuilderApplication(AnyFunctionRef fn, bool skipPrecheck) - : Fn(fn), SkipPrecheck(skipPrecheck) {} + PreCheckFunctionBuilderApplication(AnyFunctionRef fn, bool skipPrecheck, + bool suppressDiagnostics) + : Fn(fn), SkipPrecheck(skipPrecheck), + SuppressDiagnostics(suppressDiagnostics) {} const std::vector getReturnStmts() const { return ReturnStmts; } @@ -1736,16 +1784,28 @@ class PreCheckFunctionBuilderApplication : public ASTWalker { } std::pair walkToExprPre(Expr *E) override { + if (SkipPrecheck) + return std::make_pair(false, E); + // Pre-check the expression. If this fails, abort the walk immediately. // Otherwise, replace the expression with the result of pre-checking. // In either case, don't recurse into the expression. - if (!SkipPrecheck && - ConstraintSystem::preCheckExpression(E, /*DC*/ Fn.getAsDeclContext())) { - HasError = true; - return std::make_pair(false, nullptr); - } + { + auto *DC = Fn.getAsDeclContext(); + auto &diagEngine = DC->getASTContext().Diags; - return std::make_pair(false, E); + // Suppress any diangostics which could be produced by this expression. + DiagnosticTransaction transaction(diagEngine); + + HasError |= ConstraintSystem::preCheckExpression( + E, DC, /*replaceInvalidRefsWithErrors=*/false); + HasError |= transaction.hasErrors(); + + if (SuppressDiagnostics) + transaction.abort(); + + return std::make_pair(false, HasError ? nullptr : E); + } } std::pair walkToStmtPre(Stmt *S) override { @@ -1778,11 +1838,49 @@ FunctionBuilderBodyPreCheck PreCheckFunctionBuilderRequest::evaluate( owner.Fn.getAbstractClosureExpr())) skipPrecheck = shouldTypeCheckInEnclosingExpression(closure); - return PreCheckFunctionBuilderApplication(owner.Fn, false).run(); + return PreCheckFunctionBuilderApplication( + owner.Fn, /*skipPrecheck=*/false, + /*suppressDiagnostics=*/owner.SuppressDiagnostics) + .run(); } std::vector TypeChecker::findReturnStatements(AnyFunctionRef fn) { - PreCheckFunctionBuilderApplication precheck(fn, true); + PreCheckFunctionBuilderApplication precheck(fn, /*skipPreCheck=*/true, + /*SuppressDiagnostics=*/true); (void)precheck.run(); return precheck.getReturnStmts(); } + +bool TypeChecker::typeSupportsBuilderOp( + Type builderType, DeclContext *dc, Identifier fnName, + ArrayRef argLabels, SmallVectorImpl *allResults) { + bool foundMatch = false; + SmallVector foundDecls; + dc->lookupQualified( + builderType, DeclNameRef(fnName), + NL_QualifiedDefault | NL_ProtocolMembers, foundDecls); + for (auto decl : foundDecls) { + if (auto func = dyn_cast(decl)) { + // Function must be static. + if (!func->isStatic()) + continue; + + // Function must have the right argument labels, if provided. + if (!argLabels.empty()) { + auto funcLabels = func->getName().getArgumentNames(); + if (argLabels.size() > funcLabels.size() || + funcLabels.slice(0, argLabels.size()) != argLabels) + continue; + } + + foundMatch = true; + break; + } + } + + if (allResults) + allResults->append(foundDecls.begin(), foundDecls.end()); + + return foundMatch; +} + diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 3c0e373e81c6b..d35c849fb435f 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -41,12 +41,13 @@ add_swift_host_library(swiftSema STATIC TypeCheckCaptures.cpp TypeCheckCircularity.cpp TypeCheckCodeCompletion.cpp + TypeCheckConcurrency.cpp TypeCheckConstraints.cpp TypeCheckDecl.cpp TypeCheckDeclObjC.cpp TypeCheckDeclOverride.cpp TypeCheckDeclPrimary.cpp - TypeCheckError.cpp + TypeCheckEffects.cpp TypeCheckExpr.cpp TypeCheckExprObjC.cpp TypeCheckGeneric.cpp diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index c5715942de0c6..831add9e6c599 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -176,12 +176,46 @@ bool ConstraintSystem::isTypeReference(Expr *E) { }); } +bool Solution::isTypeReference(Expr *E) const { + return E->isTypeReference( + [&](Expr *expr) -> Type { return simplifyType(getType(expr)); }, + [&](Expr *expr) -> Decl * { + ConstraintLocator *locator = nullptr; + if (auto *UDE = dyn_cast(E)) { + locator = getConstraintLocator(UDE, {ConstraintLocator::Member}); + } + + if (auto *UME = dyn_cast(E)) { + locator = + getConstraintLocator(UME, {ConstraintLocator::UnresolvedMember}); + } + + if (isa(E)) + locator = getConstraintLocator(const_cast(E)); + + if (locator) { + if (auto selectedOverload = getOverloadChoiceIfAvailable(locator)) { + const auto &choice = selectedOverload->choice; + return choice.getDeclOrNull(); + } + } + + return nullptr; + }); +} + bool ConstraintSystem::isStaticallyDerivedMetatype(Expr *E) { return E->isStaticallyDerivedMetatype( [&](Expr *E) -> Type { return simplifyType(getType(E)); }, [&](Expr *E) -> bool { return isTypeReference(E); }); } +bool Solution::isStaticallyDerivedMetatype(Expr *E) const { + return E->isStaticallyDerivedMetatype( + [&](Expr *E) -> Type { return simplifyType(getType(E)); }, + [&](Expr *E) -> bool { return isTypeReference(E); }); +} + Type ConstraintSystem::getInstanceType(TypeExpr *E) { if (!hasType(E)) return Type(); @@ -364,6 +398,26 @@ namespace { return base.getOldType(); } + /// Check whether it is possible to have an ObjC key path string for the keypath expression + /// and set the key path string, if yes + void checkAndSetObjCKeyPathString(KeyPathExpr *keyPath) { + if (cs.getASTContext().LangOpts.EnableObjCInterop) { + SmallString<64> compatStringBuf; + if (buildObjCKeyPathString(keyPath, compatStringBuf)) { + auto stringCopy = cs.getASTContext().AllocateCopy(compatStringBuf.begin(), + compatStringBuf.end()); + auto stringExpr = new (cs.getASTContext()) StringLiteralExpr( + StringRef(stringCopy, compatStringBuf.size()), + SourceRange(), + /*implicit*/ true); + cs.setType( + stringExpr, + cs.getASTContext().getStringDecl()->getDeclaredInterfaceType()); + keyPath->setObjCStringLiteralExpr(stringExpr); + } + } + } + // Returns None if the AST does not contain enough information to recover // substitutions; this is different from an Optional(SubstitutionMap()), // indicating a valid call to a non-generic operator. @@ -806,12 +860,9 @@ namespace { } // Similarly, ".foo(...)" really applies two argument lists. - if (auto *unresolvedMemberExpr = dyn_cast(prev)) { - if (unresolvedMemberExpr->hasArguments() || - unresolvedMemberExpr->hasTrailingClosure()) - return 2; - return 1; - } + if (isa(prev) && + isa(cast(prev)->getFn())) + return 2; return getArgCount(maxArgCount); }(); @@ -2007,6 +2058,11 @@ namespace { keyPath->setParsedPath(componentExpr); keyPath->resolveComponents(ctx, components); cs.cacheExprTypes(keyPath); + + // See whether there's an equivalent ObjC key path string we can produce + // for interop purposes. + checkAndSetObjCKeyPathString(keyPath); + return keyPath; } @@ -2694,31 +2750,25 @@ namespace { } Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { - // 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. + // 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(cs.getType(expr)); if (resultTy->hasUnresolvedType()) { cs.setType(expr, resultTy); return expr; } - Type baseTy = resultTy->getRValueType(); auto &ctx = cs.getASTContext(); - - // Find the selected member. + // Find the selected member and base type. auto memberLocator = cs.getConstraintLocator( expr, ConstraintLocator::UnresolvedMember); auto selected = solution.getOverloadChoice(memberLocator); - - // If the member came by optional unwrapping, then unwrap the base type. - if (selected.choice.getKind() - == OverloadChoiceKind::DeclViaUnwrappedOptional) { - baseTy = baseTy->getOptionalObjectType(); - assert(baseTy - && "got unwrapped optional decl from non-optional base?!"); - } + + // Unresolved member lookup always happens in a metatype so dig out the + // instance type. + auto baseTy = selected.choice.getBaseType()->getMetatypeInstanceType(); + baseTy = simplifyType(baseTy); // The base expression is simply the metatype of the base type. // FIXME: This location info is bogus. @@ -2733,30 +2783,6 @@ namespace { if (!result) return nullptr; - auto getType = [&](Expr *E) -> Type { return cs.getType(E); }; - - // If there was an argument, apply it. - if (auto arg = expr->getArgument()) { - // Get the callee locator. Note this may be different to the locator for - // the member being referenced for things like callAsFunction. - auto *calleeLoc = cs.getCalleeLocator(exprLoc); - - // Build and finish the apply. - ApplyExpr *apply = CallExpr::create( - ctx, result, arg, expr->getArgumentLabels(), - expr->getArgumentLabelLocs(), expr->hasTrailingClosure(), - /*implicit=*/expr->isImplicit(), Type(), getType); - result = finishApply(apply, Type(), exprLoc, calleeLoc); - - // FIXME: Application could fail, because some of the solutions - // are not expressible in AST (yet?), like certain tuple-to-tuple - // conversions. Better solution here would be not to form solutions - // which couldn't be applied by e.g. detecting situations like that - // and inserting fixes early. - if (!result) - return nullptr; - } - // Check for ambiguous member if the base is an Optional if (baseTy->getOptionalObjectType()) { diagnoseAmbiguousNominalMember(baseTy, result); @@ -3217,6 +3243,19 @@ namespace { return simplifyExprType(expr); } + Expr *visitUnresolvedMemberChainResultExpr( + UnresolvedMemberChainResultExpr *expr) { + // Since this expression only exists to give the result type of an + // unresolved member chain visibility in the AST, remove it from the AST + // now that we have a solution and coerce the subexpr to the resulting + // type. + auto *subExpr = expr->getSubExpr(); + auto type = simplifyType(cs.getType(expr)); + subExpr = coerceToType(subExpr, type, cs.getConstraintLocator(subExpr)); + cs.setType(subExpr, type); + return subExpr; + } + Expr *visitTupleExpr(TupleExpr *expr) { return simplifyExprType(expr); } @@ -3751,17 +3790,14 @@ namespace { }; // There's nothing special to do if the operand isn't optional - // and we don't need any bridging. - if (srcOptionals.empty()) { + // (or is insufficiently optional) and we don't need any bridging. + if (srcOptionals.empty() + || (srcOptionals.size() < destOptionals.size() - destExtraOptionals)) { Expr *result = buildInnerOperation(subExpr, finalResultType); if (!result) return nullptr; return addFinalOptionalInjections(result); } - // The result type (without the final optional) is a subtype of - // the operand type, so it will never have a higher depth. - assert(destOptionals.size() - destExtraOptionals <= srcOptionals.size()); - // The outermost N levels of optionals on the operand must all // be present or the cast fails. The innermost M levels of // optionals on the operand are reflected in the requested @@ -4673,9 +4709,21 @@ namespace { KeyPathExpr::Component::forOptionalChain(objectTy, loc)); break; } - case KeyPathExpr::Component::Kind::OptionalForce: - buildKeyPathOptionalForceComponent(resolvedComponents); + case KeyPathExpr::Component::Kind::OptionalForce: { + // Handle force optional when it is the first component e.g. + // \String?.!.count + if (resolvedComponents.empty()) { + auto loc = origComponent.getLoc(); + auto objectTy = componentTy->getOptionalObjectType(); + assert(objectTy); + + resolvedComponents.push_back( + KeyPathExpr::Component::forOptionalForce(objectTy, loc)); + } else { + buildKeyPathOptionalForceComponent(resolvedComponents); + } break; + } case KeyPathExpr::Component::Kind::Invalid: { auto component = origComponent; component.setComponentType(leafTy); @@ -4721,22 +4769,7 @@ namespace { // See whether there's an equivalent ObjC key path string we can produce // for interop purposes. - if (cs.getASTContext().LangOpts.EnableObjCInterop) { - SmallString<64> compatStringBuf; - if (buildObjCKeyPathString(E, compatStringBuf)) { - auto stringCopy = - cs.getASTContext().AllocateCopy(compatStringBuf.begin(), - compatStringBuf.end()); - auto stringExpr = new (cs.getASTContext()) StringLiteralExpr( - StringRef(stringCopy, compatStringBuf.size()), - SourceRange(), - /*implicit*/ true); - cs.setType( - stringExpr, - cs.getASTContext().getStringDecl()->getDeclaredInterfaceType()); - E->setObjCStringLiteralExpr(stringExpr); - } - } + checkAndSetObjCKeyPathString(E); // The final component type ought to line up with the leaf type of the // key path. @@ -5536,7 +5569,7 @@ Expr *ExprRewriter::coerceCallArguments( SmallVector path; auto anchor = locator.getLocatorParts(path); if (!path.empty() && path.back().is() && - (anchor.isExpr(ExprKind::Call) || anchor.isExpr(ExprKind::Subscript))) { + !anchor.isExpr(ExprKind::UnresolvedDot)) { auto locatorPtr = cs.getConstraintLocator(locator); assert(solution.trailingClosureMatchingChoices.count(locatorPtr) == 1); trailingClosureMatching = solution.trailingClosureMatchingChoices.find( @@ -7618,6 +7651,8 @@ namespace { // "Mismatched types!"); assert(!exprType->hasTypeVariable() && "Should not write type variable into expression!"); + assert(!exprType->hasHole() && + "Should not write type holes into expression!"); expr->setType(exprType); if (auto kp = dyn_cast(expr)) { @@ -7627,6 +7662,8 @@ namespace { componentType = solution.simplifyType(cs.getType(kp, i)); assert(!componentType->hasTypeVariable() && "Should not write type variable into key-path component"); + assert(!componentType->hasHole() && + "Should not write type hole into key-path component"); kp->getMutableComponents()[i].setComponentType(componentType); } } @@ -8381,6 +8418,10 @@ Type Solution::getType(ASTNode node) const { return cs.getType(node); } +Type Solution::getResolvedType(ASTNode node) const { + return simplifyType(getType(node)); +} + void Solution::setExprTypes(Expr *expr) const { if (!expr) return; diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index bb99b97afd980..a2cf83809921b 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -22,7 +22,7 @@ using namespace swift; using namespace constraints; void ConstraintSystem::PotentialBindings::inferTransitiveBindings( - ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes, + const ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes, const llvm::SmallDenseMap &inferredBindings) { @@ -56,8 +56,33 @@ void ConstraintSystem::PotentialBindings::inferTransitiveBindings( auto &bindings = relatedBindings->getSecond(); - // Infer transitive protocol requirements. - llvm::copy(bindings.Protocols, std::back_inserter(Protocols)); + // FIXME: This is a workaround necessary because solver doesn't filter + // bindings based on protocol requirements placed on a type variable. + // + // Forward propagate (subtype -> supertype) only literal conformance + // requirements since that helps solver to infer more types at + // parameter positions. + // + // \code + // func foo(_: String, _: T) -> T { + // fatalError() + // } + // + // func bar(_: Any?) {} + // + // func test() { + // bar(foo("", "")) + // } + // \endcode + // + // If one of the literal arguments doesn't propagate its + // `ExpressibleByStringLiteral` conformance, we'd end up picking + // `T` with only one type `Any?` which is incorrect. + llvm::copy_if(bindings.Protocols, std::back_inserter(Protocols), + [](const Constraint *protocol) { + return protocol->getKind() == + ConstraintKind::LiteralConformsTo; + }); // Infer transitive defaults. llvm::copy(bindings.Defaults, std::back_inserter(Defaults)); @@ -119,7 +144,7 @@ isUnviableDefaultType(Type defaultType, } void ConstraintSystem::PotentialBindings::inferDefaultTypes( - ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes) { + const ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes) { auto isDirectRequirement = [&](Constraint *constraint) -> bool { if (auto *typeVar = constraint->getFirstType()->getAs()) { auto *repr = cs.getRepresentative(typeVar); @@ -275,7 +300,7 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes( } void ConstraintSystem::PotentialBindings::finalize( - ConstraintSystem &cs, + const ConstraintSystem &cs, const llvm::SmallDenseMap &inferredBindings) { @@ -335,7 +360,7 @@ void ConstraintSystem::PotentialBindings::finalize( if (locator->isLastElement()) PotentiallyIncomplete = true; - addPotentialBinding(PotentialBinding::forHole(cs.getASTContext(), locator)); + addPotentialBinding(PotentialBinding::forHole(TypeVar, locator)); } // Let's always consider `Any` to be a last resort binding because @@ -374,7 +399,7 @@ ConstraintSystem::determineBestBindings() { // First, let's collect all of the possible bindings. for (auto *typeVar : getTypeVariables()) { if (!typeVar->getImpl().hasRepresentativeOrFixed()) - cache.insert({typeVar, getPotentialBindings(typeVar)}); + cache.insert({typeVar, inferBindingsFor(typeVar, /*finalize=*/false)}); } // Determine whether given type variable with its set of bindings is @@ -481,6 +506,7 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding( if (binding.Kind == AllowedBindingKind::Supertypes && !binding.BindingType->hasUnresolvedType() && !binding.BindingType->hasTypeVariable() && + !binding.BindingType->hasHole() && !binding.BindingType->hasUnboundGenericType() && !binding.hasDefaultedLiteralProtocol() && !binding.isDefaultableBinding() && allowJoinMeet) { @@ -577,20 +603,41 @@ bool ConstraintSystem::PotentialBindings::favoredOverDisjunction( } ConstraintSystem::PotentialBindings -ConstraintSystem::inferBindingsFor(TypeVariableType *typeVar) { - auto bindings = getPotentialBindings(typeVar); +ConstraintSystem::inferBindingsFor(TypeVariableType *typeVar, + bool finalize) const { + assert(typeVar->getImpl().getRepresentative(nullptr) == typeVar && + "not a representative"); + assert(!typeVar->getImpl().getFixedType(nullptr) && "has a fixed type"); + + PotentialBindings bindings(typeVar); + + // Gather the constraints associated with this type variable. + auto constraints = CG.gatherConstraints( + typeVar, ConstraintGraph::GatheringKind::EquivalenceClass); + + llvm::SmallPtrSet exactTypes; + + for (auto *constraint : constraints) { + bool failed = bindings.infer(*this, exactTypes, constraint); + + // Upon inference failure let's produce an empty set of bindings. + if (failed) + return {typeVar}; + } + + if (finalize) { + llvm::SmallDenseMap + inferred; + + bindings.finalize(*this, inferred); + } - llvm::SmallDenseMap - inferred; - bindings.finalize(*this, inferred); return bindings; } Optional ConstraintSystem::getPotentialBindingForRelationalConstraint( - PotentialBindings &result, Constraint *constraint, - bool &hasDependentMemberRelationalConstraints, - bool &hasNonDependentMemberRelationalConstraints) const { + PotentialBindings &result, Constraint *constraint) const { assert(constraint->getClassification() == ConstraintClassification::Relational && "only relational constraints handled here"); @@ -673,11 +720,11 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint( if (type->is()) { if (!ConstraintSystem::typeVarOccursInType(typeVar, type, &result.InvolvesTypeVariables)) { - hasDependentMemberRelationalConstraints = true; + result.FullyBound = true; } + return None; } - hasNonDependentMemberRelationalConstraints = true; // If our binding choice is a function type and we're attempting // to bind to a type variable that is the result of opening a @@ -721,6 +768,24 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint( return None; } + // If subtyping is allowed and this is a result of an implicit member chain, + // let's delay binding it to an optional until its object type resolved too or + // it has been determined that there is no possibility to resolve it. Otherwise + // we might end up missing solutions since it's allowed to implicitly unwrap + // base type of the chain but it can't be done early - type variable + // representing chain's result type has a different l-valueness comparing + // to generic parameter of the optional. + if (kind == AllowedBindingKind::Subtypes) { + auto *locator = typeVar->getImpl().getLocator(); + if (locator && + locator->isLastElement()) { + auto objectType = type->getOptionalObjectType(); + if (objectType && objectType->isTypeVariableOrMember()) { + result.PotentiallyIncomplete = true; + } + } + } + if (type->is() && !typeVar->getImpl().canBindToInOut()) type = LValueType::get(type->getInOutObjectType()); if (type->is() && !typeVar->getImpl().canBindToLValue()) @@ -746,67 +811,46 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint( /// Retrieve the set of potential type bindings for the given /// representative type variable, along with flags indicating whether /// those types should be opened. -ConstraintSystem::PotentialBindings -ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { - assert(typeVar->getImpl().getRepresentative(nullptr) == typeVar && - "not a representative"); - assert(!typeVar->getImpl().getFixedType(nullptr) && "has a fixed type"); - - // Determines whether this type variable represents an object - // of the optional type extracted by force unwrap. - bool isOptionalObject = false; - if (auto *locator = typeVar->getImpl().getLocator()) { - auto anchor = locator->getAnchor(); - isOptionalObject = isExpr(anchor); - } - - // Gather the constraints associated with this type variable. - auto constraints = - getConstraintGraph().gatherConstraints( - typeVar, ConstraintGraph::GatheringKind::EquivalenceClass); - - PotentialBindings result(typeVar); - - // Consider each of the constraints related to this type variable. - llvm::SmallPtrSet exactTypes; - SmallVector literalBindings; - bool hasNonDependentMemberRelationalConstraints = false; - bool hasDependentMemberRelationalConstraints = false; - for (auto constraint : constraints) { - switch (constraint->getKind()) { - case ConstraintKind::Bind: - case ConstraintKind::Equal: - case ConstraintKind::BindParam: - case ConstraintKind::BindToPointerType: - case ConstraintKind::Subtype: - case ConstraintKind::Conversion: - case ConstraintKind::ArgumentConversion: - case ConstraintKind::OperatorArgumentConversion: - case ConstraintKind::OptionalObject: { - // If there is a `bind param` constraint associated with - // current type variable, result should be aware of that - // fact. Binding set might be incomplete until - // this constraint is resolved, because we currently don't - // look-through constraints expect to `subtype` to try and - // find related bindings. - // This only affects type variable that appears one the - // right-hand side of the `bind param` constraint and - // represents result type of the closure body, because - // left-hand side gets types from overload choices. - if (constraint->getKind() == ConstraintKind::BindParam && - constraint->getSecondType()->isEqual(typeVar)) - result.PotentiallyIncomplete = true; +bool ConstraintSystem::PotentialBindings::infer( + const ConstraintSystem &cs, llvm::SmallPtrSetImpl &exactTypes, + Constraint *constraint) { + switch (constraint->getKind()) { + case ConstraintKind::Bind: + case ConstraintKind::Equal: + case ConstraintKind::BindParam: + case ConstraintKind::BindToPointerType: + case ConstraintKind::Subtype: + case ConstraintKind::Conversion: + case ConstraintKind::ArgumentConversion: + case ConstraintKind::OperatorArgumentConversion: + case ConstraintKind::OptionalObject: { + // If there is a `bind param` constraint associated with + // current type variable, result should be aware of that + // fact. Binding set might be incomplete until + // this constraint is resolved, because we currently don't + // look-through constraints expect to `subtype` to try and + // find related bindings. + // This only affects type variable that appears one the + // right-hand side of the `bind param` constraint and + // represents result type of the closure body, because + // left-hand side gets types from overload choices. + if (constraint->getKind() == ConstraintKind::BindParam && + constraint->getSecondType()->isEqual(TypeVar)) + PotentiallyIncomplete = true; - auto binding = getPotentialBindingForRelationalConstraint( - result, constraint, hasDependentMemberRelationalConstraints, - hasNonDependentMemberRelationalConstraints); - if (!binding) - break; + auto binding = + cs.getPotentialBindingForRelationalConstraint(*this, constraint); + if (!binding) + break; - auto type = binding->BindingType; - if (exactTypes.insert(type->getCanonicalType()).second) { - result.addPotentialBinding(*binding); + auto type = binding->BindingType; + if (exactTypes.insert(type->getCanonicalType()).second) { + addPotentialBinding(*binding); + // Determines whether this type variable represents an object + // of the optional type extracted by force unwrap. + if (auto *locator = TypeVar->getImpl().getLocator()) { + auto anchor = locator->getAnchor(); // Result of force unwrap is always connected to its base // optional type via `OptionalObject` constraint which // preserves l-valueness, so in case where object type got @@ -814,191 +858,169 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { // type from context e.g. parameter type of a function call), // we need to test type with and without l-value after // delaying bindings for as long as possible. - if (isOptionalObject && !type->is()) { - result.addPotentialBinding(binding->withType(LValueType::get(type))); - result.FullyBound = true; + if (isExpr(anchor) && !type->is()) { + addPotentialBinding(binding->withType(LValueType::get(type))); + FullyBound = true; } - if (auto *locator = typeVar->getImpl().getLocator()) { - auto path = locator->getPath(); - auto voidType = getASTContext().TheEmptyTupleType; - - // If this is a type variable representing closure result, - // which is on the right-side of some relational constraint - // let's have it try `Void` as well because there is an - // implicit conversion `() -> T` to `() -> Void` and this - // helps to avoid creating a thunk to support it. - if (!path.empty() && - path.back().getKind() == ConstraintLocator::ClosureResult && - binding->Kind == AllowedBindingKind::Supertypes && - exactTypes.insert(voidType).second) { - result.addPotentialBinding({voidType, binding->Kind, constraint}, - /*allowJoinMeet=*/false); - } + // If this is a type variable representing closure result, + // which is on the right-side of some relational constraint + // let's have it try `Void` as well because there is an + // implicit conversion `() -> T` to `() -> Void` and this + // helps to avoid creating a thunk to support it. + auto voidType = cs.getASTContext().TheEmptyTupleType; + if (locator->isLastElement() && + binding->Kind == AllowedBindingKind::Supertypes && + exactTypes.insert(voidType).second) { + addPotentialBinding({voidType, binding->Kind, constraint}, + /*allowJoinMeet=*/false); } } - break; } - case ConstraintKind::KeyPathApplication: { - if (result.FullyBound) - continue; + break; + } + case ConstraintKind::KeyPathApplication: { + if (FullyBound) + return false; + + // If this variable is in the application projected result type, mark the + // result as `FullyBound` to ensure we delay binding until we've bound + // other type variables in the KeyPathApplication constraint. This ensures + // we try to bind the key path type first, which can allow us to discover + // additional bindings for the result type. + SmallPtrSet typeVars; + findInferableTypeVars(cs.simplifyType(constraint->getThirdType()), + typeVars); + if (typeVars.count(TypeVar)) + FullyBound = true; - // If this variable is in the application projected result type, mark the - // result as `FullyBound` to ensure we delay binding until we've bound - // other type variables in the KeyPathApplication constraint. This ensures - // we try to bind the key path type first, which can allow us to discover - // additional bindings for the result type. - SmallPtrSet typeVars; - findInferableTypeVars(simplifyType(constraint->getThirdType()), typeVars); - if (typeVars.count(typeVar)) - result.FullyBound = true; + break; + } - break; + case ConstraintKind::BridgingConversion: + case ConstraintKind::CheckedCast: + case ConstraintKind::EscapableFunctionOf: + case ConstraintKind::OpenedExistentialOf: + case ConstraintKind::KeyPath: + case ConstraintKind::FunctionInput: + case ConstraintKind::FunctionResult: + case ConstraintKind::OpaqueUnderlyingType: + // Constraints from which we can't do anything. + break; + + case ConstraintKind::DynamicTypeOf: { + // Direct binding of the left-hand side could result + // in `DynamicTypeOf` failure if right-hand side is + // bound (because 'Bind' requires equal types to + // succeed), or left is bound to Any which is not an + // [existential] metatype. + auto dynamicType = constraint->getFirstType(); + if (auto *tv = dynamicType->getAs()) { + if (tv->getImpl().getRepresentative(nullptr) == TypeVar) + return true; } - case ConstraintKind::BridgingConversion: - case ConstraintKind::CheckedCast: - case ConstraintKind::EscapableFunctionOf: - case ConstraintKind::OpenedExistentialOf: - case ConstraintKind::KeyPath: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: - case ConstraintKind::OpaqueUnderlyingType: - // Constraints from which we can't do anything. - break; - - case ConstraintKind::DynamicTypeOf: { - // Direct binding of the left-hand side could result - // in `DynamicTypeOf` failure if right-hand side is - // bound (because 'Bind' requires equal types to - // succeed), or left is bound to Any which is not an - // [existential] metatype. - auto dynamicType = constraint->getFirstType(); - if (auto *tv = dynamicType->getAs()) { - if (tv->getImpl().getRepresentative(nullptr) == typeVar) - return {typeVar}; - } + // This is right-hand side, let's continue. + break; + } - // This is right-hand side, let's continue. - break; + case ConstraintKind::Defaultable: + case ConstraintKind::DefaultClosureType: + // Do these in a separate pass. + if (cs.getFixedTypeRecursive(constraint->getFirstType(), true) + ->getAs() == TypeVar) { + Defaults.push_back(constraint); } + break; + + case ConstraintKind::Disjunction: + // FIXME: Recurse into these constraints to see whether this + // type variable is fully bound by any of them. + InvolvesTypeVariables = true; + + // If there is additional context available via disjunction + // associated with closure literal (e.g. coercion to some other + // type) let's delay resolving the closure until the disjunction + // is attempted. + if (TypeVar->getImpl().isClosureType()) + return true; - case ConstraintKind::Defaultable: - case ConstraintKind::DefaultClosureType: - // Do these in a separate pass. - if (getFixedTypeRecursive(constraint->getFirstType(), true) - ->getAs() == typeVar) { - result.Defaults.push_back(constraint); - hasNonDependentMemberRelationalConstraints = true; - } - break; - - case ConstraintKind::Disjunction: - // FIXME: Recurse into these constraints to see whether this - // type variable is fully bound by any of them. - result.InvolvesTypeVariables = true; - - // If there is additional context available via disjunction - // associated with closure literal (e.g. coercion to some other - // type) let's delay resolving the closure until the disjunction - // is attempted. - if (typeVar->getImpl().isClosureType()) - return {typeVar}; - - break; - - case ConstraintKind::ConformsTo: - case ConstraintKind::SelfObjectOfProtocol: - // Swift 3 allowed the use of default types for normal conformances - // to expressible-by-literal protocols. - if (getASTContext().LangOpts.EffectiveLanguageVersion[0] >= 4) - continue; - - if (!constraint->getSecondType()->is()) - continue; - - LLVM_FALLTHROUGH; - - case ConstraintKind::LiteralConformsTo: { - // Record constraint where protocol requirement originated - // this is useful to use for the binding later. - result.Protocols.push_back(constraint); - hasNonDependentMemberRelationalConstraints = true; - break; - } + break; - case ConstraintKind::ApplicableFunction: - case ConstraintKind::DynamicCallableApplicableFunction: - case ConstraintKind::BindOverload: { - if (result.FullyBound && result.InvolvesTypeVariables) - continue; + case ConstraintKind::ConformsTo: + case ConstraintKind::SelfObjectOfProtocol: + return false; - // If this variable is in the left-hand side, it is fully bound. - SmallPtrSet typeVars; - findInferableTypeVars(simplifyType(constraint->getFirstType()), typeVars); - if (typeVars.count(typeVar)) - result.FullyBound = true; + case ConstraintKind::LiteralConformsTo: { + // Record constraint where protocol requirement originated + // this is useful to use for the binding later. + Protocols.push_back(constraint); + break; + } - if (result.InvolvesTypeVariables) - continue; + case ConstraintKind::ApplicableFunction: + case ConstraintKind::DynamicCallableApplicableFunction: + case ConstraintKind::BindOverload: { + if (FullyBound && InvolvesTypeVariables) + return false; - // If this and another type variable occur, this result involves - // type variables. - findInferableTypeVars(simplifyType(constraint->getSecondType()), - typeVars); - if (typeVars.size() > 1 && typeVars.count(typeVar)) - result.InvolvesTypeVariables = true; + // If this variable is in the left-hand side, it is fully bound. + SmallPtrSet typeVars; + findInferableTypeVars(cs.simplifyType(constraint->getFirstType()), + typeVars); + if (typeVars.count(TypeVar)) + FullyBound = true; + + if (InvolvesTypeVariables) + return false; + + // If this and another type variable occur, this result involves + // type variables. + findInferableTypeVars(cs.simplifyType(constraint->getSecondType()), + typeVars); + if (typeVars.size() > 1 && typeVars.count(TypeVar)) + InvolvesTypeVariables = true; + + break; + } - break; + case ConstraintKind::ValueMember: + case ConstraintKind::UnresolvedValueMember: + case ConstraintKind::ValueWitness: + // If our type variable shows up in the base type, there's + // nothing to do. + // FIXME: Can we avoid simplification here? + if (ConstraintSystem::typeVarOccursInType( + TypeVar, cs.simplifyType(constraint->getFirstType()), + &InvolvesTypeVariables)) { + return false; } - case ConstraintKind::ValueMember: - case ConstraintKind::UnresolvedValueMember: - case ConstraintKind::ValueWitness: - // If our type variable shows up in the base type, there's - // nothing to do. - // FIXME: Can we avoid simplification here? - if (ConstraintSystem::typeVarOccursInType( - typeVar, simplifyType(constraint->getFirstType()), - &result.InvolvesTypeVariables)) { - continue; - } - - // If the type variable is in the list of member type - // variables, it is fully bound. - // FIXME: Can we avoid simplification here? - if (ConstraintSystem::typeVarOccursInType( - typeVar, simplifyType(constraint->getSecondType()), - &result.InvolvesTypeVariables)) { - result.FullyBound = true; - } - break; - - case ConstraintKind::OneWayEqual: - case ConstraintKind::OneWayBindParam: { - // Don't produce any bindings if this type variable is on the left-hand - // side of a one-way binding. - auto firstType = constraint->getFirstType(); - if (auto *tv = firstType->getAs()) { - if (tv->getImpl().getRepresentative(nullptr) == typeVar) - return {typeVar}; - } - - break; + // If the type variable is in the list of member type + // variables, it is fully bound. + // FIXME: Can we avoid simplification here? + if (ConstraintSystem::typeVarOccursInType( + TypeVar, cs.simplifyType(constraint->getSecondType()), + &InvolvesTypeVariables)) { + FullyBound = true; } + break; + + case ConstraintKind::OneWayEqual: + case ConstraintKind::OneWayBindParam: { + // Don't produce any bindings if this type variable is on the left-hand + // side of a one-way binding. + auto firstType = constraint->getFirstType(); + if (auto *tv = firstType->getAs()) { + if (tv->getImpl().getRepresentative(nullptr) == TypeVar) + return true; } - } - // If there were both dependent-member and non-dependent-member relational - // constraints, consider this "fully bound"; we don't want to touch it. - if (hasDependentMemberRelationalConstraints) { - if (hasNonDependentMemberRelationalConstraints) - result.FullyBound = true; - else - result.Bindings.clear(); + break; + } } - return result; + return false; } /// Check whether the given type can be used as a binding for the given @@ -1220,10 +1242,23 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const { } else if (TypeVar->getImpl().isClosureParameterType()) { fix = SpecifyClosureParameterType::create(cs, dstLocator); } else if (TypeVar->getImpl().isClosureResultType()) { - fix = SpecifyClosureReturnType::create(cs, dstLocator); + auto *locator = TypeVar->getImpl().getLocator(); + auto *closure = castToExpr(locator->getAnchor()); + // If the whole body is being ignored due to a pre-check failure, + // let's not record a fix about result type since there is + // just not enough context to infer it without a body. + if (!cs.hasFixFor(cs.getConstraintLocator(closure->getBody()), + FixKind::IgnoreInvalidFunctionBuilderBody)) + fix = SpecifyClosureReturnType::create(cs, dstLocator); } else if (srcLocator->directlyAt()) { fix = SpecifyObjectLiteralTypeImport::create(cs, dstLocator); } else if (srcLocator->isKeyPathRoot()) { + // If we recorded an invalid key path fix, let's skip this specify root + // type fix because it wouldn't produce a useful diagnostic. + auto *kpLocator = cs.getConstraintLocator(srcLocator->getAnchor()); + if (cs.hasFixFor(kpLocator, FixKind::AllowKeyPathWithoutComponents)) + return true; + fix = SpecifyKeyPathRootType::create(cs, dstLocator); } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 4791518b68816..822ede889e55a 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -17,8 +17,10 @@ #include "CSDiagnostics.h" #include "ConstraintSystem.h" #include "MiscDiagnostics.h" +#include "TypeCheckProtocol.h" #include "TypoCorrection.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" @@ -641,7 +643,7 @@ Optional> GenericArgumentsMismatchFailure::getDiagnosticFor( void GenericArgumentsMismatchFailure::emitNoteForMismatch(int position) { auto *locator = getLocator(); - // Since there could be implicit conversions assoicated with argument + // Since there could be implicit conversions associated with argument // to parameter conversions, let's use parameter type as a source of // generic parameter information. auto paramSourceTy = @@ -753,6 +755,11 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() { break; } + case ConstraintLocator::UnresolvedMemberChainResult: { + diagnostic = diag::cannot_convert_chain_result_type; + break; + } + default: break; } @@ -1040,6 +1047,8 @@ SourceRange MemberAccessOnOptionalBaseFailure::getSourceRange() const { if (componentPathElt->getIndex() == 0) { if (auto rootType = keyPathExpr->getRootType()) { return rootType->getSourceRange(); + } else { + return keyPathExpr->getComponents().front().getLoc(); } } else { auto componentIdx = componentPathElt->getIndex() - 1; @@ -1069,9 +1078,6 @@ bool MemberAccessOnOptionalBaseFailure::diagnoseAsError() { return false; auto sourceRange = getSourceRange(); - - emitDiagnostic(diag::optional_base_not_unwrapped, - baseType, Member, unwrappedBaseType); auto componentPathElt = locator->getLastElementAs(); @@ -1080,12 +1086,25 @@ bool MemberAccessOnOptionalBaseFailure::diagnoseAsError() { // let's emit a tailored note suggesting to use its unwrapped type. auto *keyPathExpr = castToExpr(getAnchor()); if (auto rootType = keyPathExpr->getRootType()) { + emitDiagnostic(diag::optional_base_not_unwrapped, baseType, Member, + unwrappedBaseType); + emitDiagnostic(diag::optional_base_remove_optional_for_keypath_root, unwrappedBaseType) .fixItReplace(rootType->getSourceRange(), unwrappedBaseType.getString()); + } else { + emitDiagnostic(diag::invalid_optional_infered_keypath_root, baseType, + Member, unwrappedBaseType); + emitDiagnostic(diag::optional_key_path_root_base_chain, Member) + .fixItInsert(sourceRange.End, "?."); + emitDiagnostic(diag::optional_key_path_root_base_unwrap, Member) + .fixItInsert(sourceRange.End, "!."); } } else { + emitDiagnostic(diag::optional_base_not_unwrapped, baseType, Member, + unwrappedBaseType); + // FIXME: It would be nice to immediately offer "base?.member ?? defaultValue" // for non-optional results where that would be appropriate. For the moment // always offering "?" means that if the user chooses chaining, we'll end up @@ -1124,6 +1143,8 @@ void MissingOptionalUnwrapFailure::offerDefaultValueUnwrapFixIt( bool needsParensInside = exprNeedsParensBeforeAddingNilCoalescing(DC, const_cast(expr)); auto parentExpr = findParentExpr(anchor); + if (parentExpr && isa(parentExpr)) + parentExpr = findParentExpr(parentExpr); bool needsParensOutside = exprNeedsParensAfterAddingNilCoalescing( DC, const_cast(expr), parentExpr); @@ -1177,7 +1198,7 @@ class VarDeclMultipleReferencesChecker : public ASTWalker { VarDecl *varDecl; int count; - std::pair walkToExprPre(Expr *E) { + std::pair walkToExprPre(Expr *E) override { if (auto *DRE = dyn_cast(E)) { if (DRE->getDecl() == varDecl) ++count; @@ -1198,14 +1219,6 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() { auto *anchor = castToExpr(getAnchor()); - // If this is an unresolved member expr e.g. `.foo` its - // base type is going to be the same as result type minus - // r-value adjustment because base could be an l-value type. - // We want to fix both cases by only diagnose one of them, - // otherwise this is just going to result in a duplcate diagnostic. - if (getLocator()->isLastElement()) - return false; - if (auto assignExpr = dyn_cast(anchor)) anchor = assignExpr->getSrc(); @@ -1235,8 +1248,10 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() { assert(!baseType->hasTypeVariable() && "Base type must not be a type variable"); + assert(!baseType->isHole() && "Base type must not be a type hole"); assert(!unwrappedType->hasTypeVariable() && "Unwrapped type must not be a type variable"); + assert(!unwrappedType->isHole() && "Unwrapped type must not be a type hole"); if (!baseType->getOptionalObjectType()) return false; @@ -1313,6 +1328,11 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { if (getContextualTypePurpose(diagExpr) == CTP_Condition) return false; + // If the failure happened at the end of an unresolved member chain, it should + // be diagnosed instead as though it happened at the last element. + if (auto chainExpr = dyn_cast(diagExpr)) + diagExpr = chainExpr->getSubExpr(); + if (auto assignExpr = dyn_cast(diagExpr)) { // Let's check whether this is an attempt to assign // variable or property to itself. @@ -1436,6 +1456,8 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { } } else if (isa(diagExpr)) { subElementDiagID = diag::assignment_subscript_has_immutable_base; + } else if (auto *UME = dyn_cast(diagExpr)) { + subElementDiagID = diag::assignment_lhs_is_immutable_property; } else { subElementDiagID = diag::assignment_lhs_is_immutable_variable; } @@ -1860,7 +1882,9 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const { // In Swift versions lower than 5, this check will fail as read only // key paths can masquerade as writable for compatibilty reasons. // This is fine as in this case we just fall back on old diagnostics. - if (bgt->getDecl() == getASTContext().getKeyPathDecl()) { + auto &ctx = getASTContext(); + if (bgt->getDecl() == ctx.getKeyPathDecl() || + bgt->getDecl() == ctx.getPartialKeyPathDecl()) { return {expr, member}; } } @@ -1900,6 +1924,18 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const { return resolveImmutableBase(MRE->getBase()); } + if (auto *UME = dyn_cast(expr)) { + auto loc = getConstraintLocator(UME, ConstraintLocator::UnresolvedMember); + auto member = getMemberRef(loc); + + // If we can resolve a member, we can determine whether it is settable in + // this context. + if (member && member->isDecl() && isImmutable(member->getDecl())) + return {expr, member}; + else + return {expr, None}; + } + if (auto *DRE = dyn_cast(expr)) return {expr, OverloadChoice(Type(), DRE->getDecl(), FunctionRefKind::Unapplied)}; @@ -2133,10 +2169,11 @@ bool ContextualFailure::diagnoseAsError() { return false; } - case ConstraintLocator::RValueAdjustment: { + case ConstraintLocator::UnresolvedMemberChainResult: { auto &solution = getSolution(); - auto overload = getOverloadChoiceIfAvailable( - getConstraintLocator(anchor, ConstraintLocator::UnresolvedMember)); + + auto overload = + getCalleeOverloadChoiceIfAvailable(getConstraintLocator(anchor)); if (!(overload && overload->choice.isDecl())) return false; @@ -2171,13 +2208,22 @@ bool ContextualFailure::diagnoseAsError() { }); if (numMissingArgs == 0 || numMissingArgs > 1) { - auto diagnostic = emitDiagnostic( - diag::expected_parens_in_contextual_member, choice->getName()); - - // If there are no parameters we can suggest a fix-it - // to form an explicit call. - if (numMissingArgs == 0) - diagnostic.fixItInsertAfter(getSourceRange().End, "()"); + auto applyFixIt = [&](InFlightDiagnostic &diagnostic) { + // If there are no parameters we can suggest a fix-it + // to form an explicit call. + if (numMissingArgs == 0) + diagnostic.fixItInsertAfter(getSourceRange().End, "()"); + }; + if (fnType->getResult()->isEqual(toType)) { + auto diag = emitDiagnostic( + diag::expected_parens_in_contextual_member_type, + choice->getName(), fnType->getResult()); + applyFixIt(diag); + } else { + auto diag = emitDiagnostic(diag::expected_parens_in_contextual_member, + choice->getName()); + applyFixIt(diag); + } } else { emitDiagnostic(diag::expected_argument_in_contextual_member, choice->getName(), params.front().getPlainType()); @@ -2396,6 +2442,10 @@ bool ContextualFailure::diagnoseMissingFunctionCall() const { if (getLocator()->isLastElement()) return false; + if (getLocator() + ->isLastElement()) + return false; + auto *srcFT = getFromType()->getAs(); if (!srcFT || !(srcFT->getParams().empty() || @@ -2766,9 +2816,11 @@ bool ContextualFailure::tryProtocolConformanceFixIt( // Let's build a list of protocols that the context does not conform to. SmallVector missingProtoTypeStrings; + SmallVector missingProtocols; for (auto protocol : layout.getProtocols()) { if (!TypeChecker::conformsToProtocol(fromType, protocol->getDecl(), getDC())) { missingProtoTypeStrings.push_back(protocol->getString()); + missingProtocols.push_back(protocol->getDecl()); } } @@ -2790,8 +2842,6 @@ bool ContextualFailure::tryProtocolConformanceFixIt( // Emit a diagnostic to inform the user that they need to conform to the // missing protocols. - // - // TODO: Maybe also insert the requirement stubs? auto conformanceDiag = emitDiagnostic(diag::assign_protocol_conformance_fix_it, unwrappedToType, nominal->getDescriptiveKind(), fromType); @@ -2806,6 +2856,35 @@ bool ContextualFailure::tryProtocolConformanceFixIt( conformanceDiag.fixItInsert(nameEndLoc, ": " + protoString); } + // Emit fix-its to insert requirement stubs if we're in editor mode. + if (!getASTContext().LangOpts.DiagnosticsEditorMode) { + return true; + } + + { + llvm::SmallString<128> Text; + llvm::raw_svector_ostream SS(Text); + llvm::SetVector missingWitnesses; + for (auto protocol : missingProtocols) { + auto conformance = NormalProtocolConformance( + nominal->getDeclaredType(), protocol, SourceLoc(), nominal, + ProtocolConformanceState::Incomplete); + ConformanceChecker checker(getASTContext(), &conformance, + missingWitnesses); + checker.resolveValueWitnesses(); + checker.resolveTypeWitnesses(); + } + + for (auto decl : missingWitnesses) { + swift::printRequirementStub(decl, nominal, nominal->getDeclaredType(), + nominal->getStartLoc(), SS); + } + + if (!Text.empty()) { + conformanceDiag.fixItInsertAfter(nominal->getBraces().Start, Text.str()); + } + } + return true; } @@ -3092,7 +3171,7 @@ bool MissingCallFailure::diagnoseAsError() { } bool ExtraneousPropertyWrapperUnwrapFailure::diagnoseAsError() { - auto newPrefix = usingStorageWrapper() ? "$" : "_"; + auto newPrefix = usingProjection() ? "$" : "_"; if (auto *member = getReferencedMember()) { emitDiagnostic(diag::incorrect_property_wrapper_reference_member, @@ -3409,6 +3488,13 @@ bool MissingMemberFailure::diagnoseInLiteralCollectionContext() const { if (!(parentExpr && isa(expr))) return false; + if (!isa(parentExpr)) + return false; + + parentExpr = findParentExpr(parentExpr); + if (!parentExpr) + return false; + auto parentType = getType(parentExpr); if (!parentType->isKnownStdlibCollectionType() && !parentType->is()) @@ -4425,9 +4511,6 @@ MissingArgumentsFailure::getCallInfo(ASTNode anchor) const { return std::make_tuple(call->getFn(), call->getArg(), call->getNumArguments(), call->getUnlabeledTrailingClosureIndex()); - } else if (auto *UME = getAsExpr(anchor)) { - return std::make_tuple(UME, UME->getArgument(), UME->getNumArguments(), - UME->getUnlabeledTrailingClosureIndex()); } else if (auto *SE = getAsExpr(anchor)) { return std::make_tuple(SE, SE->getIndex(), SE->getNumArguments(), SE->getUnlabeledTrailingClosureIndex()); @@ -5002,7 +5085,7 @@ bool ExtraneousReturnFailure::diagnoseAsError() { // cases like like 'var foo: () { return 1 }' as here that loc will // be invalid. We also need to check that the name is not empty, // because certain decls will have empty name (like setters). - if (FD->getBodyResultTypeLoc().getLoc().isInvalid() && + if (FD->getResultTypeRepr() == nullptr && FD->getParameters()->getStartLoc().isValid() && !FD->getBaseIdentifier().empty()) { auto fixItLoc = Lexer::getLocForEndOfToken( @@ -5055,7 +5138,7 @@ bool CollectionElementContextualFailure::diagnoseAsError() { // holes present in the contextual type. if (FailureDiagnostic::getContextualTypePurpose(getAnchor()) == ContextualTypePurpose::CTP_ForEachStmt && - contextualType->hasHole()) { + contextualType->hasUnresolvedType()) { diagnostic.emplace(emitDiagnostic( (contextualType->is() && !eltType->is()) ? diag::cannot_match_expr_tuple_pattern_with_nontuple_value @@ -6266,6 +6349,20 @@ bool MissingContextualBaseInMemberRefFailure::diagnoseAsError() { // Member reference could be wrapped into a number of parens // e.g. `((.foo))`. auto *parentExpr = findParentExpr(anchor); + + // Look through immediate call of unresolved member (e.g., `.foo(0)`). + if (parentExpr && isa(parentExpr)) + parentExpr = findParentExpr(parentExpr); + + // FIXME: We should probably look through the entire member chain so that + // something like `let _ = .foo().bar` gets the "no contextual type" error + // rather than the "Cannot infer contextual base" error. + UnresolvedMemberChainResultExpr *resultExpr = nullptr; + if (parentExpr && isa(parentExpr)) { + resultExpr = cast(parentExpr); + parentExpr = findParentExpr(parentExpr); + } + do { // If we have found something which isn't a paren let's stop, // otherwise let's keep unwrapping until there are either no @@ -6274,7 +6371,7 @@ bool MissingContextualBaseInMemberRefFailure::diagnoseAsError() { break; } while ((parentExpr = findParentExpr(parentExpr))); - auto diagnostic = parentExpr || getContextualType(anchor) + auto diagnostic = parentExpr || (resultExpr && getContextualType(resultExpr)) ? diag::cannot_infer_base_of_unresolved_member : diag::unresolved_member_no_inference; @@ -6313,7 +6410,7 @@ bool UnableToInferClosureParameterType::diagnoseAsError() { if (parentExpr) { // Missing or invalid member reference in call. if (auto *AE = dyn_cast(parentExpr)) { - if (getType(AE->getFn())->isHole()) + if (getType(AE->getFn())->is()) return false; } @@ -6760,3 +6857,19 @@ void TrailingClosureRequiresExplicitLabel::fixIt( diagnostic.fixItInsert(newRParenLoc, isExpr(anchor) ? "]" : ")"); } + +bool InvalidEmptyKeyPathFailure::diagnoseAsError() { + auto *KPE = getAsExpr(getAnchor()); + assert(KPE && KPE->hasSingleInvalidComponent() && + "Expected a malformed key path expression"); + + // If we have a string interpolation represented as key path expressions + // e.g. \(x), \(x, a: 1). Let's skip it because this would be already + // diagnosed and it is not the case for an extra empty key path diagnostic. + auto *root = KPE->getParsedRoot(); + if (root && (isa(root) || isa(root))) + return true; + + emitDiagnostic(diag::expr_swift_keypath_empty); + return true; +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 30192dbc20fc4..980a8a51b753b 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -94,20 +94,26 @@ class FailureDiagnostic { /// Resolve type variables present in the raw type, if any. Type resolveType(Type rawType, bool reconstituteSugar = false, bool wantRValue = true) const { - if (!rawType->hasTypeVariable()) { - if (reconstituteSugar) - rawType = rawType->reconstituteSugar(/*recursive*/ true); - return wantRValue ? rawType->getRValueType() : rawType; + auto &cs = getConstraintSystem(); + + if (rawType->hasTypeVariable() || rawType->hasHole()) { + rawType = rawType.transform([&](Type type) { + if (auto *typeVar = type->getAs()) { + auto resolvedType = S.simplifyType(typeVar); + Type GP = typeVar->getImpl().getGenericParameter(); + return resolvedType->is() && GP + ? GP + : resolvedType; + } + + return type->isHole() ? Type(cs.getASTContext().TheUnresolvedType) + : type; + }); } - auto &cs = getConstraintSystem(); - return cs.simplifyTypeImpl(rawType, [&](TypeVariableType *typeVar) -> Type { - auto fixed = S.simplifyType(typeVar); - auto *genericParam = typeVar->getImpl().getGenericParameter(); - if (fixed->isHole() && genericParam) - return genericParam; - return resolveType(fixed, reconstituteSugar, wantRValue); - }); + if (reconstituteSugar) + rawType = rawType->reconstituteSugar(/*recursive*/ true); + return wantRValue ? rawType->getRValueType() : rawType; } template @@ -968,20 +974,20 @@ class MissingCallFailure final : public FailureDiagnostic { class PropertyWrapperReferenceFailure : public ContextualFailure { VarDecl *Property; - bool UsingStorageWrapper; + bool UsingProjection; public: PropertyWrapperReferenceFailure(const Solution &solution, VarDecl *property, - bool usingStorageWrapper, Type base, + bool usingProjection, Type base, Type wrapper, ConstraintLocator *locator) : ContextualFailure(solution, base, wrapper, locator), Property(property), - UsingStorageWrapper(usingStorageWrapper) {} + UsingProjection(usingProjection) {} VarDecl *getProperty() const { return Property; } Identifier getPropertyName() const { return Property->getName(); } - bool usingStorageWrapper() const { return UsingStorageWrapper; } + bool usingProjection() const { return UsingProjection; } ValueDecl *getReferencedMember() const { auto *locator = getLocator(); @@ -2013,7 +2019,7 @@ class MissingContextualBaseInMemberRefFailure final : public FailureDiagnostic { ConstraintLocator *locator) : FailureDiagnostic(solution, locator), MemberName(member) {} - bool diagnoseAsError(); + bool diagnoseAsError() override; }; class UnableToInferClosureParameterType final : public FailureDiagnostic { @@ -2022,7 +2028,7 @@ class UnableToInferClosureParameterType final : public FailureDiagnostic { ConstraintLocator *locator) : FailureDiagnostic(solution, locator) {} - bool diagnoseAsError(); + bool diagnoseAsError() override; }; class UnableToInferClosureReturnType final : public FailureDiagnostic { @@ -2031,7 +2037,7 @@ class UnableToInferClosureReturnType final : public FailureDiagnostic { ConstraintLocator *locator) : FailureDiagnostic(solution, locator) {} - bool diagnoseAsError(); + bool diagnoseAsError() override; }; class UnableToInferProtocolLiteralType final : public FailureDiagnostic { @@ -2065,7 +2071,7 @@ class MissingQuialifierInMemberRefFailure final : public FailureDiagnostic { ConstraintLocator *locator) : FailureDiagnostic(solution, locator) {} - bool diagnoseAsError(); + bool diagnoseAsError() override; }; /// Emits a warning about an attempt to use the 'as' operator as the 'as!' @@ -2248,6 +2254,20 @@ class TrailingClosureRequiresExplicitLabel final : public FailureDiagnostic { const FunctionArgApplyInfo &info) const; }; +/// Diagnose situations where we have a key path with no components. +/// +/// \code +/// let _ : KeyPath = \A +/// \endcode +class InvalidEmptyKeyPathFailure final : public FailureDiagnostic { +public: + InvalidEmptyKeyPathFailure(const Solution &solution, + ConstraintLocator *locator) + : FailureDiagnostic(solution, locator) {} + + bool diagnoseAsError() override; +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 96f6a43872284..9808f8d63e7c8 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -534,22 +534,22 @@ InsertExplicitCall *InsertExplicitCall::create(ConstraintSystem &cs, bool UsePropertyWrapper::diagnose(const Solution &solution, bool asNote) const { ExtraneousPropertyWrapperUnwrapFailure failure( - solution, Wrapped, UsingStorageWrapper, Base, Wrapper, getLocator()); + solution, Wrapped, UsingProjection, Base, Wrapper, getLocator()); return failure.diagnose(asNote); } UsePropertyWrapper *UsePropertyWrapper::create(ConstraintSystem &cs, VarDecl *wrapped, - bool usingStorageWrapper, + bool usingProjection, Type base, Type wrapper, ConstraintLocator *locator) { return new (cs.getAllocator()) UsePropertyWrapper( - cs, wrapped, usingStorageWrapper, base, wrapper, locator); + cs, wrapped, usingProjection, base, wrapper, locator); } bool UseWrappedValue::diagnose(const Solution &solution, bool asNote) const { MissingPropertyWrapperUnwrapFailure failure(solution, PropertyWrapper, - usingStorageWrapper(), Base, + usingProjection(), Base, Wrapper, getLocator()); return failure.diagnose(asNote); } @@ -1539,3 +1539,67 @@ SpecifyLabelToAssociateTrailingClosure::create(ConstraintSystem &cs, return new (cs.getAllocator()) SpecifyLabelToAssociateTrailingClosure(cs, locator); } + +bool AllowKeyPathWithoutComponents::diagnose(const Solution &solution, + bool asNote) const { + InvalidEmptyKeyPathFailure failure(solution, getLocator()); + return failure.diagnose(asNote); +} + +AllowKeyPathWithoutComponents * +AllowKeyPathWithoutComponents::create(ConstraintSystem &cs, + ConstraintLocator *locator) { + return new (cs.getAllocator()) AllowKeyPathWithoutComponents(cs, locator); +} + +bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution, + bool asNote) const { + switch (Phase) { + // Handled below + case ErrorInPhase::PreCheck: + break; + case ErrorInPhase::ConstraintGeneration: + return true; // Already diagnosed by `matchFunctionBuilder`. + } + + auto *S = getAnchor().get(); + + class PreCheckWalker : public ASTWalker { + DeclContext *DC; + DiagnosticTransaction Transaction; + + public: + PreCheckWalker(DeclContext *dc) + : DC(dc), Transaction(dc->getASTContext().Diags) {} + + std::pair walkToExprPre(Expr *E) override { + auto hasError = ConstraintSystem::preCheckExpression( + E, DC, /*replaceInvalidRefsWithErrors=*/true); + return std::make_pair(false, hasError ? nullptr : E); + } + + std::pair walkToStmtPre(Stmt *S) override { + return std::make_pair(true, S); + } + + // Ignore patterns because function builder pre-check does so as well. + std::pair walkToPatternPre(Pattern *P) override { + return std::make_pair(false, P); + } + + bool diagnosed() const { + return Transaction.hasErrors(); + } + }; + + PreCheckWalker walker(solution.getDC()); + S->walk(walker); + + return walker.diagnosed(); +} + +IgnoreInvalidFunctionBuilderBody *IgnoreInvalidFunctionBuilderBody::create( + ConstraintSystem &cs, ErrorInPhase phase, ConstraintLocator *locator) { + return new (cs.getAllocator()) + IgnoreInvalidFunctionBuilderBody(cs, phase, locator); +} diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index ae232f33ff187..acf8123fcbc26 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -266,13 +266,19 @@ enum class FixKind : uint8_t { /// Specify key path root type when it cannot be infered from context. SpecifyKeyPathRootType, - + /// Unwrap optional base on key path application. UnwrapOptionalBaseKeyPathApplication, /// Explicitly specify a label to match trailing closure to a certain /// parameter in the call. SpecifyLabelToAssociateTrailingClosure, + + /// Allow key path expressions with no components. + AllowKeyPathWithoutComponents, + + /// Ignore function builder body which fails `pre-check` call. + IgnoreInvalidFunctionBuilderBody, }; class ConstraintFix { @@ -793,15 +799,15 @@ class InsertExplicitCall final : public ConstraintFix { class UsePropertyWrapper final : public ConstraintFix { VarDecl *Wrapped; - bool UsingStorageWrapper; + bool UsingProjection; Type Base; Type Wrapper; UsePropertyWrapper(ConstraintSystem &cs, VarDecl *wrapped, - bool usingStorageWrapper, Type base, Type wrapper, + bool usingProjection, Type base, Type wrapper, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::UsePropertyWrapper, locator), - Wrapped(wrapped), UsingStorageWrapper(usingStorageWrapper), Base(base), + Wrapped(wrapped), UsingProjection(usingProjection), Base(base), Wrapper(wrapper) {} public: @@ -816,7 +822,7 @@ class UsePropertyWrapper final : public ConstraintFix { } static UsePropertyWrapper *create(ConstraintSystem &cs, VarDecl *wrapped, - bool usingStorageWrapper, Type base, + bool usingProjection, Type base, Type wrapper, ConstraintLocator *locator); }; @@ -830,7 +836,7 @@ class UseWrappedValue final : public ConstraintFix { : ConstraintFix(cs, FixKind::UseWrappedValue, locator), PropertyWrapper(propertyWrapper), Base(base), Wrapper(wrapper) {} - bool usingStorageWrapper() const { + bool usingProjection() const { auto nameStr = PropertyWrapper->getName().str(); return !nameStr.startswith("_"); } @@ -1694,9 +1700,9 @@ class CoerceToCheckedCast final : public ContextualMismatch { locator) {} public: - std::string getName() const { return "as to as!"; } + std::string getName() const override { return "as to as!"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static CoerceToCheckedCast *attempt(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); @@ -1707,11 +1713,11 @@ class RemoveInvalidCall final : public ConstraintFix { : ConstraintFix(cs, FixKind::RemoveCall, locator) {} public: - std::string getName() const { + std::string getName() const override { return "remove extraneous call from value of non-function type"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static RemoveInvalidCall *create(ConstraintSystem &cs, ConstraintLocator *locator); @@ -1749,13 +1755,13 @@ class SpecifyBaseTypeForContextualMember final : public ConstraintFix { MemberName(member) {} public: - std::string getName() const { + std::string getName() const override { const auto baseName = MemberName.getBaseName(); return "specify base type in reference to member '" + baseName.userFacingName().str() + "'"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyBaseTypeForContextualMember * create(ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator); @@ -1766,9 +1772,9 @@ class SpecifyClosureParameterType final : public ConstraintFix { : ConstraintFix(cs, FixKind::SpecifyClosureParameterType, locator) {} public: - std::string getName() const; + std::string getName() const override; - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyClosureParameterType *create(ConstraintSystem &cs, ConstraintLocator *locator); @@ -1779,11 +1785,11 @@ class SpecifyClosureReturnType final : public ConstraintFix { : ConstraintFix(cs, FixKind::SpecifyClosureReturnType, locator) {} public: - std::string getName() const { + std::string getName() const override { return "specify closure return type"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyClosureReturnType *create(ConstraintSystem &cs, ConstraintLocator *locator); @@ -1794,11 +1800,11 @@ class SpecifyObjectLiteralTypeImport final : public ConstraintFix { : ConstraintFix(cs, FixKind::SpecifyObjectLiteralTypeImport, locator) {} public: - std::string getName() const { + std::string getName() const override { return "import required module to gain access to a default literal type"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyObjectLiteralTypeImport *create(ConstraintSystem &cs, ConstraintLocator *locator); @@ -1810,11 +1816,11 @@ class AddQualifierToAccessTopLevelName final : public ConstraintFix { : ConstraintFix(cs, FixKind::AddQualifierToAccessTopLevelName, locator) {} public: - std::string getName() const { + std::string getName() const override { return "qualify reference to access top-level function"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static AddQualifierToAccessTopLevelName *create(ConstraintSystem &cs, ConstraintLocator *locator); @@ -1825,11 +1831,11 @@ class AllowNonClassTypeToConvertToAnyObject final : public ContextualMismatch { ConstraintLocator *locator); public: - std::string getName() const { + std::string getName() const override { return "allow non-class type to convert to 'AnyObject'"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowNonClassTypeToConvertToAnyObject * create(ConstraintSystem &cs, Type type, ConstraintLocator *locator); @@ -1852,11 +1858,11 @@ class AllowCoercionToForceCast final : public ContextualMismatch { toType, locator, /*warning*/ true) {} public: - std::string getName() const { + std::string getName() const override { return "allow coercion to be treated as a force-cast"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowCoercionToForceCast *create(ConstraintSystem &cs, Type fromType, Type toType, @@ -1894,11 +1900,11 @@ class SpecifyKeyPathRootType final : public ConstraintFix { : ConstraintFix(cs, FixKind::SpecifyKeyPathRootType, locator) {} public: - std::string getName() const { + std::string getName() const override { return "specify key path root type"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyKeyPathRootType *create(ConstraintSystem &cs, ConstraintLocator *locator); @@ -1958,6 +1964,64 @@ class SpecifyLabelToAssociateTrailingClosure final : public ConstraintFix { create(ConstraintSystem &cs, ConstraintLocator *locator); }; +/// Diagnose situations where we have a key path with no components. +/// +/// \code +/// let _ : KeyPath = \A +/// \endcode +class AllowKeyPathWithoutComponents final : public ConstraintFix { + AllowKeyPathWithoutComponents(ConstraintSystem &cs, + ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::AllowKeyPathWithoutComponents, locator) {} + +public: + std::string getName() const override { return "key path missing component"; } + + bool diagnose(const Solution &solution, bool asNote = false) const override; + + static AllowKeyPathWithoutComponents *create(ConstraintSystem &cs, + ConstraintLocator *locator); +}; + +class IgnoreInvalidFunctionBuilderBody final : public ConstraintFix { + enum class ErrorInPhase { + PreCheck, + ConstraintGeneration, + }; + + ErrorInPhase Phase; + + IgnoreInvalidFunctionBuilderBody(ConstraintSystem &cs, ErrorInPhase phase, + ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::IgnoreInvalidFunctionBuilderBody, locator), + Phase(phase) {} + +public: + std::string getName() const override { + return "ignore invalid function builder body"; + } + + bool diagnose(const Solution &solution, bool asNote = false) const override; + + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { + return diagnose(*commonFixes.front().first); + } + + static IgnoreInvalidFunctionBuilderBody * + duringPreCheck(ConstraintSystem &cs, ConstraintLocator *locator) { + return create(cs, ErrorInPhase::PreCheck, locator); + } + + static IgnoreInvalidFunctionBuilderBody * + duringConstraintGeneration(ConstraintSystem &cs, ConstraintLocator *locator) { + return create(cs, ErrorInPhase::ConstraintGeneration, locator); + } + +private: + static IgnoreInvalidFunctionBuilderBody * + create(ConstraintSystem &cs, ErrorInPhase phase, ConstraintLocator *locator); +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index b4f0c1facc721..c3450ad9f39fd 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -79,22 +79,10 @@ namespace { /// Internal struct for tracking information about types within a series /// of "linked" expressions. (Such as a chain of binary operator invocations.) struct LinkedTypeInfo { - unsigned haveIntLiteral : 1; - unsigned haveFloatLiteral : 1; - unsigned haveStringLiteral : 1; + bool hasLiteral = false; llvm::SmallSet collectedTypes; llvm::SmallVector binaryExprs; - - LinkedTypeInfo() { - haveIntLiteral = false; - haveFloatLiteral = false; - haveStringLiteral = false; - } - - bool hasLiteral() { - return haveIntLiteral || haveFloatLiteral || haveStringLiteral; - } }; /// Walks an expression sub-tree, and collects information about expressions @@ -180,19 +168,9 @@ namespace { !CS.getType(expr)->hasTypeVariable()) { return { false, expr }; } - - if (isa(expr)) { - LTI.haveIntLiteral = true; - return { false, expr }; - } - - if (isa(expr)) { - LTI.haveFloatLiteral = true; - return { false, expr }; - } - - if (isa(expr)) { - LTI.haveStringLiteral = true; + + if (isa(expr)) { + LTI.hasLiteral = true; return { false, expr }; } @@ -331,7 +309,7 @@ namespace { auto simplifyBinOpExprTyVars = [&]() { // Don't attempt to do linking if there are // literals intermingled with other inferred types. - if (lti.hasLiteral()) + if (lti.hasLiteral) return; for (auto binExp1 : lti.binaryExprs) { @@ -391,42 +369,6 @@ namespace { simplifyBinOpExprTyVars(); return true; - } - - if (lti.haveFloatLiteral) { - if (auto floatProto = CS.getASTContext().getProtocol( - KnownProtocolKind::ExpressibleByFloatLiteral)) { - if (auto defaultType = TypeChecker::getDefaultType(floatProto, CS.DC)) { - if (!CS.getFavoredType(expr)) { - CS.setFavoredType(expr, defaultType.getPointer()); - } - return true; - } - } - } - - if (lti.haveIntLiteral) { - if (auto intProto = CS.getASTContext().getProtocol( - KnownProtocolKind::ExpressibleByIntegerLiteral)) { - if (auto defaultType = TypeChecker::getDefaultType(intProto, CS.DC)) { - if (!CS.getFavoredType(expr)) { - CS.setFavoredType(expr, defaultType.getPointer()); - } - return true; - } - } - } - - if (lti.haveStringLiteral) { - if (auto stringProto = CS.getASTContext().getProtocol( - KnownProtocolKind::ExpressibleByStringLiteral)) { - if (auto defTy = TypeChecker::getDefaultType(stringProto, CS.DC)) { - if (!CS.getFavoredType(expr)) { - CS.setFavoredType(expr, defTy.getPointer()); - } - return true; - } - } } return false; @@ -850,6 +792,10 @@ namespace { /// Keep track of acceptable DiscardAssignmentExpr's. llvm::SmallPtrSet CorrectDiscardAssignmentExprs; + /// A map from each UnresolvedMemberExpr to the respective (implicit) base + /// found during our walk. + llvm::MapVector UnresolvedBaseTypes; + /// Returns false and emits the specified diagnostic if the member reference /// base is a nil literal. Returns true otherwise. bool isValidBaseOfMemberRef(Expr *base, Diag<> diagnostic) { @@ -1382,17 +1328,11 @@ namespace { Type resolveTypeReferenceInExpression(TypeRepr *repr, TypeResolverContext resCtx, - OpenUnboundGenericTypeFn unboundTyOpener) { - if (!unboundTyOpener) { - unboundTyOpener = [](auto unboundTy) { - // FIXME: Don't let unbound generic types escape type resolution. - // For now, just return the unbound generic type. - return unboundTy; - }; - } - const auto result = - TypeResolution::forContextual(CS.DC, resCtx, unboundTyOpener) - .resolveType(repr); + const ConstraintLocatorBuilder &locator) { + // Introduce type variables for unbound generics. + const auto opener = OpenUnboundGenericType(CS, locator); + const auto result = TypeResolution::forContextual(CS.DC, resCtx, opener) + .resolveType(repr); if (result->hasError()) { return Type(); } @@ -1418,8 +1358,7 @@ namespace { auto *repr = E->getTypeRepr(); assert(repr && "Explicit node has no type repr!"); type = resolveTypeReferenceInExpression( - repr, TypeResolverContext::InExpression, - OpenUnboundGenericType(CS, locator)); + repr, TypeResolverContext::InExpression, locator); } if (!type || type->hasError()) return Type(); @@ -1480,15 +1419,21 @@ namespace { Type visitDynamicMemberRefExpr(DynamicMemberRefExpr *expr) { llvm_unreachable("Already typechecked"); } + + void setUnresolvedBaseType(UnresolvedMemberExpr *UME, Type ty) { + UnresolvedBaseTypes.insert({UME, ty}); + } + + Type getUnresolvedBaseType(UnresolvedMemberExpr *UME) { + auto result = UnresolvedBaseTypes.find(UME); + assert(result != UnresolvedBaseTypes.end()); + return result->second; + } virtual Type visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { auto baseLocator = CS.getConstraintLocator( expr, ConstraintLocator::MemberRefBase); - FunctionRefKind functionRefKind = - expr->getArgument() ? FunctionRefKind::DoubleApply - : FunctionRefKind::Compound; - auto memberLocator = CS.getConstraintLocator(expr, ConstraintLocator::UnresolvedMember); @@ -1496,6 +1441,8 @@ namespace { // should be marked as a potential hole. auto baseTy = CS.createTypeVariable(baseLocator, TVO_CanBindToNoEscape | TVO_CanBindToHole); + setUnresolvedBaseType(expr, baseTy); + auto memberTy = CS.createTypeVariable( memberLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); @@ -1508,54 +1455,38 @@ namespace { // member, i.e., an enum case or a static variable. auto baseMetaTy = MetatypeType::get(baseTy); CS.addUnresolvedValueMemberConstraint(baseMetaTy, expr->getName(), - memberTy, CurDC, functionRefKind, + memberTy, CurDC, + expr->getFunctionRefKind(), memberLocator); + return memberTy; + } + + Type visitUnresolvedMemberChainResultExpr( + UnresolvedMemberChainResultExpr *expr) { + auto *tail = expr->getSubExpr(); + auto memberTy = CS.getType(tail); + auto *base = expr->getChainBase(); + assert(base == TypeChecker::getUnresolvedMemberChainBase(tail)); + + // The result type of the chain is is represented by a new type variable. + auto locator = CS.getConstraintLocator( + expr, ConstraintLocator::UnresolvedMemberChainResult); + auto chainResultTy = CS.createTypeVariable( + locator, + TVO_CanBindToLValue | TVO_CanBindToHole | TVO_CanBindToNoEscape); + auto chainBaseTy = getUnresolvedBaseType(base); + + // The result of the last element of the chain must be convertible to the + // whole chain, and the type of the whole chain must be equal to the base. + CS.addConstraint( + ConstraintKind::Conversion, memberTy, chainBaseTy, + CS.getConstraintLocator(tail, ConstraintLocator::RValueAdjustment)); + CS.addConstraint(ConstraintKind::Conversion, memberTy, chainResultTy, + locator); + CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, + locator); - // If there is an argument, apply it. - if (auto arg = expr->getArgument()) { - // The result type of the function must be convertible to the base type. - // TODO: we definitely want this to include ImplicitlyUnwrappedOptional; - // does it need to include everything else in the world? - auto outputTy = CS.createTypeVariable( - CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult), - TVO_CanBindToNoEscape); - CS.addConstraint(ConstraintKind::Conversion, outputTy, baseTy, - CS.getConstraintLocator(expr, ConstraintLocator::RValueAdjustment)); - - // The function/enum case must be callable with the given argument. - - // FIXME: Redesign the AST so that an UnresolvedMemberExpr directly - // stores a list of arguments together with their inout-ness, instead of - // a single ParenExpr or TupleExpr argument. - SmallVector params; - AnyFunctionType::decomposeInput(CS.getType(arg), params); - - CS.addConstraint(ConstraintKind::ApplicableFunction, - FunctionType::get(params, outputTy), - memberTy, - CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction)); - - associateArgumentLabels( - CS.getConstraintLocator(expr), - {expr->getArgumentLabels(), - expr->getUnlabeledTrailingClosureIndex()}); - return baseTy; - } - - // Otherwise, the member needs to be convertible to the base type. - CS.addConstraint(ConstraintKind::Conversion, memberTy, baseTy, - CS.getConstraintLocator(expr, ConstraintLocator::RValueAdjustment)); - - // The member type also needs to be convertible to the context type, which - // preserves lvalue-ness. - auto resultTy = CS.createTypeVariable(memberLocator, - TVO_CanBindToLValue | - TVO_CanBindToNoEscape); - CS.addConstraint(ConstraintKind::Conversion, memberTy, resultTy, - memberLocator); - CS.addConstraint(ConstraintKind::Equal, resultTy, baseTy, - memberLocator); - return resultTy; + return chainResultTy; } Type visitUnresolvedDotExpr(UnresolvedDotExpr *expr) { @@ -2114,56 +2045,42 @@ namespace { } } - auto extInfo = FunctionType::ExtInfo(); - if (closureCanThrow(closure)) - extInfo = extInfo.withThrows(); + auto extInfo = closureEffects(closure); // Closure expressions always have function type. In cases where a // parameter or return type is omitted, a fresh type variable is used to // stand in for that parameter or return type, allowing it to be inferred // from context. - auto getExplicitResultType = [&]() -> Type { - if (!closure->hasExplicitResultType()) { - return Type(); - } + Type resultTy = [&] { + if (closure->hasExplicitResultType()) { + if (auto declaredTy = closure->getExplicitResultType()) { + return declaredTy; + } - if (auto declaredTy = closure->getExplicitResultType()) { - return declaredTy; + const auto resolvedTy = resolveTypeReferenceInExpression( + closure->getExplicitResultTypeRepr(), + TypeResolverContext::InExpression, + CS.getConstraintLocator(closure, + ConstraintLocator::ClosureResult)); + if (resolvedTy) + return resolvedTy; } - return resolveTypeReferenceInExpression( - closure->getExplicitResultTypeRepr(), - TypeResolverContext::InExpression, nullptr); - }; - - Type resultTy; - auto *resultLoc = - CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult); - if (auto explicityTy = getExplicitResultType()) { - resultTy = explicityTy; - } else { - auto getContextualResultType = [&]() -> Type { - if (auto contextualType = CS.getContextualType(closure)) { - if (auto fnType = contextualType->getAs()) - return fnType->getResult(); - } - return Type(); - }; - - if (auto contextualResultTy = getContextualResultType()) { - resultTy = contextualResultTy; - } else { - // If no return type was specified, create a fresh type - // variable for it and mark it as possible hole. - // - // If this is a multi-statement closure, let's mark result - // as potential hole right away. - resultTy = CS.createTypeVariable( - resultLoc, - shouldTypeCheckInEnclosingExpression(closure) - ? 0 : TVO_CanBindToHole); + if (auto contextualType = CS.getContextualType(closure)) { + if (auto fnType = contextualType->getAs()) + return fnType->getResult(); } - } + + // If no return type was specified, create a fresh type + // variable for it and mark it as possible hole. + // + // If this is a multi-statement closure, let's mark result + // as potential hole right away. + return Type(CS.createTypeVariable( + CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult), + shouldTypeCheckInEnclosingExpression(closure) ? 0 + : TVO_CanBindToHole)); + }(); return FunctionType::get(closureParams, resultTy, extInfo); } @@ -2249,6 +2166,12 @@ namespace { Type varType; + // Determine whether optionality will be required. + auto ROK = ReferenceOwnership::Strong; + if (auto *OA = var->getAttrs().getAttribute()) + ROK = OA->get(); + auto optionality = optionalityOf(ROK); + // If we have a type from an initializer expression, and that // expression does not produce an InOut type, use it. This // will avoid exponential typecheck behavior in the case of @@ -2257,18 +2180,17 @@ namespace { // FIXME: This should be handled in the solver, not here. // // Otherwise, create a new type variable. - bool assumedInitializerType = false; if (!var->hasNonPatternBindingInit() && - !var->hasAttachedPropertyWrapper()) { + !var->hasAttachedPropertyWrapper() && + optionality != ReferenceOwnershipOptionality::Required) { if (auto boundExpr = locator.trySimplifyToExpr()) { if (!boundExpr->isSemanticallyInOutExpr()) { varType = CS.getType(boundExpr)->getRValueType(); - assumedInitializerType = true; } } } - if (!assumedInitializerType) + if (!varType) varType = CS.createTypeVariable(CS.getConstraintLocator(locator), TVO_CanBindToNoEscape); @@ -2286,22 +2208,8 @@ namespace { // If there is an externally-imposed type. - auto ROK = ReferenceOwnership::Strong; - if (auto *OA = var->getAttrs().getAttribute()) - ROK = OA->get(); - switch (optionalityOf(ROK)) { + switch (optionality) { case ReferenceOwnershipOptionality::Required: - if (assumedInitializerType) { - // Already Optional - if (varType->getOptionalObjectType()) - break; - - // Create a fresh type variable to handle overloaded expressions. - if (varType->is()) - varType = CS.createTypeVariable(CS.getConstraintLocator(locator), - TVO_CanBindToNoEscape); - } - varType = TypeChecker::getOptionalType(var->getLoc(), varType); assert(!varType->hasError()); @@ -2437,9 +2345,7 @@ namespace { const Type castType = resolveTypeReferenceInExpression( isPattern->getCastTypeRepr(), TypeResolverContext::InExpression, - OpenUnboundGenericType(CS, - locator.withPathElement( - LocatorPathElt::PatternMatch(pattern)))); + locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); if (!castType) return Type(); auto *subPattern = isPattern->getSubPattern(); @@ -2490,32 +2396,31 @@ namespace { FunctionRefKind functionRefKind = FunctionRefKind::Compound; if (enumPattern->getParentType() || enumPattern->getParentTypeRepr()) { // Resolve the parent type. - Type parentType = [&]() -> Type { - if (auto preTy = enumPattern->getParentType()) { - return preTy; + const auto parentType = [&] { + auto *const patternMatchLoc = CS.getConstraintLocator( + locator, {LocatorPathElt::PatternMatch(pattern), + ConstraintLocator::ParentType}); + + // FIXME: Sometimes the parent type is realized eagerly in + // ResolvePattern::visitUnresolvedDotExpr, so we have to open it + // ex post facto. Remove this once we learn how to resolve patterns + // while generating constraints to keep the opening of generic types + // contained within the type resolver. + if (const auto preresolvedTy = enumPattern->getParentType()) { + const auto openedTy = + CS.openUnboundGenericTypes(preresolvedTy, patternMatchLoc); + assert(openedTy); + return openedTy; } + return resolveTypeReferenceInExpression( enumPattern->getParentTypeRepr(), - TypeResolverContext::InExpression, [](auto unboundTy) { - // FIXME: We ought to pass an OpenUnboundGenericType object - // rather than calling CS.openUnboundGenericType below, but - // sometimes the parent type is resolved eagerly in - // ResolvePattern::visitUnresolvedDotExpr, letting unbound - // generics escape. - return unboundTy; - }); + TypeResolverContext::InExpression, patternMatchLoc); }(); if (!parentType) return Type(); - parentType = CS.openUnboundGenericTypes( - parentType, CS.getConstraintLocator( - locator, {LocatorPathElt::PatternMatch(pattern), - ConstraintLocator::ParentType})); - - assert(parentType); - // Perform member lookup into the parent's metatype. Type parentMetaType = MetatypeType::get(parentType); CS.addValueMemberConstraint( @@ -2596,9 +2501,12 @@ namespace { return CS.getType(expr->getClosureBody()); } - /// Walk a closure AST to determine if it can throw. - bool closureCanThrow(ClosureExpr *expr) { - // A walker that looks for 'try' or 'throw' expressions + /// Walk a closure AST to determine its effects. + /// + /// \returns a function's extended info describing the effects, as + /// determined syntactically. + FunctionType::ExtInfo closureEffects(ClosureExpr *expr) { + // A walker that looks for 'try' and 'throw' expressions // that aren't nested within closures, nested declarations, // or exhaustive catches. class FindInnerThrows : public ASTWalker { @@ -2743,18 +2651,62 @@ namespace { bool foundThrow() { return FoundThrow; } }; - - if (expr->getThrowsLoc().isValid()) - return true; - + + // A walker that looks for 'async' and 'await' expressions + // that aren't nested within closures or nested declarations. + class FindInnerAsync : public ASTWalker { + bool FoundAsync = false; + + std::pair walkToExprPre(Expr *expr) override { + // If we've found an 'await', record it and terminate the traversal. + if (isa(expr)) { + FoundAsync = true; + return { false, nullptr }; + } + + // Do not recurse into other closures. + if (isa(expr)) + return { false, expr }; + + return { true, expr }; + } + + bool walkToDeclPre(Decl *decl) override { + // Do not walk into function or type declarations. + if (!isa(decl)) + return false; + + return true; + } + + public: + bool foundAsync() { return FoundAsync; } + }; + + // If either 'throws' or 'async' was explicitly specified, use that + // set of effects. + bool throws = expr->getThrowsLoc().isValid(); + bool async = expr->getAsyncLoc().isValid(); + if (throws || async) { + return ASTExtInfoBuilder() + .withThrows(throws) + .withAsync(async) + .build(); + } + + // Scan the body to determine the effects. auto body = expr->getBody(); - if (!body) - return false; - - auto tryFinder = FindInnerThrows(CS, expr); - body->walk(tryFinder); - return tryFinder.foundThrow(); + return FunctionType::ExtInfo(); + + auto throwFinder = FindInnerThrows(CS, expr); + body->walk(throwFinder); + auto asyncFinder = FindInnerAsync(); + body->walk(asyncFinder); + return ASTExtInfoBuilder() + .withThrows(throwFinder.foundThrow()) + .withAsync(asyncFinder.foundAsync()) + .build(); } Type visitClosureExpr(ClosureExpr *closure) { @@ -2797,10 +2749,17 @@ namespace { return { true, expr }; } } collectVarRefs(CS); + closure->walk(collectVarRefs); - if (collectVarRefs.hasErrorExprs) + // If walker discovered error expressions, let's fail constraint + // genreation only if closure is going to participate + // in the type-check. This allows us to delay validation of + // multi-statement closures until body is opened. + if (shouldTypeCheckInEnclosingExpression(closure) && + collectVarRefs.hasErrorExprs) { return Type(); + } auto inferredType = inferClosureType(closure); if (!inferredType || inferredType->hasError()) @@ -3005,8 +2964,7 @@ namespace { // Validate the resulting type. const auto toType = resolveTypeReferenceInExpression( repr, TypeResolverContext::ExplicitCastExpr, - // Introduce type variables for unbound generics. - OpenUnboundGenericType(CS, CS.getConstraintLocator(expr))); + CS.getConstraintLocator(expr)); if (!toType) return nullptr; @@ -3032,8 +2990,7 @@ namespace { auto *const repr = expr->getCastTypeRepr(); const auto toType = resolveTypeReferenceInExpression( repr, TypeResolverContext::ExplicitCastExpr, - // Introduce type variables for unbound generics. - OpenUnboundGenericType(CS, CS.getConstraintLocator(expr))); + CS.getConstraintLocator(expr)); if (!toType) return nullptr; @@ -3065,8 +3022,7 @@ namespace { auto *const repr = expr->getCastTypeRepr(); const auto toType = resolveTypeReferenceInExpression( repr, TypeResolverContext::ExplicitCastExpr, - // Introduce type variables for unbound generics. - OpenUnboundGenericType(CS, CS.getConstraintLocator(expr))); + CS.getConstraintLocator(expr)); if (!toType) return nullptr; @@ -3093,8 +3049,7 @@ namespace { auto &ctx = CS.getASTContext(); const auto toType = resolveTypeReferenceInExpression( expr->getCastTypeRepr(), TypeResolverContext::ExplicitCastExpr, - // Introduce type variables for unbound generics. - OpenUnboundGenericType(CS, CS.getConstraintLocator(expr))); + CS.getConstraintLocator(expr)); if (!toType) return nullptr; @@ -3302,9 +3257,9 @@ namespace { Type visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) { if (auto *placeholderRepr = E->getPlaceholderTypeRepr()) { // Just resolve the referenced type. - // FIXME: The type reference needs to be opened into context. return resolveTypeReferenceInExpression( - placeholderRepr, TypeResolverContext::InExpression, nullptr); + placeholderRepr, TypeResolverContext::InExpression, + CS.getConstraintLocator(E)); } auto locator = CS.getConstraintLocator(E); @@ -3375,9 +3330,7 @@ namespace { // If a root type was explicitly given, then resolve it now. if (auto rootRepr = E->getRootType()) { const auto rootObjectTy = resolveTypeReferenceInExpression( - rootRepr, TypeResolverContext::InExpression, - // Introduce type variables for unbound generics. - OpenUnboundGenericType(CS, locator)); + rootRepr, TypeResolverContext::InExpression, locator); if (!rootObjectTy || rootObjectTy->hasError()) return Type(); @@ -3699,6 +3652,7 @@ namespace { if (CG.getConstraintSystem().shouldReusePrecheckedType()) { if (expr->getType()) { assert(!expr->getType()->hasTypeVariable()); + assert(!expr->getType()->hasHole()); CG.getConstraintSystem().cacheType(expr); return { false, expr }; } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 6468c1e5a0cc1..afb594bc871eb 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2897,7 +2897,7 @@ static ConstraintFix *fixPropertyWrapperFailure( return nullptr; enum class Fix : uint8_t { - StorageWrapper, + ProjectedValue, PropertyWrapper, WrappedValue, }; @@ -2916,9 +2916,9 @@ static ConstraintFix *fixPropertyWrapperFailure( return nullptr; switch (fix) { - case Fix::StorageWrapper: + case Fix::ProjectedValue: case Fix::PropertyWrapper: - return UsePropertyWrapper::create(cs, decl, fix == Fix::StorageWrapper, + return UsePropertyWrapper::create(cs, decl, fix == Fix::ProjectedValue, baseTy, toType.getValueOr(type), locator); @@ -2929,10 +2929,10 @@ static ConstraintFix *fixPropertyWrapperFailure( llvm_unreachable("Unhandled Fix type in switch"); }; - if (auto storageWrapper = - cs.getStorageWrapperInformation(*resolvedOverload)) { - if (auto *fix = applyFix(Fix::StorageWrapper, storageWrapper->first, - storageWrapper->second)) + if (auto projection = + cs.getPropertyWrapperProjectionInfo(*resolvedOverload)) { + if (auto *fix = applyFix(Fix::ProjectedValue, projection->first, + projection->second)) return fix; } @@ -3829,8 +3829,11 @@ bool ConstraintSystem::repairFailures( // If this is an implicit 'something-to-pointer' conversion // it's going to be diagnosed by specialized fix which deals // with generic argument mismatches. - if (matchKind == ConstraintKind::BindToPointerType) - break; + if (matchKind == ConstraintKind::BindToPointerType) { + auto *member = rhs->getAs(); + if (!(member && member->getBase()->hasHole())) + break; + } // If this is a ~= operator implicitly generated by pattern matching // let's not try to fix right-hand side of the operator because it's @@ -4306,22 +4309,18 @@ bool ConstraintSystem::repairFailures( break; } - // Unresolved member type mismatches are handled when - // r-value adjustment constraint fails. - case ConstraintLocator::UnresolvedMember: + case ConstraintLocator::RValueAdjustment: return true; - case ConstraintLocator::RValueAdjustment: { - if (!isExpr(anchor)) - break; - + case ConstraintLocator::UnresolvedMemberChainResult: { if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes, locator)) break; - // r-value adjustment is used to connect base type of - // unresolved member to its output type, if there is - // a type mismatch here it's contextual e.g. + if (repairByTreatingRValueAsLValue(lhs, rhs)) + break; + + // If there is a type mismatch here it's contextual e.g., // `let x: E = .foo(42)`, where `.foo` is a member of `E` // but produces an incorrect type. auto *fix = IgnoreContextualType::create(*this, lhs, rhs, @@ -4434,6 +4433,12 @@ bool ConstraintSystem::repairFailures( } case ConstraintLocator::FunctionBuilderBodyResult: { + // If result type of the body couldn't be determined + // there is going to be other fix available to diagnose + // the underlying issue. + if (lhs->isHole()) + return true; + conversionsOrFixes.push_back(ContextualMismatch::create( *this, lhs, rhs, getConstraintLocator(locator))); break; @@ -4529,7 +4534,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, return formUnsolvedResult(); // Merge the equivalence classes corresponding to these two variables. - mergeEquivalenceClasses(rep1, rep2); + mergeEquivalenceClasses(rep1, rep2, /*updateWorkList=*/true); return getTypeMatchSuccess(); } @@ -4581,7 +4586,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, if (!rep1->getImpl().canBindToInOut() || !rep2->getImpl().canBindToLValue()) { // Merge the equivalence classes corresponding to these two variables. - mergeEquivalenceClasses(rep1, rep2); + mergeEquivalenceClasses(rep1, rep2, /*updateWorkList=*/true); return getTypeMatchSuccess(); } } @@ -4687,6 +4692,17 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, case TypeKind::Unresolved: return getTypeMatchFailure(locator); + case TypeKind::Hole: { + // If it's allowed to attempt fixes, let's delegate + // decision to `repairFailures`, since depending on + // locator we might either ignore such a mismatch, + // or record a specialized fix. + if (shouldAttemptFixes()) + break; + + return getTypeMatchFailure(locator); + } + case TypeKind::GenericTypeParam: llvm_unreachable("unmapped dependent type in type checker"); @@ -5366,6 +5382,7 @@ ConstraintSystem::simplifyConstructionConstraint( case TypeKind::Unresolved: case TypeKind::Error: + case TypeKind::Hole: return SolutionKind::Error; case TypeKind::GenericFunction: @@ -6759,28 +6776,39 @@ static ConstraintFix *validateInitializerRef(ConstraintSystem &cs, } else if (auto *CE = getAsExpr(anchor)) { baseExpr = CE->getFn(); baseType = getType(baseExpr); - // If this is an initializer call without explicit mention - // of `.init` on metatype value. - if (auto *AMT = baseType->getAs()) { - auto instanceType = AMT->getInstanceType()->getWithoutParens(); - if (!cs.isTypeReference(baseExpr)) { - if (baseType->is() && - instanceType->isAnyExistentialType()) { - return AllowInvalidInitRef::onProtocolMetatype( - cs, baseType, init, cs.isStaticallyDerivedMetatype(baseExpr), - baseExpr->getSourceRange(), locator); - } + // FIXME: Historically, UnresolvedMemberExprs have allowed implicit + // construction through a metatype value, but this should probably be + // illegal. + if (!isa(baseExpr)) { + // If this is an initializer call without explicit mention + // of `.init` on metatype value. + if (auto *AMT = baseType->getAs()) { + auto instanceType = AMT->getInstanceType()->getWithoutParens(); + if (!cs.isTypeReference(baseExpr)) { + if (baseType->is() && + instanceType->isAnyExistentialType()) { + return AllowInvalidInitRef::onProtocolMetatype( + cs, baseType, init, cs.isStaticallyDerivedMetatype(baseExpr), + baseExpr->getSourceRange(), locator); + } - if (!instanceType->isExistentialType() || - instanceType->isAnyExistentialType()) { - return AllowInvalidInitRef::onNonConstMetatype(cs, baseType, init, - locator); + if (!instanceType->isExistentialType() || + instanceType->isAnyExistentialType()) { + return AllowInvalidInitRef::onNonConstMetatype(cs, baseType, init, + locator); + } } } } // Initializer reference which requires contextual base type e.g. - // `.init(...)`. + // `.init(...)`. Could also be a nested type or typealias being constructed + // via implicit member syntax, e.g., `let _: Base = .Nested()` where + // `Base.Nested: Base`. } else if (auto *UME = getAsExpr(anchor)) { + // If we're accessing a nested type to perform the construction implicitly, + // then the type we're constructing may not actually be the base of the + // UnresolvedMemberExpr--instead, it will be the type of the nested type + // member. // We need to find type variable which represents contextual base. auto *baseLocator = cs.getConstraintLocator( UME, locatorEndsWith(locator, ConstraintLocator::ConstructorMember) @@ -6938,6 +6966,24 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint( auto locator = getConstraintLocator(locatorB); + auto formUnsolved = [&](bool activate = false) { + // If requested, generate a constraint. + if (flags.contains(TMF_GenerateConstraints)) { + auto *memberRef = Constraint::createMemberOrOuterDisjunction( + *this, kind, baseTy, memberTy, member, useDC, functionRefKind, + outerAlternatives, locator); + + addUnsolvedConstraint(memberRef); + + if (activate) + activateConstraint(memberRef); + + return SolutionKind::Solved; + } + + return SolutionKind::Unsolved; + }; + // If the base type of this member lookup is a "hole" there is no // reason to perform a lookup because it wouldn't return any results. if (shouldAttemptFixes()) { @@ -6949,15 +6995,57 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint( // If this is an unresolved member ref e.g. `.foo` and its contextual base // type has been determined to be a "hole", let's mark the resulting member // type as a potential hole and continue solving. - if (kind == ConstraintKind::UnresolvedValueMember && - baseObjTy->getMetatypeInstanceType()->isHole()) { - auto *fix = - SpecifyBaseTypeForContextualMember::create(*this, member, locator); - if (recordFix(fix)) - return SolutionKind::Error; + if (kind == ConstraintKind::UnresolvedValueMember) { + // Let's look through all metatypes to find "underlying" type + // of this lookup. + Type underlyingType = baseObjTy; + while (auto *MT = underlyingType->getAs()) { + underlyingType = MT->getInstanceType(); + } + + // Let's delay solving this constraint in diagnostic + // mode until it's certain that there is no way to + // find out what the base type is. + if (underlyingType->isTypeVariableOrMember()) + return formUnsolved(); - markMemberTypeAsPotentialHole(memberTy); - return SolutionKind::Solved; + // Let's record a fix only if the hole originates either + // at the result of the chain (that could happen since solving + // of this constraint is delayed until base could be resolved), + // or it is certain that base type can't be bound to any other + // type but a hole. + auto shouldRecordFixForHole = [&](HoleType *baseType) { + auto *originator = + baseType->getOriginatorType().dyn_cast(); + + if (!originator) + return false; + + auto *originatorLoc = originator->getImpl().getLocator(); + + // It could either be a hole associated directly with the base + // or a hole which came from result type of the chain. + if (originatorLoc->isLastElement< + LocatorPathElt::UnresolvedMemberChainResult>()) { + auto *UMCR = castToExpr( + originatorLoc->getAnchor()); + return UMCR->getChainBase() == getAsExpr(locator->getAnchor()); + } + + return originatorLoc == locator; + }; + + if (auto *hole = underlyingType->getAs()) { + if (shouldRecordFixForHole(hole)) { + auto *fix = SpecifyBaseTypeForContextualMember::create(*this, member, + locator); + if (recordFix(fix)) + return SolutionKind::Error; + } + + markMemberTypeAsPotentialHole(memberTy); + return SolutionKind::Solved; + } } else if ((kind == ConstraintKind::ValueMember || kind == ConstraintKind::ValueWitness) && baseObjTy->getMetatypeInstanceType()->isHole()) { @@ -6972,24 +7060,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint( performMemberLookup(kind, member, baseTy, functionRefKind, locator, /*includeInaccessibleMembers*/ shouldAttemptFixes()); - auto formUnsolved = [&](bool activate = false) { - // If requested, generate a constraint. - if (flags.contains(TMF_GenerateConstraints)) { - auto *memberRef = Constraint::createMemberOrOuterDisjunction( - *this, kind, baseTy, memberTy, member, useDC, functionRefKind, - outerAlternatives, locator); - - addUnsolvedConstraint(memberRef); - - if (activate) - activateConstraint(memberRef); - - return SolutionKind::Solved; - } - - return SolutionKind::Unsolved; - }; - switch (result.OverallResult) { case MemberLookupResult::Unsolved: return formUnsolved(); @@ -8127,6 +8197,14 @@ ConstraintSystem::simplifyKeyPathConstraint( if (keyPathTy->isHole()) return SolutionKind::Solved; + // If we have a malformed KeyPathExpr e.g. let _: KeyPath = \A + // let's record a AllowKeyPathMissingComponent fix. + if (keyPath->hasSingleInvalidComponent()) { + auto *fix = AllowKeyPathWithoutComponents::create( + *this, getConstraintLocator(locator)); + return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; + } + // If the root type has been bound to a hole, we cannot infer it. if (getFixedTypeRecursive(rootTy, /*wantRValue*/ true)->isHole()) return SolutionKind::Solved; @@ -9988,7 +10066,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::UnwrapOptionalBaseKeyPathApplication: case FixKind::AllowCoercionToForceCast: case FixKind::SpecifyKeyPathRootType: - case FixKind::SpecifyLabelToAssociateTrailingClosure: { + case FixKind::SpecifyLabelToAssociateTrailingClosure: + case FixKind::AllowKeyPathWithoutComponents: + case FixKind::IgnoreInvalidFunctionBuilderBody: { return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; } @@ -10647,7 +10727,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { case ConstraintKind::OptionalObject: return simplifyOptionalObjectConstraint(constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::ValueMember: @@ -10659,8 +10739,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { constraint.getMemberUseDC(), constraint.getFunctionRefKind(), /*outerAlternatives=*/{}, - TMF_GenerateConstraints, - constraint.getLocator()); + /*flags*/ None, constraint.getLocator()); case ConstraintKind::ValueWitness: return simplifyValueWitnessConstraint(constraint.getKind(), @@ -10669,20 +10748,20 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { constraint.getSecondType(), constraint.getMemberUseDC(), constraint.getFunctionRefKind(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::Defaultable: return simplifyDefaultableConstraint(constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::DefaultClosureType: return simplifyDefaultClosureTypeConstraint(constraint.getFirstType(), constraint.getSecondType(), constraint.getTypeVariables(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::FunctionInput: @@ -10690,7 +10769,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { return simplifyFunctionComponentConstraint(constraint.getKind(), constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::Disjunction: @@ -10702,8 +10781,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { return simplifyOneWayConstraint(constraint.getKind(), constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, - constraint.getLocator()); + /*flags*/ None, constraint.getLocator()); } llvm_unreachable("Unhandled ConstraintKind in switch."); diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 7af6590a65c0d..e48bf075b046b 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -450,11 +450,11 @@ ConstraintSystem::SolverState::~SolverState() { // Update the "largest" statistics if this system is larger than the // previous one. // FIXME: This is not at all thread-safe. - if (NumStatesExplored > LargestNumStatesExplored.Value) { - LargestSolutionAttemptNumber.Value = SolutionAttempt-1; + if (NumStatesExplored > LargestNumStatesExplored.getValue()) { + LargestSolutionAttemptNumber = SolutionAttempt-1; ++LargestSolutionAttemptNumber; #define CS_STATISTIC(Name, Description) \ - JOIN2(Largest,Name).Value = Name-1; \ + JOIN2(Largest,Name) = Name-1; \ ++JOIN2(Largest,Name); #include "ConstraintSolverStats.def" } @@ -1411,7 +1411,8 @@ void ConstraintSystem::solveForCodeCompletion( llvm::function_ref callback) { // First, pre-check the expression, validating any types that occur in the // expression and folding sequence expressions. - if (ConstraintSystem::preCheckExpression(expr, DC)) + if (ConstraintSystem::preCheckExpression( + expr, DC, /*replaceInvalidRefsWithErrors=*/true)) return; ConstraintSystemOptions options; @@ -1428,7 +1429,7 @@ void ConstraintSystem::solveForCodeCompletion( cs.shrink(expr); - if (cs.generateConstraints(expr, DC)) + if (!cs.generateConstraints(expr, DC)) return; llvm::SmallVector solutions; diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 4ff16a78a5ede..384cad9dcb45c 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -550,10 +550,11 @@ configureInheritedDesignatedInitAttributes(ClassDecl *classDecl, // If the superclass constructor is @objc but the subclass constructor is // not representable in Objective-C, add @nonobjc implicitly. + Optional asyncConvention; Optional errorConvention; if (superclassCtor->isObjC() && !isRepresentableInObjC(ctor, ObjCReason::MemberOfObjCSubclass, - errorConvention)) + asyncConvention, errorConvention)) ctor->getAttrs().add(new (ctx) NonObjCAttr(/*isImplicit=*/true)); } @@ -911,8 +912,8 @@ static bool canInheritDesignatedInits(Evaluator &eval, ClassDecl *decl) { static void collectNonOveriddenSuperclassInits( ClassDecl *subclass, SmallVectorImpl &results) { - auto superclassTy = subclass->getSuperclass(); - assert(superclassTy); + auto *superclassDecl = subclass->getSuperclassDecl(); + assert(superclassDecl); // Record all of the initializers the subclass has overriden, excluding stub // overrides, which we don't want to consider as viable delegates for @@ -924,11 +925,17 @@ static void collectNonOveriddenSuperclassInits( if (auto overridden = ctor->getOverriddenDecl()) overriddenInits.insert(overridden); - auto superclassCtors = TypeChecker::lookupConstructors( - subclass, superclassTy, NameLookupFlags::IgnoreAccessControl); + superclassDecl->synthesizeSemanticMembersIfNeeded( + DeclBaseName::createConstructor()); - for (auto memberResult : superclassCtors) { - auto superclassCtor = cast(memberResult.getValueDecl()); + NLOptions subOptions = (NL_QualifiedDefault | NL_IgnoreAccessControl); + SmallVector lookupResults; + subclass->lookupQualified( + superclassDecl, DeclNameRef::createConstructor(), + subOptions, lookupResults); + + for (auto decl : lookupResults) { + auto superclassCtor = cast(decl); // Skip invalid superclass initializers. if (superclassCtor->isInvalid()) @@ -958,12 +965,7 @@ static void addImplicitInheritedConstructorsToClass(ClassDecl *decl) { decl->setAddedImplicitInitializers(); // We can only inherit initializers if we have a superclass. - // FIXME: We should be bailing out earlier in the function, but unfortunately - // that currently regresses associated type inference for cases like - // compiler_crashers_2_fixed/0124-sr5825.swift due to the fact that we no - // longer eagerly compute the interface types of the other constructors. - auto superclassTy = decl->getSuperclass(); - if (!superclassTy) + if (!decl->getSuperclassDecl() || !decl->getSuperclass()) return; // Check whether the user has defined a designated initializer for this class, diff --git a/lib/Sema/ConstraintLocator.cpp b/lib/Sema/ConstraintLocator.cpp index d570c8983b13e..708d90d7dc6de 100644 --- a/lib/Sema/ConstraintLocator.cpp +++ b/lib/Sema/ConstraintLocator.cpp @@ -32,54 +32,7 @@ void ConstraintLocator::Profile(llvm::FoldingSetNodeID &id, ASTNode anchor, id.AddInteger(path.size()); for (auto elt : path) { id.AddInteger(elt.getKind()); - switch (elt.getKind()) { - case GenericParameter: - id.AddPointer(elt.castTo().getType()); - break; - - case ProtocolRequirement: { - auto reqElt = elt.castTo(); - id.AddPointer(reqElt.getDecl()); - break; - } - - case Witness: - id.AddPointer(elt.castTo().getDecl()); - break; - - case KeyPathDynamicMember: { - auto kpElt = elt.castTo(); - id.AddPointer(kpElt.getKeyPathDecl()); - break; - } - - case PatternMatch: - id.AddPointer(elt.castTo().getPattern()); - break; - - case ArgumentAttribute: - case GenericArgument: - case NamedTupleElement: - case TupleElement: - case ApplyArgToParam: - case OpenedGeneric: - case KeyPathComponent: - case ConditionalRequirement: - case TypeParameterRequirement: - case ContextualType: - case SynthesizedArgument: - case TernaryBranch: - case ClosureBody: { - auto numValues = numNumericValuesInPathElement(elt.getKind()); - for (unsigned i = 0; i < numValues; ++i) - id.AddInteger(elt.getValue(i)); - break; - } -#define SIMPLE_LOCATOR_PATH_ELT(Name) case Name : -#include "ConstraintLocatorPathElts.def" - // Nothing to do for simple locator elements. - break; - } + id.AddInteger(elt.getRawStorage()); } } @@ -128,6 +81,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const { case ConstraintLocator::TernaryBranch: case ConstraintLocator::PatternMatch: case ConstraintLocator::ArgumentAttribute: + case ConstraintLocator::UnresolvedMemberChainResult: return 0; case ConstraintLocator::FunctionArgument: @@ -530,6 +484,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const { break; } + + case UnresolvedMemberChainResult: + out << "unresolved chain result"; + break; } } out << ']'; diff --git a/lib/Sema/ConstraintLocator.h b/lib/Sema/ConstraintLocator.h index 0c3c3e1a432ce..fd5b07a155675 100644 --- a/lib/Sema/ConstraintLocator.h +++ b/lib/Sema/ConstraintLocator.h @@ -64,42 +64,6 @@ class ConstraintLocator : public llvm::FoldingSetNode { #include "ConstraintLocatorPathElts.def" }; - /// Determine the number of numeric values used for the given path - /// element kind. - static unsigned numNumericValuesInPathElement(PathElementKind kind) { - switch (kind) { -#define SIMPLE_LOCATOR_PATH_ELT(Name) case Name : -#include "ConstraintLocatorPathElts.def" - case GenericParameter: - case ProtocolRequirement: - case Witness: - case PatternMatch: - return 0; - - case ClosureBody: - case ContextualType: - case OpenedGeneric: - case GenericArgument: - case NamedTupleElement: - case TupleElement: - case KeyPathComponent: - case SynthesizedArgument: - case KeyPathDynamicMember: - case TernaryBranch: - case ArgumentAttribute: - return 1; - - case TypeParameterRequirement: - case ConditionalRequirement: - return 2; - - case ApplyArgToParam: - return 3; - } - - llvm_unreachable("Unhandled PathElementKind in switch."); - } - /// Flags for efficiently recording certain information about a path. /// All of this information should be re-derivable from the path. /// @@ -120,143 +84,24 @@ class ConstraintLocator : public llvm::FoldingSetNode { /// a kind (PathElementKind) and a value used to describe specific /// kinds further (e.g., the position of a tuple element). class PathElement { - /// Describes the kind of data stored here. - enum StoredKind : unsigned char { - StoredGenericParameter, - StoredProtocolRequirement, - StoredWitness, - StoredGenericSignature, - StoredKeyPathDynamicMemberBase, - StoredPattern, - StoredKindAndValue - }; - - /// The actual storage for the path element, which involves both a - /// kind and (potentially) a value. - /// - /// The current storage involves a two-bit "storage kind", which selects - /// among the possible value stores. The value stores can either be an - /// archetype (for archetype path elements) or an unsigned value that - /// stores both the specific kind and the (optional) numeric value of that - /// kind. Use \c encodeStorage and \c decodeStorage to work with this value. - /// - /// \note The "storage kind" is stored in the \c storedKind field. - uint64_t storage : 61; - - /// The kind of value stored in \c storage. Valid values are those - /// from the StoredKind enum. - uint64_t storedKind : 3; - - /// Encode a path element kind and a value into the storage format. - static uint64_t encodeStorage(PathElementKind kind, uint64_t value) { - return (value << 8) | kind; - } - - /// Decode a storage value into path element kind and value. - static std::pair - decodeStorage(uint64_t storage) { - return { (PathElementKind)((unsigned)storage & 0xFF), storage >> 8 }; - } - - /// Retrieve a value associated with the path element. - unsigned getValue(unsigned index) const { - unsigned numValues = numNumericValuesInPathElement(getKind()); - assert(index < numValues && "Index out of range for path element value"); - - // We pack values into 16 bit components of the storage, with value0 - // being stored in the upper bits, valueN in the lower bits. Therefore we - // need to shift out any extra values in the lower bits. - auto extraValues = numValues - index - 1; - auto value = decodeStorage(storage).second >> (extraValues * 16); - return value & 0xFFFF; - } + PathElementKind kind; - PathElement(PathElementKind kind, unsigned value) - : storage(encodeStorage(kind, value)), storedKind(StoredKindAndValue) - { - assert(numNumericValuesInPathElement(kind) == 1 && - "Path element kind does not require 1 value"); - assert(value == getValue(0) && "value truncated"); - } - - PathElement(PathElementKind kind, unsigned value0, unsigned value1) - : storage(encodeStorage(kind, value0 << 16 | value1)), - storedKind(StoredKindAndValue) - { - assert(numNumericValuesInPathElement(kind) == 2 && - "Path element kind does not require 2 values"); - assert(value0 == getValue(0) && "value0 truncated"); - assert(value1 == getValue(1) && "value1 truncated"); - } - - PathElement(PathElementKind kind, uint64_t value0, uint64_t value1, - uint64_t value2) - : storage(encodeStorage(kind, value0 << 32 | value1 << 16 | value2)), - storedKind(StoredKindAndValue) { - assert(numNumericValuesInPathElement(kind) == 3 && - "Path element kind does not require 3 values"); - assert(value0 == getValue(0) && "value0 truncated"); - assert(value1 == getValue(1) && "value1 truncated"); - assert(value2 == getValue(2) && "value2 truncated"); - } - - /// Store a path element with an associated pointer, accessible using - /// \c getStoredPointer. - template - PathElement(StoredKind storedKind, T *ptr) - : storage((reinterpret_cast(ptr) >> 3)), - storedKind(storedKind) { - assert(ptr == getStoredPointer()); - } - - /// Retrieve an associated pointer for the element. The type \c T must match - /// the type used when creating the path element. - template - T *getStoredPointer() const { - assert(storedKind != StoredKindAndValue); - return reinterpret_cast(storage << 3); - } - - friend class ConstraintLocator; + /// The storage for the path element value. The value stores can either + /// be a pointer or an unsigned int. Only custom path elements store values. + uint64_t storage; public: #define LOCATOR_PATH_ELT(Name) class Name; #include "ConstraintLocatorPathElts.def" - PathElement(PathElementKind kind) - : storage(encodeStorage(kind, 0)), storedKind(StoredKindAndValue) - { - assert(numNumericValuesInPathElement(kind) == 0 && - "Path element requires value"); - } + PathElement(PathElementKind kind, uint64_t storage = 0) + : kind(kind), storage(storage) {} /// Retrieve the kind of path element. - PathElementKind getKind() const { - switch (static_cast(storedKind)) { - case StoredGenericParameter: - return PathElementKind::GenericParameter; - - case StoredProtocolRequirement: - return PathElementKind::ProtocolRequirement; - - case StoredWitness: - return PathElementKind::Witness; - - case StoredGenericSignature: - return PathElementKind::OpenedGeneric; - - case StoredKeyPathDynamicMemberBase: - return PathElementKind::KeyPathDynamicMember; + PathElementKind getKind() const { return kind; } - case StoredPattern: - return PathElementKind::PatternMatch; - - case StoredKindAndValue: - return decodeStorage(storage).first; - } - - llvm_unreachable("Unhandled StoredKind in switch."); - } + /// Retrieve the raw storage value. + uint64_t getRawStorage() const { return storage; } /// Attempts to cast the path element to a specific \c LocatorPathElt /// subclass, returning \c None if unsuccessful. @@ -592,20 +437,76 @@ public: \ }; #include "ConstraintLocatorPathElts.def" +/// A base class for custom path elements that store numeric values. +template +class StoredIntegerElement: public LocatorPathElt { +public: + template ::type> + StoredIntegerElement(ConstraintLocator::PathElementKind kind, unsigned value) + : LocatorPathElt(kind, value) { + assert(value == getValue<0>() && "value truncated"); + } + + template ::type> + StoredIntegerElement(ConstraintLocator::PathElementKind kind, unsigned value0, unsigned value1) + : LocatorPathElt(kind, (value0 << 16 | value1)) { + assert(value0 == getValue<0>() && "value0 truncated"); + assert(value1 == getValue<1>() && "value1 truncated"); + } + + template ::type> + StoredIntegerElement(ConstraintLocator::PathElementKind kind, unsigned value0, + unsigned value1, unsigned value2) + : LocatorPathElt(kind, uint64_t(value0) << 32 | uint64_t(value1) << 16 | uint64_t(value2)) { + assert(value0 == getValue<0>() && "value0 truncated"); + assert(value1 == getValue<1>() && "value1 truncated"); + assert(value2 == getValue<2>() && "value2 truncated"); + } + + /// Retrieve a value associated with the path element. + template ::type> + unsigned getValue() const { + // We pack values into 16 bit components of the storage, with value0 + // being stored in the upper bits, valueN in the lower bits. Therefore we + // need to shift out any extra values in the lower bits. + auto extraValues = NumValues - Index - 1; + auto value = getRawStorage() >> (extraValues * 16); + return value & 0xFFFF; + } +}; + +/// A base class for custom path elements that store a pointer. +template +class StoredPointerElement: public LocatorPathElt { +public: + StoredPointerElement(ConstraintLocator::PathElementKind kind, const T *ptr) + : LocatorPathElt(kind, reinterpret_cast(ptr)) { + assert(ptr == getStoredPointer()); + } + + /// Retrieve the associated pointer for the element. + T *getStoredPointer() const { return reinterpret_cast(getRawStorage()); } +}; + // The following LocatorPathElt subclasses are used to expose accessors for // specific path element information. They shouldn't introduce additional -// storage, as LocatorPathElt gets passed about by value. +// storage, as LocatorPathElt gets passed about by value. Custom path elements +// should subclass StoredIntegerElement to store unsigned values, or StoredPointerElement +// to store pointer values. -class LocatorPathElt::ApplyArgToParam final : public LocatorPathElt { +class LocatorPathElt::ApplyArgToParam final : public StoredIntegerElement<3> { public: ApplyArgToParam(unsigned argIdx, unsigned paramIdx, ParameterTypeFlags flags) - : LocatorPathElt(ConstraintLocator::ApplyArgToParam, argIdx, paramIdx, - flags.toRaw()) {} + : StoredIntegerElement(ConstraintLocator::ApplyArgToParam, argIdx, paramIdx, flags.toRaw()) {} - unsigned getArgIdx() const { return getValue(0); } - unsigned getParamIdx() const { return getValue(1); } + unsigned getArgIdx() const { return getValue<0>(); } + unsigned getParamIdx() const { return getValue<1>(); } ParameterTypeFlags getParameterFlags() const { - return ParameterTypeFlags::fromRaw(getValue(2)); + return ParameterTypeFlags::fromRaw(getValue<2>()); } static bool classof(const LocatorPathElt *elt) { @@ -613,12 +514,12 @@ class LocatorPathElt::ApplyArgToParam final : public LocatorPathElt { } }; -class LocatorPathElt::SynthesizedArgument final : public LocatorPathElt { +class LocatorPathElt::SynthesizedArgument final : public StoredIntegerElement<1> { public: SynthesizedArgument(unsigned index) - : LocatorPathElt(ConstraintLocator::SynthesizedArgument, index) {} + : StoredIntegerElement(ConstraintLocator::SynthesizedArgument, index) {} - unsigned getIndex() const { return getValue(0); } + unsigned getIndex() const { return getValue(); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::SynthesizedArgument; @@ -626,15 +527,15 @@ class LocatorPathElt::SynthesizedArgument final : public LocatorPathElt { }; /// Abstract superclass for any kind of tuple element. -class LocatorPathElt::AnyTupleElement : public LocatorPathElt { +class LocatorPathElt::AnyTupleElement : public StoredIntegerElement<1> { protected: AnyTupleElement(PathElementKind kind, unsigned index) - : LocatorPathElt(kind, index) { + : StoredIntegerElement(kind, index) { assert(classof(this) && "classof needs updating"); } public: - unsigned getIndex() const { return getValue(0); } + unsigned getIndex() const { return getValue(); } static bool classof(const LocatorPathElt *elt) { return elt->is() || @@ -664,24 +565,24 @@ class LocatorPathElt::NamedTupleElement final } }; -class LocatorPathElt::KeyPathComponent final : public LocatorPathElt { +class LocatorPathElt::KeyPathComponent final : public StoredIntegerElement<1> { public: KeyPathComponent(unsigned index) - : LocatorPathElt(ConstraintLocator::KeyPathComponent, index) {} + : StoredIntegerElement(ConstraintLocator::KeyPathComponent, index) {} - unsigned getIndex() const { return getValue(0); } + unsigned getIndex() const { return getValue(); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::KeyPathComponent; } }; -class LocatorPathElt::GenericArgument final : public LocatorPathElt { +class LocatorPathElt::GenericArgument final : public StoredIntegerElement<1> { public: GenericArgument(unsigned index) - : LocatorPathElt(ConstraintLocator::GenericArgument, index) {} + : StoredIntegerElement(ConstraintLocator::GenericArgument, index) {} - unsigned getIndex() const { return getValue(0); } + unsigned getIndex() const { return getValue(); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::GenericArgument; @@ -690,17 +591,17 @@ class LocatorPathElt::GenericArgument final : public LocatorPathElt { /// Abstract superclass for any kind of element that describes a requirement /// placed on a type within a requirements clause. -class LocatorPathElt::AnyRequirement : public LocatorPathElt { +class LocatorPathElt::AnyRequirement : public StoredIntegerElement<2> { protected: AnyRequirement(PathElementKind kind, unsigned index, RequirementKind reqKind) - : LocatorPathElt(kind, index, static_cast(reqKind)) { + : StoredIntegerElement(kind, index, static_cast(reqKind)) { assert(classof(this) && "classof needs updating"); } public: - unsigned getIndex() const { return getValue(0); } + unsigned getIndex() const { return getValue<0>(); } RequirementKind getRequirementKind() const { - return static_cast(getValue(1)); + return static_cast(getValue<1>()); } static bool classof(const LocatorPathElt *elt) { @@ -733,84 +634,81 @@ class LocatorPathElt::TypeParameterRequirement final } }; -class LocatorPathElt::ClosureBody final : public LocatorPathElt { +class LocatorPathElt::ClosureBody final : public StoredIntegerElement<1> { public: ClosureBody(bool hasExplicitReturn = false) - : LocatorPathElt(ConstraintLocator::ClosureBody, - hasExplicitReturn) {} + : StoredIntegerElement(ConstraintLocator::ClosureBody, hasExplicitReturn) {} /// Indicates whether body of the closure has any `return` statements. - bool hasExplicitReturn() const { return bool(getValue(0)); } + bool hasExplicitReturn() const { return bool(getValue()); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::ClosureBody; } }; -class LocatorPathElt::ContextualType final : public LocatorPathElt { +class LocatorPathElt::ContextualType final : public StoredIntegerElement<1> { public: ContextualType(bool isForSingleExprFunction = false) - : LocatorPathElt(ConstraintLocator::ContextualType, - isForSingleExprFunction) {} + : StoredIntegerElement(ConstraintLocator::ContextualType, isForSingleExprFunction) {} /// Whether this element points to the contextual type associated with the /// result of a single expression function. - bool isForSingleExprFunction() const { return bool(getValue(0)); } + bool isForSingleExprFunction() const { return bool(getValue()); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::ContextualType; } }; -class LocatorPathElt::Witness final : public LocatorPathElt { +class LocatorPathElt::Witness final : public StoredPointerElement { public: Witness(ValueDecl *witness) - : LocatorPathElt(LocatorPathElt::StoredWitness, witness) {} + : StoredPointerElement(PathElementKind::Witness, witness) {} - ValueDecl *getDecl() const { return getStoredPointer(); } + ValueDecl *getDecl() const { return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { - return elt->getKind() == ConstraintLocator::Witness; + return elt->getKind() == PathElementKind::Witness; } }; -class LocatorPathElt::ProtocolRequirement final : public LocatorPathElt { +class LocatorPathElt::ProtocolRequirement final : public StoredPointerElement { public: ProtocolRequirement(ValueDecl *decl) - : LocatorPathElt(LocatorPathElt::StoredProtocolRequirement, decl) {} + : StoredPointerElement(PathElementKind::ProtocolRequirement, decl) {} - ValueDecl *getDecl() const { return getStoredPointer(); } + ValueDecl *getDecl() const { return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { - return elt->getKind() == ConstraintLocator::ProtocolRequirement; + return elt->getKind() == PathElementKind::ProtocolRequirement; } }; -class LocatorPathElt::GenericParameter final : public LocatorPathElt { +class LocatorPathElt::GenericParameter final : public StoredPointerElement { public: GenericParameter(GenericTypeParamType *type) - : LocatorPathElt(LocatorPathElt::StoredGenericParameter, type) { + : StoredPointerElement(PathElementKind::GenericParameter, type) { static_assert(alignof(GenericTypeParamType) >= 4, "archetypes insufficiently aligned"); } GenericTypeParamType *getType() const { - return getStoredPointer(); + return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { - return elt->getKind() == ConstraintLocator::GenericParameter; + return elt->getKind() == PathElementKind::GenericParameter; } }; -class LocatorPathElt::OpenedGeneric final : public LocatorPathElt { +class LocatorPathElt::OpenedGeneric final : public StoredPointerElement { public: OpenedGeneric(GenericSignature sig) - : LocatorPathElt(LocatorPathElt::StoredGenericSignature, - sig.getPointer()) {} + : StoredPointerElement(PathElementKind::OpenedGeneric, sig.getPointer()) {} GenericSignature getSignature() const { - return getStoredPointer(); + return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { @@ -818,14 +716,13 @@ class LocatorPathElt::OpenedGeneric final : public LocatorPathElt { } }; -class LocatorPathElt::KeyPathDynamicMember final : public LocatorPathElt { +class LocatorPathElt::KeyPathDynamicMember final : public StoredPointerElement { public: KeyPathDynamicMember(NominalTypeDecl *keyPathDecl) - : LocatorPathElt(LocatorPathElt::StoredKeyPathDynamicMemberBase, - keyPathDecl) {} + : StoredPointerElement(PathElementKind::KeyPathDynamicMember, keyPathDecl) {} NominalTypeDecl *getKeyPathDecl() const { - return getStoredPointer(); + return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { @@ -833,43 +730,42 @@ class LocatorPathElt::KeyPathDynamicMember final : public LocatorPathElt { } }; -class LocatorPathElt::TernaryBranch final : public LocatorPathElt { +class LocatorPathElt::TernaryBranch final : public StoredIntegerElement<1> { public: TernaryBranch(bool side) - : LocatorPathElt(ConstraintLocator::TernaryBranch, side) {} + : StoredIntegerElement(ConstraintLocator::TernaryBranch, side) {} - bool forThen() const { return bool(getValue(0)); } + bool forThen() const { return bool(getValue()); } - bool forElse() const { return !bool(getValue(0)); } + bool forElse() const { return !bool(getValue()); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::TernaryBranch; } }; -class LocatorPathElt::PatternMatch final : public LocatorPathElt { +class LocatorPathElt::PatternMatch final : public StoredPointerElement { public: PatternMatch(Pattern *pattern) - : LocatorPathElt(LocatorPathElt::StoredPattern, pattern) {} + : StoredPointerElement(PathElementKind::PatternMatch, pattern) {} - Pattern *getPattern() const { return getStoredPointer(); } + Pattern *getPattern() const { return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::PatternMatch; } }; -class LocatorPathElt::ArgumentAttribute final : public LocatorPathElt { +class LocatorPathElt::ArgumentAttribute final : public StoredIntegerElement<1> { public: enum Attribute : uint8_t { InOut, Escaping }; private: ArgumentAttribute(Attribute attr) - : LocatorPathElt(ConstraintLocator::ArgumentAttribute, - static_cast(attr)) {} + : StoredIntegerElement(ConstraintLocator::ArgumentAttribute, static_cast(attr)) {} public: - Attribute getAttr() const { return static_cast(getValue(0)); } + Attribute getAttr() const { return static_cast(getValue()); } static ArgumentAttribute forInOut() { return ArgumentAttribute(Attribute::InOut); @@ -884,6 +780,36 @@ class LocatorPathElt::ArgumentAttribute final : public LocatorPathElt { } }; +namespace details { + template + class PathElement { + static constexpr bool hasStoredValueImpl(...) { return false; } + + template + static constexpr bool hasStoredValueImpl(StoredIntegerElement *) { return true; } + + template + static constexpr bool hasStoredValueImpl(StoredPointerElement *) { return true; } + + public: + static constexpr bool hasStoredValue() { + return hasStoredValueImpl(static_cast(nullptr)); + } + }; +} + +template +constexpr bool isValidCustomPathElement() { + return details::PathElement::hasStoredValue(); +} + +// All custom path element classes must inherit from StoredIntegerElement or StoredPointerElement +#define CUSTOM_LOCATOR_PATH_ELT(Name) \ +static_assert(isValidCustomPathElement(), \ + "Custom path elements must inherit from StoredIntegerElement or StoredPointerElement"); +#include "ConstraintLocatorPathElts.def" + + /// A simple stack-only builder object that constructs a /// constraint locator without allocating memory. /// diff --git a/lib/Sema/ConstraintLocatorPathElts.def b/lib/Sema/ConstraintLocatorPathElts.def index 67228bcbc5591..435d20b74ec9f 100644 --- a/lib/Sema/ConstraintLocatorPathElts.def +++ b/lib/Sema/ConstraintLocatorPathElts.def @@ -192,6 +192,9 @@ CUSTOM_LOCATOR_PATH_ELT(PatternMatch) /// of a problem. CUSTOM_LOCATOR_PATH_ELT(ArgumentAttribute) +/// The result of a chain of member accesses off an UnresolvedMemberExpr +SIMPLE_LOCATOR_PATH_ELT(UnresolvedMemberChainResult) + #undef LOCATOR_PATH_ELT #undef CUSTOM_LOCATOR_PATH_ELT #undef SIMPLE_LOCATOR_PATH_ELT diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 1214740c8d1d5..11adbd6b897a6 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -562,21 +562,7 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator( } if (auto *UME = getAsExpr(anchor)) { - auto *calleeLoc = - getConstraintLocator(UME, ConstraintLocator::UnresolvedMember); - - // Handle special cases for applies of non-function types. - // FIXME: Consider re-designing the AST such that an unresolved member expr - // with arguments uses a CallExpr, which would make this logic unnecessary - // and clean up a bunch of other special cases. Doing so may require a bit - // of hacking in CSGen though. - if (UME->hasArguments()) { - if (auto overload = getOverloadFor(calleeLoc)) { - if (auto *loc = getSpecialFnCalleeLoc(overload->boundType)) - return loc; - } - } - return calleeLoc; + return getConstraintLocator(UME, ConstraintLocator::UnresolvedMember); } if (isExpr(anchor)) @@ -970,7 +956,7 @@ getPropertyWrapperInformationFromOverload( } Optional> -ConstraintSystem::getStorageWrapperInformation( +ConstraintSystem::getPropertyWrapperProjectionInfo( SelectedOverload resolvedOverload) { return getPropertyWrapperInformationFromOverload( resolvedOverload, DC, @@ -978,12 +964,12 @@ ConstraintSystem::getStorageWrapperInformation( if (!decl->hasAttachedPropertyWrapper()) return None; - auto storageWrapper = decl->getPropertyWrapperStorageWrapper(); - if (!storageWrapper) + auto projectionVar = decl->getPropertyWrapperProjectionVar(); + if (!projectionVar) return None; - return std::make_pair(storageWrapper, - storageWrapper->getInterfaceType()); + return std::make_pair(projectionVar, + projectionVar->getInterfaceType()); }); } @@ -2617,11 +2603,13 @@ Type ConstraintSystem::simplifyTypeImpl(Type type, // there will be a missing conformance fix applied in diagnostic mode, // so the concrete dependent member type is considered a "hole" in // order to continue solving. + auto memberTy = DependentMemberType::get(lookupBaseType, assocType); if (shouldAttemptFixes() && - getPhase() == ConstraintSystemPhase::Solving) - return getASTContext().TheUnresolvedType; + getPhase() == ConstraintSystemPhase::Solving) { + return HoleType::get(getASTContext(), memberTy); + } - return DependentMemberType::get(lookupBaseType, assocType); + return memberTy; } auto subs = SubstitutionMap::getProtocolSubstitutions( @@ -2653,16 +2641,23 @@ Type ConstraintSystem::simplifyType(Type type) const { } Type Solution::simplifyType(Type type) const { - if (!type->hasTypeVariable()) + if (!(type->hasTypeVariable() || type->hasHole())) return type; // Map type variables to fixed types from bindings. - return getConstraintSystem().simplifyTypeImpl(type, - [&](TypeVariableType *tvt) -> Type { - auto known = typeBindings.find(tvt); - assert(known != typeBindings.end()); - return known->second; - }); + auto &cs = getConstraintSystem(); + auto resolvedType = cs.simplifyTypeImpl( + type, [&](TypeVariableType *tvt) -> Type { return getFixedType(tvt); }); + + // Holes shouldn't be reachable through a solution, they are only + // useful to determine what went wrong exactly. + if (resolvedType->hasHole()) { + return resolvedType.transform([&](Type type) { + return type->isHole() ? Type(cs.getASTContext().TheUnresolvedType) : type; + }); + } + + return resolvedType; } size_t Solution::getTotalMemory() const { @@ -3153,9 +3148,7 @@ static bool diagnoseAmbiguityWithContextualType( auto type = solution.simplifyType(overload.boundType); - if (isExpr(anchor) || isExpr(anchor) || - (isExpr(anchor) && - castToExpr(anchor)->hasArguments())) { + if (isExpr(anchor) || isExpr(anchor)) { auto fnType = type->castTo(); DE.diagnose( loc, diag::cannot_convert_candidate_result_to_contextual_type, @@ -3665,11 +3658,6 @@ void constraints::simplifyLocator(ASTNode &anchor, continue; } - if (auto *UME = getAsExpr(anchor)) { - anchor = UME->getArgument(); - path = path.slice(1); - continue; - } break; } @@ -3679,6 +3667,7 @@ void constraints::simplifyLocator(ASTNode &anchor, } case ConstraintLocator::ApplyFunction: + case ConstraintLocator::FunctionResult: // Extract application function. if (auto applyExpr = getAsExpr(anchor)) { anchor = applyExpr->getFn(); @@ -3693,15 +3682,6 @@ void constraints::simplifyLocator(ASTNode &anchor, continue; } - // The unresolved member itself is the function. - if (auto unresolvedMember = getAsExpr(anchor)) { - if (unresolvedMember->getArgument()) { - anchor = unresolvedMember; - path = path.slice(1); - continue; - } - } - break; case ConstraintLocator::AutoclosureResult: @@ -3858,6 +3838,13 @@ void constraints::simplifyLocator(ASTNode &anchor, break; } + case ConstraintLocator::UnresolvedMemberChainResult: { + auto *resultExpr = castToExpr(anchor); + anchor = resultExpr->getSubExpr(); + path = path.slice(1); + continue; + } + default: // FIXME: Lots of other cases to handle. break; @@ -3890,8 +3877,6 @@ Expr *constraints::getArgumentExpr(ASTNode node, unsigned index) { Expr *argExpr = nullptr; if (auto *AE = dyn_cast(expr)) argExpr = AE->getArg(); - else if (auto *UME = dyn_cast(expr)) - argExpr = UME->getArgument(); else if (auto *SE = dyn_cast(expr)) argExpr = SE->getIndex(); else @@ -4646,7 +4631,7 @@ SolutionApplicationTarget SolutionApplicationTarget::forInitialization( // Determine the contextual type for the initialization. TypeLoc contextualType; if (!(isa(pattern) && !pattern->isImplicit()) && - patternType && !patternType->isHole()) { + patternType && !patternType->is()) { contextualType = TypeLoc::withoutLoc(patternType); // Only provide a TypeLoc if it makes sense to allow diagnostics. diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 4e4924a0bc78b..eff529ac6e26f 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -1190,6 +1190,11 @@ class Solution { /// Retrieve the type of the given node, as recorded in this solution. Type getType(ASTNode node) const; + /// Retrieve the type of the given node as recorded in this solution + /// and resolve all of the type variables in contains to form a fully + /// "resolved" concrete type. + Type getResolvedType(ASTNode node) const; + /// Resolve type variables present in the raw type, using generic parameter /// types where possible. Type resolveInterfaceType(Type type) const; @@ -1210,6 +1215,16 @@ class Solution { : nullptr; } + /// This method implements functionality of `Expr::isTypeReference` + /// with data provided by a given solution. + bool isTypeReference(Expr *E) const; + + /// Call Expr::isIsStaticallyDerivedMetatype on the given + /// expression, using a custom accessor for the type on the + /// expression that reads the type from the Solution + /// expression type map. + bool isStaticallyDerivedMetatype(Expr *E) const; + SWIFT_DEBUG_DUMP; /// Dump this solution. @@ -2010,6 +2025,13 @@ class ConstraintSystem { /// from declared parameters/result and body. llvm::MapVector ClosureTypes; + /// This is a *global* list of all function builder bodies that have + /// been determined to be incorrect by failing constraint generation. + /// + /// Tracking this information is useful to avoid producing duplicate + /// diagnostics when function builder has multiple overloads. + llvm::SmallDenseSet InvalidFunctionBuilderBodies; + /// Maps node types used within all portions of the constraint /// system, instead of directly using the types on the /// nodes themselves. This allows us to typecheck and @@ -3147,7 +3169,7 @@ class ConstraintSystem { if (originalRep) { if (originalRep != currentRep) - mergeEquivalenceClasses(currentRep, originalRep); + mergeEquivalenceClasses(currentRep, originalRep, /*updateWorkList=*/false); continue; } @@ -3421,9 +3443,9 @@ class ConstraintSystem { ConstraintLocator::PathElementKind kind) const; /// Gets the VarDecl associateed with resolvedOverload, and the type of the - /// storage wrapper if the decl has an associated storage wrapper. + /// projection if the decl has an associated property wrapper with a projectedValue. Optional> - getStorageWrapperInformation(SelectedOverload resolvedOverload); + getPropertyWrapperProjectionInfo(SelectedOverload resolvedOverload); /// Gets the VarDecl associateed with resolvedOverload, and the type of the /// backing storage if the decl has an associated property wrapper. @@ -3443,7 +3465,7 @@ class ConstraintSystem { /// distinct. void mergeEquivalenceClasses(TypeVariableType *typeVar1, TypeVariableType *typeVar2, - bool updateWorkList = true); + bool updateWorkList); /// Flags that direct type matching. enum TypeMatchFlags { @@ -4549,9 +4571,10 @@ class ConstraintSystem { return {type, kind, BindingSource}; } - static PotentialBinding forHole(ASTContext &ctx, + static PotentialBinding forHole(TypeVariableType *typeVar, ConstraintLocator *locator) { - return {ctx.TheUnresolvedType, AllowedBindingKind::Exact, + return {HoleType::get(typeVar->getASTContext(), typeVar), + AllowedBindingKind::Exact, /*source=*/locator}; } }; @@ -4705,6 +4728,7 @@ class ConstraintSystem { /// if it has only concrete types or would resolve a closure. bool favoredOverDisjunction(Constraint *disjunction) const; +private: /// Detect `subtype` relationship between two type variables and /// attempt to infer supertype bindings transitively e.g. /// @@ -4717,19 +4741,25 @@ class ConstraintSystem { /// \param inferredBindings The set of all bindings inferred for type /// variables in the workset. void inferTransitiveBindings( - ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes, + const ConstraintSystem &cs, + llvm::SmallPtrSetImpl &existingTypes, const llvm::SmallDenseMap &inferredBindings); /// Infer bindings based on any protocol conformances that have default /// types. - void inferDefaultTypes(ConstraintSystem &cs, + void inferDefaultTypes(const ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes); +public: + bool infer(const ConstraintSystem &cs, + llvm::SmallPtrSetImpl &exactTypes, + Constraint *constraint); + /// Finalize binding computation for this type variable by /// inferring bindings from context e.g. transitive bindings. - void finalize(ConstraintSystem &cs, + void finalize(const ConstraintSystem &cs, const llvm::SmallDenseMap &inferredBindings); @@ -4797,14 +4827,13 @@ class ConstraintSystem { /// Infer bindings for the given type variable based on current /// state of the constraint system. - PotentialBindings inferBindingsFor(TypeVariableType *typeVar); + PotentialBindings inferBindingsFor(TypeVariableType *typeVar, + bool finalize = true) const; private: Optional - getPotentialBindingForRelationalConstraint( - PotentialBindings &result, Constraint *constraint, - bool &hasDependentMemberRelationalConstraints, - bool &hasNonDependentMemberRelationalConstraints) const; + getPotentialBindingForRelationalConstraint(PotentialBindings &result, + Constraint *constraint) const; PotentialBindings getPotentialBindings(TypeVariableType *typeVar) const; /// Add a constraint to the constraint system. @@ -4934,8 +4963,12 @@ class ConstraintSystem { public: /// Pre-check the expression, validating any types that occur in the /// expression and folding sequence expressions. - static bool preCheckExpression(Expr *&expr, DeclContext *dc); - + /// + /// \param replaceInvalidRefsWithErrors Indicates whether it's allowed + /// to replace any discovered invalid member references with `ErrorExpr`. + static bool preCheckExpression(Expr *&expr, DeclContext *dc, + bool replaceInvalidRefsWithErrors); + /// Solve the system of constraints generated from provided target. /// /// \param target The target that we'll generate constraints from, which diff --git a/lib/Sema/DebuggerTestingTransform.cpp b/lib/Sema/DebuggerTestingTransform.cpp index 082c9b6190b52..61484a57a0d77 100644 --- a/lib/Sema/DebuggerTestingTransform.cpp +++ b/lib/Sema/DebuggerTestingTransform.cpp @@ -227,8 +227,8 @@ class DebuggerTestingTransform : public ASTWalker { auto *Params = ParameterList::createEmpty(Ctx); auto *Closure = new (Ctx) ClosureExpr(SourceRange(), nullptr, Params, SourceLoc(), SourceLoc(), - SourceLoc(), nullptr, DF.getNextDiscriminator(), - getCurrentDeclContext()); + SourceLoc(), SourceLoc(), nullptr, + DF.getNextDiscriminator(), getCurrentDeclContext()); Closure->setImplicit(true); // TODO: Save and return the value of $OriginalExpr. diff --git a/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp b/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp index baddb7fcfd470..353980ddde7af 100644 --- a/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp +++ b/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp @@ -190,14 +190,12 @@ static ValueDecl *deriveMathOperator(DerivedConformance &derived, auto operatorId = C.getIdentifier(getMathOperatorName(op)); DeclName operatorDeclName(C, operatorId, params); - auto operatorDecl = - FuncDecl::create(C, SourceLoc(), StaticSpellingKind::KeywordStatic, - SourceLoc(), operatorDeclName, SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws*/ false, SourceLoc(), - /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(selfInterfaceType), parentDC); - operatorDecl->setImplicit(); + auto *const operatorDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::KeywordStatic, operatorDeclName, + /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/false, + /*GenericParams=*/nullptr, params, selfInterfaceType, parentDC); auto bodySynthesizer = [](AbstractFunctionDecl *funcDecl, void *ctx) -> std::pair { auto op = (MathOperator) reinterpret_cast(ctx); diff --git a/lib/Sema/DerivedConformanceCaseIterable.cpp b/lib/Sema/DerivedConformanceCaseIterable.cpp index 14d3309936918..bc809b4e53930 100644 --- a/lib/Sema/DerivedConformanceCaseIterable.cpp +++ b/lib/Sema/DerivedConformanceCaseIterable.cpp @@ -69,6 +69,15 @@ static ArraySliceType *computeAllCasesType(NominalTypeDecl *enumDecl) { return ArraySliceType::get(enumType); } +static Type deriveCaseIterable_AllCases(DerivedConformance &derived) { + // enum SomeEnum : CaseIterable { + // @derived + // typealias AllCases = [SomeEnum] + // } + auto *rawInterfaceType = computeAllCasesType(cast(derived.Nominal)); + return derived.getConformanceContext()->mapTypeIntoContext(rawInterfaceType); +} + ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) { // Conformance can't be synthesized in an extension. if (checkAndDiagnoseDisallowedContext(requirement)) @@ -102,3 +111,18 @@ ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) { return propDecl; } + +Type DerivedConformance::deriveCaseIterable(AssociatedTypeDecl *assocType) { + // Check that we can actually derive CaseIterable for this type. + if (!canDeriveConformance(Nominal)) + return nullptr; + + if (assocType->getName() == Context.Id_AllCases) { + return deriveCaseIterable_AllCases(*this); + } + + Context.Diags.diagnose(assocType->getLoc(), + diag::broken_case_iterable_requirement); + return nullptr; +} + diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index 701189126dc34..f903cd126b215 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -626,12 +626,11 @@ static FuncDecl *deriveEncodable_encode(DerivedConformance &derived) { // Func name: encode(to: Encoder) DeclName name(C, C.Id_encode, params); - auto *encodeDecl = FuncDecl::create( - C, SourceLoc(), StaticSpellingKind::None, SourceLoc(), name, SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws=*/true, SourceLoc(), nullptr, params, - TypeLoc::withoutLoc(returnType), conformanceDC); - encodeDecl->setImplicit(); + auto *const encodeDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::None, name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/true, /*GenericParams=*/nullptr, params, returnType, + conformanceDC); encodeDecl->setSynthesized(); encodeDecl->setBodySynthesizer(deriveBodyEncodable_encode); diff --git a/lib/Sema/DerivedConformanceComparable.cpp b/lib/Sema/DerivedConformanceComparable.cpp index 25be215c54351..61035b23364c1 100644 --- a/lib/Sema/DerivedConformanceComparable.cpp +++ b/lib/Sema/DerivedConformanceComparable.cpp @@ -255,17 +255,11 @@ deriveComparable_lt( } DeclName name(C, generatedIdentifier, params); - auto comparableDecl = - FuncDecl::create(C, /*StaticLoc=*/SourceLoc(), - StaticSpellingKind::KeywordStatic, - /*FuncLoc=*/SourceLoc(), name, /*NameLoc=*/SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - /*GenericParams=*/nullptr, - params, - TypeLoc::withoutLoc(boolTy), - parentDC); - comparableDecl->setImplicit(); + auto *const comparableDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::KeywordStatic, name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/false, + /*GenericParams=*/nullptr, params, boolTy, parentDC); comparableDecl->setUserAccessible(false); // Add the @_implements(Comparable, < (_:_:)) attribute diff --git a/lib/Sema/DerivedConformanceDifferentiable.cpp b/lib/Sema/DerivedConformanceDifferentiable.cpp index b479372be9da0..5ab7ffc81c1ef 100644 --- a/lib/Sema/DerivedConformanceDifferentiable.cpp +++ b/lib/Sema/DerivedConformanceDifferentiable.cpp @@ -32,12 +32,37 @@ using namespace swift; +/// Return true if `move(along:)` can be invoked on the given `Differentiable`- +/// conforming property. +/// +/// If the given property is a `var`, return true because `move(along:)` can be +/// invoked regardless. Otherwise, return true if and only if the property's +/// type's 'Differentiable.move(along:)' witness is non-mutating. +static bool canInvokeMoveAlongOnProperty( + VarDecl *vd, ProtocolConformanceRef diffableConformance) { + assert(diffableConformance && "Property must conform to 'Differentiable'"); + // `var` always supports `move(along:)` since it is mutable. + if (vd->getIntroducer() == VarDecl::Introducer::Var) + return true; + // When the property is a `let`, the only case that would be supported is when + // it has a `move(along:)` protocol requirement witness that is non-mutating. + auto interfaceType = vd->getInterfaceType(); + auto &C = vd->getASTContext(); + auto witness = diffableConformance.getWitnessByName( + interfaceType, DeclName(C, C.Id_move, {C.Id_along})); + if (!witness) + return false; + auto *decl = cast(witness.getDecl()); + return decl->isNonMutating(); +} + /// Get the stored properties of a nominal type that are relevant for /// differentiation, except the ones tagged `@noDerivative`. static void -getStoredPropertiesForDifferentiation(NominalTypeDecl *nominal, DeclContext *DC, - SmallVectorImpl &result, - bool includeLetProperties = false) { +getStoredPropertiesForDifferentiation( + NominalTypeDecl *nominal, DeclContext *DC, + SmallVectorImpl &result, + bool includeLetPropertiesWithNonmutatingMoveAlong = false) { auto &C = nominal->getASTContext(); auto *diffableProto = C.getProtocol(KnownProtocolKind::Differentiable); for (auto *vd : nominal->getStoredProperties()) { @@ -53,15 +78,18 @@ getStoredPropertiesForDifferentiation(NominalTypeDecl *nominal, DeclContext *DC, // Skip stored properties with `@noDerivative` attribute. if (vd->getAttrs().hasAttribute()) continue; - // Skip `let` stored properties if requested. - // `mutating func move(along:)` cannot be synthesized to update `let` - // properties. - if (!includeLetProperties && vd->isLet()) - continue; if (vd->getInterfaceType()->hasError()) continue; auto varType = DC->mapTypeIntoContext(vd->getValueInterfaceType()); - if (!TypeChecker::conformsToProtocol(varType, diffableProto, nominal)) + auto conformance = TypeChecker::conformsToProtocol( + varType, diffableProto, nominal); + if (!conformance) + continue; + // Skip `let` stored properties with a mutating `move(along:)` if requested. + // `mutating func move(along:)` cannot be synthesized to update `let` + // properties. + if (!includeLetPropertiesWithNonmutatingMoveAlong && + !canInvokeMoveAlongOnProperty(vd, conformance)) continue; result.push_back(vd); } @@ -393,9 +421,9 @@ deriveBodyDifferentiable_zeroTangentVectorInitializer( auto *closureParams = ParameterList::createEmpty(C); auto *closure = new (C) ClosureExpr( - SourceRange(), /*capturedSelfDecl*/ nullptr, closureParams, SourceLoc(), - SourceLoc(), SourceLoc(), TypeExpr::createImplicit(resultTy, C), - discriminator, funcDecl); + SourceRange(), /*capturedSelfDecl*/ nullptr, closureParams, + SourceLoc(), SourceLoc(), SourceLoc(), SourceLoc(), + TypeExpr::createImplicit(resultTy, C), discriminator, funcDecl); closure->setImplicit(); auto *closureReturn = new (C) ReturnStmt(SourceLoc(), zeroExpr, true); auto *closureBody = @@ -504,8 +532,8 @@ deriveBodyDifferentiable_zeroTangentVectorInitializer( auto *closureParams = ParameterList::createEmpty(C); auto *closure = new (C) ClosureExpr( SourceRange(), /*capturedSelfDecl*/ nullptr, closureParams, SourceLoc(), - SourceLoc(), SourceLoc(), TypeExpr::createImplicit(resultTy, C), - discriminator, funcDecl); + SourceLoc(), SourceLoc(), SourceLoc(), + TypeExpr::createImplicit(resultTy, C), discriminator, funcDecl); closure->setImplicit(); auto *closureReturn = new (C) ReturnStmt(SourceLoc(), callExpr, true); auto *closureBody = @@ -544,15 +572,13 @@ static ValueDecl *deriveDifferentiable_method( ParameterList *params = ParameterList::create(C, {param}); DeclName declName(C, methodName, params); - auto *funcDecl = FuncDecl::create(C, SourceLoc(), StaticSpellingKind::None, - SourceLoc(), declName, SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws*/ false, SourceLoc(), - /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(returnType), parentDC); + auto *const funcDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::None, declName, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/false, + /*GenericParams=*/nullptr, params, returnType, parentDC); if (!nominal->getSelfClassDecl()) funcDecl->setSelfAccessKind(SelfAccessKind::Mutating); - funcDecl->setImplicit(); funcDecl->setBodySynthesizer(bodySynthesizer.Fn, bodySynthesizer.Context); funcDecl->setGenericSignature(parentDC->getGenericSignatureOfContext()); @@ -784,18 +810,18 @@ static void checkAndDiagnoseImplicitNoDerivative(ASTContext &Context, continue; // Check whether to diagnose stored property. auto varType = DC->mapTypeIntoContext(vd->getValueInterfaceType()); - bool conformsToDifferentiable = - !TypeChecker::conformsToProtocol(varType, diffableProto, nominal) - .isInvalid(); + auto diffableConformance = + TypeChecker::conformsToProtocol(varType, diffableProto, nominal); // If stored property should not be diagnosed, continue. - if (conformsToDifferentiable && !vd->isLet()) + if (diffableConformance && + canInvokeMoveAlongOnProperty(vd, diffableConformance)) continue; // Otherwise, add an implicit `@noDerivative` attribute. vd->getAttrs().add(new (Context) NoDerivativeAttr(/*Implicit*/ true)); auto loc = vd->getAttributeInsertionLoc(/*forModifier*/ false); assert(loc.isValid() && "Expected valid source location"); // Diagnose properties that do not conform to `Differentiable`. - if (!conformsToDifferentiable) { + if (!diffableConformance) { Context.Diags .diagnose( loc, diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp index b77762648c7c4..54d5268c52cb5 100644 --- a/lib/Sema/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp @@ -406,17 +406,11 @@ deriveEquatable_eq( } DeclName name(C, generatedIdentifier, params); - auto eqDecl = - FuncDecl::create(C, /*StaticLoc=*/SourceLoc(), - StaticSpellingKind::KeywordStatic, - /*FuncLoc=*/SourceLoc(), name, /*NameLoc=*/SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - /*GenericParams=*/nullptr, - params, - TypeLoc::withoutLoc(boolTy), - parentDC); - eqDecl->setImplicit(); + auto *const eqDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::KeywordStatic, name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/false, + /*GenericParams=*/nullptr, params, boolTy, parentDC); eqDecl->setUserAccessible(false); // Add the @_implements(Equatable, ==(_:_:)) attribute @@ -549,15 +543,11 @@ deriveHashable_hashInto( // Func name: hash(into: inout Hasher) -> () DeclName name(C, C.Id_hash, params); - auto *hashDecl = FuncDecl::create(C, - SourceLoc(), StaticSpellingKind::None, - SourceLoc(), name, SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws=*/false, SourceLoc(), - nullptr, params, - TypeLoc::withoutLoc(returnType), - parentDC); - hashDecl->setImplicit(); + auto *const hashDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::None, name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/false, + /*GenericParams=*/nullptr, params, returnType, parentDC); hashDecl->setBodySynthesizer(bodySynthesizer); hashDecl->copyFormalAccessFrom(derived.Nominal); @@ -899,7 +889,7 @@ static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) { /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(intType), parentDC); + intType, parentDC); getterDecl->setImplicit(); getterDecl->setBodySynthesizer(&deriveBodyHashable_hashValue); getterDecl->setIsTransparent(false); diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index 6b96232009592..b3eb907ebb44b 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "TypeChecker.h" +#include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/Stmt.h" #include "swift/AST/Expr.h" @@ -429,8 +430,6 @@ DerivedConformance::declareDerivedPropertyGetter(VarDecl *property, auto &C = property->getASTContext(); auto parentDC = property->getDeclContext(); ParameterList *params = ParameterList::createEmpty(C); - - Type propertyInterfaceType = property->getInterfaceType(); auto getterDecl = AccessorDecl::create(C, /*FuncLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(), @@ -438,7 +437,7 @@ DerivedConformance::declareDerivedPropertyGetter(VarDecl *property, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(propertyInterfaceType), parentDC); + property->getInterfaceType(), parentDC); getterDecl->setImplicit(); getterDecl->setIsTransparent(false); @@ -490,8 +489,27 @@ bool DerivedConformance::checkAndDiagnoseDisallowedContext( Nominal->getModuleScopeContext() != getConformanceContext()->getModuleScopeContext()) { ConformanceDecl->diagnose(diag::cannot_synthesize_in_crossfile_extension, + Nominal->getDescriptiveKind(), Nominal->getName(), + synthesizing->getName(), getProtocolType()); Nominal->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); + + // In editor mode, try to insert a stub. + if (Context.LangOpts.DiagnosticsEditorMode) { + auto Extension = cast(getConformanceContext()); + auto FixitLocation = Extension->getBraces().Start; + llvm::SmallString<128> Text; + { + llvm::raw_svector_ostream SS(Text); + swift::printRequirementStub(synthesizing, Nominal, + Nominal->getDeclaredType(), + Extension->getStartLoc(), SS); + if (!Text.empty()) { + ConformanceDecl->diagnose(diag::missing_witnesses_general) + .fixItInsertAfter(FixitLocation, Text.str()); + } + } + } return true; } diff --git a/lib/Sema/DerivedConformances.h b/lib/Sema/DerivedConformances.h index 3465402b7a9d6..c5dba4bb20172 100644 --- a/lib/Sema/DerivedConformances.h +++ b/lib/Sema/DerivedConformances.h @@ -163,6 +163,12 @@ class DerivedConformance { /// \returns the derived member, which will also be added to the type. ValueDecl *deriveCaseIterable(ValueDecl *requirement); + /// Derive a CaseIterable type witness for an enum if it has no associated + /// values for any of its cases. + /// + /// \returns the derived member, which will also be added to the type. + Type deriveCaseIterable(AssociatedTypeDecl *assocType); + /// Determine if a RawRepresentable requirement can be derived for a type. /// /// This is implemented for non-empty enums without associated values, diff --git a/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index 2ec7aacd2a964..c8ed785366efb 100644 --- a/lib/Sema/ImportResolution.cpp +++ b/lib/Sema/ImportResolution.cpp @@ -298,6 +298,8 @@ void swift::performImportResolution(SourceFile &SF) { // Resolve each import declaration. for (auto D : SF.getTopLevelDecls()) resolver.visit(D); + for (auto D : SF.getHoistedDecls()) + resolver.visit(D); SF.setImports(resolver.getFinishedImports()); diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index cc1ef792f5c92..2989603eb708f 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -234,7 +234,7 @@ static void collectVisibleMemberDecls(const DeclContext *CurrDC, LookupState LS, } static void -synthesizePropertyWrapperStorageWrapperProperties(IterableDeclContext *IDC); +synthesizePropertyWrapperVariables(IterableDeclContext *IDC); /// Lookup members in extensions of \p LookupType, using \p BaseType as the /// underlying type when checking any constraints on the extensions. @@ -253,7 +253,7 @@ static void doGlobalExtensionLookup(Type BaseType, extension)), false)) continue; - synthesizePropertyWrapperStorageWrapperProperties(extension); + synthesizePropertyWrapperVariables(extension); collectVisibleMemberDecls(CurrDC, LS, BaseType, extension, FoundDecls); } @@ -538,10 +538,10 @@ static void Consumer, CurrDC, LS, Reason); } -// Generate '$' and '_' prefixed variables that have attached property +// Generate '$' and '_' prefixed variables for members that have attached property // wrappers. static void -synthesizePropertyWrapperStorageWrapperProperties(IterableDeclContext *IDC) { +synthesizePropertyWrapperVariables(IterableDeclContext *IDC) { auto SF = IDC->getAsGenericContext()->getParentSourceFile(); if (!SF || SF->Kind == SourceFileKind::Interface) return; @@ -578,7 +578,7 @@ static void synthesizeMemberDeclsForLookup(NominalTypeDecl *NTD, /*useResolver=*/true); } - synthesizePropertyWrapperStorageWrapperProperties(NTD); + synthesizePropertyWrapperVariables(NTD); } static void lookupVisibleMemberDeclsImpl( @@ -946,17 +946,22 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer { /*wouldConflictInSwift5*/nullptr, /*skipProtocolExtensionCheck*/true)) { FoundConflicting = true; - // Prefer derived requirements over their witnesses. - if (Reason == - DeclVisibilityKind::MemberOfProtocolDerivedByCurrentNominal || - VD->getFormalAccess() > OtherVD->getFormalAccess() || - //Prefer available one. - (!AvailableAttr::isUnavailable(VD) && - AvailableAttr::isUnavailable(OtherVD))) { - FilteredResults.remove( - FoundDeclTy(OtherVD, DeclVisibilityKind::LocalVariable, {})); - FilteredResults.insert(DeclAndReason); - *I = VD; + + if (!AvailableAttr::isUnavailable(VD)) { + bool preferVD = ( + // Prefer derived requirements over their witnesses. + Reason == DeclVisibilityKind:: + MemberOfProtocolDerivedByCurrentNominal || + // Prefer available one. + AvailableAttr::isUnavailable(OtherVD) || + // Prefer more accessible one. + VD->getFormalAccess() > OtherVD->getFormalAccess()); + if (preferVD) { + FilteredResults.remove( + FoundDeclTy(OtherVD, DeclVisibilityKind::LocalVariable, {})); + FilteredResults.insert(DeclAndReason); + *I = VD; + } } } } diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 563f281663182..f8bf7cd5219fe 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -594,8 +594,8 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, isExistential = instanceTy->isExistentialType(); if (!isExistential && instanceTy->mayHaveMembers() && - !TypeChecker::lookupConstructors(const_cast(DC), - instanceTy).empty()) { + !TypeChecker::lookupMember(const_cast(DC), instanceTy, + DeclNameRef::createConstructor()).empty()) { Ctx.Diags.diagnose(E->getEndLoc(), diag::add_parens_to_type) .fixItInsertAfter(E->getEndLoc(), "()"); } @@ -2223,7 +2223,7 @@ static bool fixItOverrideDeclarationTypesImpl( fixedAny |= checkType(resultType, ParamDecl::Specifier::Default, baseResultType, ParamDecl::Specifier::Default, - method->getBodyResultTypeLoc().getSourceRange()); + method->getResultTypeSourceRange()); } return fixedAny; } @@ -2246,7 +2246,7 @@ static bool fixItOverrideDeclarationTypesImpl( baseSubscript->getElementInterfaceType()); fixedAny |= checkType(resultType, ParamDecl::Specifier::Default, baseResultType, ParamDecl::Specifier::Default, - subscript->getElementTypeLoc().getSourceRange()); + subscript->getElementTypeSourceRange()); return fixedAny; } diff --git a/lib/Sema/PCMacro.cpp b/lib/Sema/PCMacro.cpp index 5d6075ef5b031..573ad52e9f8f8 100644 --- a/lib/Sema/PCMacro.cpp +++ b/lib/Sema/PCMacro.cpp @@ -226,8 +226,8 @@ class Instrumenter : InstrumenterBase { SourceLoc StartLoc = FES->getStartLoc(); SourceLoc EndLoc = FES->getSequence()->getEndLoc(); // FIXME: get the 'end' of the for stmt - // if (FD->getBodyResultTypeLoc().hasLocation()) { - // EndLoc = FD->getBodyResultTypeLoc().getSourceRange().End; + // if (FD->getResultTypeRepr()) { + // EndLoc = FD->getResultTypeSourceRange().End; // } else { // EndLoc = FD->getParameters()->getSourceRange().End; // } @@ -343,8 +343,8 @@ class Instrumenter : InstrumenterBase { // decl at the start of the transformed body SourceLoc StartLoc = FD->getStartLoc(); SourceLoc EndLoc = SourceLoc(); - if (FD->getBodyResultTypeLoc().hasLocation()) { - EndLoc = FD->getBodyResultTypeLoc().getSourceRange().End; + if (FD->getResultTypeRepr()) { + EndLoc = FD->getResultTypeSourceRange().End; } else { EndLoc = FD->getParameters()->getSourceRange().End; } @@ -354,7 +354,7 @@ class Instrumenter : InstrumenterBase { if (NB != B) { FD->setBody(NB); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } } } else if (auto *NTD = dyn_cast(D)) { @@ -695,7 +695,7 @@ void swift::performPCMacro(SourceFile &SF) { BraceStmt *NewBody = I.transformBraceStmt(Body, true); if (NewBody != Body) { TLCD->setBody(NewBody); - TypeChecker::checkTopLevelErrorHandling(TLCD); + TypeChecker::checkTopLevelEffects(TLCD); TypeChecker::contextualizeTopLevelCode(TLCD); } return false; diff --git a/lib/Sema/PlaygroundTransform.cpp b/lib/Sema/PlaygroundTransform.cpp index 7c7e9dcd1e39b..f36294ff47240 100644 --- a/lib/Sema/PlaygroundTransform.cpp +++ b/lib/Sema/PlaygroundTransform.cpp @@ -294,7 +294,7 @@ class Instrumenter : InstrumenterBase { BraceStmt *NB = transformBraceStmt(B); if (NB != B) { FD->setBody(NB); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } } } else if (auto *NTD = dyn_cast(D)) { @@ -893,7 +893,7 @@ void swift::performPlaygroundTransform(SourceFile &SF, bool HighPerformance) { BraceStmt *NewBody = I.transformBraceStmt(Body); if (NewBody != Body) { FD->setBody(NewBody); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } return false; } @@ -905,7 +905,7 @@ void swift::performPlaygroundTransform(SourceFile &SF, bool HighPerformance) { BraceStmt *NewBody = I.transformBraceStmt(Body, true); if (NewBody != Body) { TLCD->setBody(NewBody); - TypeChecker::checkTopLevelErrorHandling(TLCD); + TypeChecker::checkTopLevelEffects(TLCD); } return false; } diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index ee8cf299ed2dc..8da9fd07da9ab 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -16,6 +16,7 @@ #include "TypeChecker.h" #include "TypeCheckAvailability.h" +#include "TypeCheckAccess.h" #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" @@ -171,7 +172,8 @@ static bool diagnoseDeclExportability(SourceLoc loc, const ValueDecl *D, static bool diagnoseGenericArgumentsExportability(SourceLoc loc, SubstitutionMap subs, - const SourceFile &userSF) { + const SourceFile &userSF, + const DeclContext *userDC) { bool hadAnyIssues = false; for (ProtocolConformanceRef conformance : subs.getConformances()) { if (!conformance.isConcrete()) @@ -180,18 +182,23 @@ diagnoseGenericArgumentsExportability(SourceLoc loc, SubstitutionMap subConformanceSubs = concreteConf->getSubstitutions(userSF.getParentModule()); - diagnoseGenericArgumentsExportability(loc, subConformanceSubs, userSF); + diagnoseGenericArgumentsExportability(loc, subConformanceSubs, userSF, userDC); const RootProtocolConformance *rootConf = concreteConf->getRootConformance(); ModuleDecl *M = rootConf->getDeclContext()->getParentModule(); - if (!userSF.isImportedImplementationOnly(M)) + + auto originKind = getDisallowedOriginKind( + rootConf->getDeclContext()->getAsDecl(), + userSF, userDC->getInnermostDeclarationDeclContext()); + if (originKind == DisallowedOriginKind::None) continue; ASTContext &ctx = M->getASTContext(); ctx.Diags.diagnose(loc, diag::conformance_from_implementation_only_module, rootConf->getType(), - rootConf->getProtocol()->getName(), 0, M->getName()); + rootConf->getProtocol()->getName(), 0, M->getName(), + static_cast(originKind)); hadAnyIssues = true; } return hadAnyIssues; @@ -209,10 +216,10 @@ void TypeChecker::diagnoseGenericTypeExportability(SourceLoc Loc, Type T, if (auto *BGT = dyn_cast(T.getPointer())) { ModuleDecl *useModule = SF->getParentModule(); auto subs = T->getContextSubstitutionMap(useModule, BGT->getDecl()); - (void)diagnoseGenericArgumentsExportability(Loc, subs, *SF); + (void)diagnoseGenericArgumentsExportability(Loc, subs, *SF, DC); } else if (auto *TAT = dyn_cast(T.getPointer())) { auto subs = TAT->getSubstitutionMap(); - (void)diagnoseGenericArgumentsExportability(Loc, subs, *SF); + (void)diagnoseGenericArgumentsExportability(Loc, subs, *SF, DC); } } @@ -226,19 +233,11 @@ TypeChecker::diagnoseDeclRefExportability(SourceLoc loc, if (!userSF) return false; - // If the source file doesn't have any implementation-only imports, - // we can fast-path this. In the current language design, we never - // need to consider the possibility of implementation-only imports - // from other source files in the module (or indirectly in other modules). - // TODO: maybe check whether D is from a bridging header? - if (!userSF->hasImplementationOnlyImports()) - return false; - const ValueDecl *D = declRef.getDecl(); if (diagnoseDeclExportability(loc, D, *userSF, fragileKind)) return true; if (diagnoseGenericArgumentsExportability(loc, declRef.getSubstitutions(), - *userSF)) { + *userSF, DC)) { return true; } return false; diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index e9b75ad9b5ac1..67f15ea3f539b 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -873,7 +873,8 @@ class AccessControlChecker : public AccessControlCheckerBase, }); } - checkTypeAccess(SD->getElementTypeLoc(), SD, /*mayBeInferred*/false, + checkTypeAccess(SD->getElementInterfaceType(), SD->getElementTypeRepr(), + SD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *thisComplainRepr, DowngradeToWarning downgradeDiag) { @@ -937,7 +938,8 @@ class AccessControlChecker : public AccessControlCheckerBase, bool problemIsResult = false; if (auto FD = dyn_cast(fn)) { - checkTypeAccess(FD->getBodyResultTypeLoc(), FD, /*mayBeInferred*/false, + checkTypeAccess(FD->getResultInterfaceType(), FD->getResultTypeRepr(), + FD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *thisComplainRepr, DowngradeToWarning downgradeDiag) { @@ -1375,7 +1377,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, }); } - checkTypeAccess(SD->getElementTypeLoc(), SD, /*mayBeInferred*/false, + checkTypeAccess(SD->getElementInterfaceType(), SD->getElementTypeRepr(), + SD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *complainRepr, DowngradeToWarning downgradeDiag) { @@ -1418,7 +1421,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, } if (auto FD = dyn_cast(fn)) { - checkTypeAccess(FD->getBodyResultTypeLoc(), FD, /*mayBeInferred*/false, + checkTypeAccess(FD->getResultInterfaceType(), FD->getResultTypeRepr(), + FD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *complainRepr, DowngradeToWarning downgradeDiag) { @@ -1450,47 +1454,40 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, } }; +/// Returns the kind of origin, implementation-only import or SPI declaration, +/// that restricts exporting \p decl from the given file and context. +/// +/// Local variant to swift::getDisallowedOriginKind for downgrade to warnings. +DisallowedOriginKind +getDisallowedOriginKind(const Decl *decl, + const SourceFile &userSF, + const Decl *userContext, + DowngradeToWarning &downgradeToWarning) { + downgradeToWarning = DowngradeToWarning::No; + ModuleDecl *M = decl->getModuleContext(); + if (userSF.isImportedImplementationOnly(M)) { + // Temporarily downgrade implementation-only exportability in SPI to + // a warning. + if (userContext->isSPI()) + downgradeToWarning = DowngradeToWarning::Yes; + + // Implementation-only imported, cannot be reexported. + return DisallowedOriginKind::ImplementationOnly; + } else if (decl->isSPI() && !userContext->isSPI()) { + // SPI can only be exported in SPI. + return userContext->getModuleContext() == M ? + DisallowedOriginKind::SPILocal : + DisallowedOriginKind::SPIImported; + } + + return DisallowedOriginKind::None; +}; + // Diagnose public APIs exposing types that are either imported as // implementation-only or declared as SPI. class ExportabilityChecker : public DeclVisitor { class Diagnoser; - // Problematic origin of an exported type. - // - // This enum must be kept in sync with - // diag::decl_from_hidden_module and - // diag::conformance_from_implementation_only_module. - enum class DisallowedOriginKind : uint8_t { - ImplementationOnly, - SPIImported, - SPILocal, - None - }; - - // If there's an exportability problem with \p typeDecl, get its origin kind. - static DisallowedOriginKind getDisallowedOriginKind( - const TypeDecl *typeDecl, const SourceFile &SF, const Decl *context, - DowngradeToWarning &downgradeToWarning) { - downgradeToWarning = DowngradeToWarning::No; - ModuleDecl *M = typeDecl->getModuleContext(); - if (SF.isImportedImplementationOnly(M)) { - // Temporarily downgrade implementation-only exportability in SPI to - // a warning. - if (context->isSPI()) - downgradeToWarning = DowngradeToWarning::Yes; - - // Implementation-only imported, cannot be reexported. - return DisallowedOriginKind::ImplementationOnly; - } else if (typeDecl->isSPI() && !context->isSPI()) { - // SPI can only be exported in SPI. - return context->getModuleContext() == M ? - DisallowedOriginKind::SPILocal : - DisallowedOriginKind::SPIImported; - } - - return DisallowedOriginKind::None; - }; - void checkTypeImpl( Type type, const TypeRepr *typeRepr, const SourceFile &SF, const Decl *context, @@ -1556,10 +1553,12 @@ class ExportabilityChecker : public DeclVisitor { const RootProtocolConformance *rootConf = concreteConf->getRootConformance(); - ModuleDecl *M = rootConf->getDeclContext()->getParentModule(); - if (!SF.isImportedImplementationOnly(M)) + auto originKind = getDisallowedOriginKind( + rootConf->getDeclContext()->getAsDecl(), + SF, context); + if (originKind == DisallowedOriginKind::None) continue; - diagnoser.diagnoseConformance(rootConf); + diagnoser.diagnoseConformance(rootConf, originKind); } } @@ -1670,12 +1669,14 @@ class ExportabilityChecker : public DeclVisitor { highlightOffendingType(diag, complainRepr); } - void diagnoseConformance(const ProtocolConformance *offendingConformance) const { + void diagnoseConformance(const ProtocolConformance *offendingConformance, + DisallowedOriginKind originKind) const { ModuleDecl *M = offendingConformance->getDeclContext()->getParentModule(); D->diagnose(diag::conformance_from_implementation_only_module, offendingConformance->getType(), offendingConformance->getProtocol()->getName(), - static_cast(reason), M->getName()); + static_cast(reason), M->getName(), + static_cast(originKind)); } void diagnoseClangFunctionType(Type fnType, const clang::Type *type) const { @@ -1916,7 +1917,8 @@ class ExportabilityChecker : public DeclVisitor { checkType(P->getInterfaceType(), P->getTypeRepr(), SD, getDiagnoser(SD)); } - checkType(SD->getElementTypeLoc(), SD, getDiagnoser(SD)); + checkType(SD->getElementInterfaceType(), SD->getElementTypeRepr(), SD, + getDiagnoser(SD)); } void visitAbstractFunctionDecl(AbstractFunctionDecl *fn) { @@ -1929,7 +1931,8 @@ class ExportabilityChecker : public DeclVisitor { void visitFuncDecl(FuncDecl *FD) { visitAbstractFunctionDecl(FD); - checkType(FD->getBodyResultTypeLoc(), FD, getDiagnoser(FD)); + checkType(FD->getResultInterfaceType(), FD->getResultTypeRepr(), FD, + getDiagnoser(FD)); } void visitEnumElementDecl(EnumElementDecl *EED) { @@ -2061,6 +2064,13 @@ static void checkExtensionGenericParamAccess(const ExtensionDecl *ED) { ED, ED, desiredAccessScope, userSpecifiedAccess); } +DisallowedOriginKind swift::getDisallowedOriginKind(const Decl *decl, + const SourceFile &userSF, + const Decl *declContext) { + auto downgradeToWarning = DowngradeToWarning::No; + return getDisallowedOriginKind(decl, userSF, declContext, downgradeToWarning); +} + void swift::checkAccessControl(Decl *D) { if (isa(D) || isa(D)) { AccessControlChecker().visit(D); diff --git a/lib/Sema/TypeCheckAccess.h b/lib/Sema/TypeCheckAccess.h index 181fb4490a301..d29523ef39a8d 100644 --- a/lib/Sema/TypeCheckAccess.h +++ b/lib/Sema/TypeCheckAccess.h @@ -17,9 +17,12 @@ #ifndef TYPECHECKACCESS_H #define TYPECHECKACCESS_H +#include + namespace swift { class Decl; +class SourceFile; /// Performs access-related checks for \p D. /// @@ -28,6 +31,24 @@ class Decl; /// itself. Related checks may also be performed. void checkAccessControl(Decl *D); +// Problematic origin of an exported type. +// +// This enum must be kept in sync with +// diag::decl_from_hidden_module and +// diag::conformance_from_implementation_only_module. +enum class DisallowedOriginKind : uint8_t { + ImplementationOnly, + SPIImported, + SPILocal, + None +}; + +/// Returns the kind of origin, implementation-only import or SPI declaration, +/// that restricts exporting \p decl from the given file and context. +DisallowedOriginKind getDisallowedOriginKind(const Decl *decl, + const SourceFile &userSF, + const Decl *userContext); + } // end namespace swift #endif diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 1133d4eb3199b..93c6b287a8e07 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -257,6 +257,22 @@ class AttributeChecker : public AttributeVisitor { void visitDifferentiableAttr(DifferentiableAttr *attr); void visitDerivativeAttr(DerivativeAttr *attr); void visitTransposeAttr(TransposeAttr *attr); + + void visitAsyncHandlerAttr(AsyncHandlerAttr *attr) { + if (!Ctx.LangOpts.EnableExperimentalConcurrency) { + diagnoseAndRemoveAttr(attr, diag::asynchandler_attr_requires_concurrency); + return; + } + + auto func = dyn_cast(D); + if (!func) { + diagnoseAndRemoveAttr(attr, diag::asynchandler_non_func); + return; + } + + // Trigger the request to check for @asyncHandler. + (void)func->isAsyncHandler(); + } }; } // end anonymous namespace @@ -301,14 +317,17 @@ void AttributeChecker::visitMutationAttr(DeclAttribute *attr) { llvm_unreachable("unhandled attribute kind"); } + auto DC = FD->getDeclContext(); // mutation attributes may only appear in type context. - if (auto contextTy = FD->getDeclContext()->getDeclaredInterfaceType()) { + if (auto contextTy = DC->getDeclaredInterfaceType()) { // 'mutating' and 'nonmutating' are not valid on types // with reference semantics. if (contextTy->hasReferenceSemantics()) { - if (attrModifier != SelfAccessKind::Consuming) + if (attrModifier != SelfAccessKind::Consuming) { diagnoseAndRemoveAttr(attr, diag::mutating_invalid_classes, - attrModifier); + attrModifier, FD->getDescriptiveKind(), + DC->getSelfProtocolDecl() != nullptr); + } } } else { diagnoseAndRemoveAttr(attr, diag::mutating_invalid_global_scope, @@ -1893,19 +1912,15 @@ SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator, mainFunction = viableCandidates[0]; } - auto *func = FuncDecl::create( - context, /*StaticLoc*/ SourceLoc(), StaticSpellingKind::KeywordStatic, - /*FuncLoc*/ SourceLoc(), + auto *const func = FuncDecl::createImplicit( + context, StaticSpellingKind::KeywordStatic, DeclName(context, DeclBaseName(context.Id_MainEntryPoint), ParameterList::createEmpty(context)), - /*NameLoc*/ SourceLoc(), - /*Async*/ false, SourceLoc(), + /*NameLoc=*/SourceLoc(), + /*Async=*/false, /*Throws=*/mainFunction->hasThrows(), - /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, ParameterList::createEmpty(context), - /*FnRetType=*/TypeLoc::withoutLoc(TupleType::getEmpty(context)), - declContext); - func->setImplicit(true); + /*FnRetType=*/TupleType::getEmpty(context), declContext); func->setSynthesized(true); auto *params = context.Allocate(); @@ -2886,18 +2901,7 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) { auto nominal = evaluateOrDefault( Ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr); - // If there is no nominal type with this name, complain about this being - // an unknown attribute. if (!nominal) { - std::string typeName; - if (auto typeRepr = attr->getTypeRepr()) { - llvm::raw_string_ostream out(typeName); - typeRepr->print(out); - } else { - typeName = attr->getType().getString(); - } - - diagnose(attr->getLocation(), diag::unknown_attribute, typeName); attr->setInvalid(); return; } @@ -3004,8 +3008,32 @@ void AttributeChecker::visitPropertyWrapperAttr(PropertyWrapperAttr *attr) { } void AttributeChecker::visitFunctionBuilderAttr(FunctionBuilderAttr *attr) { - // TODO: check that the type at least provides a `sequence` factory? - // Any other validation? + auto *nominal = dyn_cast(D); + SmallVector potentialMatches; + bool supportsBuildBlock = TypeChecker::typeSupportsBuilderOp( + nominal->getDeclaredType(), nominal, D->getASTContext().Id_buildBlock, + /*argLabels=*/{}, &potentialMatches); + + if (!supportsBuildBlock) { + diagnose(nominal->getLoc(), diag::function_builder_static_buildblock); + + // For any close matches, attempt to explain to the user why they aren't + // valid. + for (auto *member : potentialMatches) { + if (member->isStatic() && isa(member)) + continue; + + if (isa(member) && + member->getDeclContext()->getSelfNominalTypeDecl() == nominal) + diagnose(member->getLoc(), diag::function_builder_non_static_buildblock) + .fixItInsert(member->getAttributeInsertionLoc(true), "static "); + else if (isa(member)) + diagnose(member->getLoc(), diag::function_builder_buildblock_enum_case); + else + diagnose(member->getLoc(), + diag::function_builder_buildblock_not_static_method); + } + } } void @@ -4641,7 +4669,8 @@ static bool typeCheckDerivativeAttr(ASTContext &Ctx, Decl *D, if (originalAFD->getFormalAccess() == derivative->getFormalAccess()) return true; return originalAFD->getFormalAccess() == AccessLevel::Public && - derivative->getEffectiveAccess() == AccessLevel::Public; + (derivative->getFormalAccess() == AccessLevel::Public || + derivative->isUsableFromInline()); }; // Check access level compatibility for original and derivative functions. @@ -4770,7 +4799,7 @@ static bool typeCheckDerivativeAttr(ASTContext &Ctx, Decl *D, // Emit note with expected differential/pullback type on actual type // location. auto *tupleReturnTypeRepr = - cast(derivative->getBodyResultTypeLoc().getTypeRepr()); + cast(derivative->getResultTypeRepr()); auto *funcEltTypeRepr = tupleReturnTypeRepr->getElementType(1); diags .diagnose(funcEltTypeRepr->getStartLoc(), diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index 20a41c6953b7e..c83ed135bcc9a 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -660,10 +660,11 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { AFD->diagnose(diag::objc_generic_extension_using_type_parameter); // If it's possible, suggest adding @objc. + Optional asyncConvention; Optional errorConvention; if (!AFD->isObjC() && isRepresentableInObjC(AFD, ObjCReason::MemberOfObjCMembersClass, - errorConvention)) { + asyncConvention, errorConvention)) { AFD->diagnose( diag::objc_generic_extension_using_type_parameter_try_objc) .fixItInsert(AFD->getAttributeInsertionLoc(false), "@objc "); diff --git a/lib/Sema/TypeCheckCodeCompletion.cpp b/lib/Sema/TypeCheckCodeCompletion.cpp index b40af172a2cd5..6ba92aeb42dd4 100644 --- a/lib/Sema/TypeCheckCodeCompletion.cpp +++ b/lib/Sema/TypeCheckCodeCompletion.cpp @@ -416,6 +416,8 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc, assert(exprType && !exprType->hasTypeVariable() && "free type variable with FreeTypeVariableBinding::GenericParameters?"); + assert(exprType && !exprType->hasHole() && + "type hole with FreeTypeVariableBinding::GenericParameters?"); if (exprType->hasError()) { recoverOriginalType(); @@ -553,10 +555,10 @@ TypeChecker::getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS, // 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(DeclNameRef(opName), refKind, DeclNameLoc(Loc)); - auto *opExpr = TypeChecker::resolveDeclRefExpr(&UDRE, DC); + auto *opExpr = TypeChecker::resolveDeclRefExpr( + &UDRE, DC, /*replaceInvalidRefsWithErrors=*/true); switch (refKind) { - case DeclRefKind::PostfixOperator: { // (postfix_unary_expr // (declref_expr name=) @@ -611,7 +613,8 @@ static Optional getTypeOfCompletionContextExpr( CompletionTypeCheckKind kind, Expr *&parsedExpr, ConcreteDeclRef &referencedDecl) { - if (constraints::ConstraintSystem::preCheckExpression(parsedExpr, DC)) + if (constraints::ConstraintSystem::preCheckExpression( + parsedExpr, DC, /*replaceInvalidRefsWithErrors=*/true)) return None; switch (kind) { diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp new file mode 100644 index 0000000000000..2019e8a179bf3 --- /dev/null +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -0,0 +1,163 @@ +//===--- TypeCheckConcurrency.cpp - Concurrency ---------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file implements type checking support for Swift's concurrency model. +// +//===----------------------------------------------------------------------===// +#include "TypeChecker.h" +#include "swift/AST/ParameterList.h" +#include "swift/AST/ProtocolConformance.h" +#include "swift/AST/TypeCheckRequests.h" + +using namespace swift; + +/// Check whether the @asyncHandler attribute can be applied to the given +/// function declaration. +/// +/// \param diagnose Whether to emit a diagnostic when a problem is encountered. +/// +/// \returns \c true if there was a problem with adding the attribute, \c false +/// otherwise. +static bool checkAsyncHandler(FuncDecl *func, bool diagnose) { + if (!func->getResultInterfaceType()->isVoid()) { + if (diagnose) { + func->diagnose(diag::asynchandler_returns_value) + .highlight(func->getResultTypeSourceRange()); + } + + return true; + } + + if (func->hasThrows()) { + if (diagnose) { + func->diagnose(diag::asynchandler_throws) + .fixItRemove(func->getThrowsLoc()); + } + + return true; + } + + if (func->hasAsync()) { + if (diagnose) { + func->diagnose(diag::asynchandler_async) + .fixItRemove(func->getAsyncLoc()); + } + + return true; + } + + for (auto param : *func->getParameters()) { + if (param->isInOut()) { + if (diagnose) { + param->diagnose(diag::asynchandler_inout_parameter) + .fixItRemove(param->getSpecifierLoc()); + } + + return true; + } + } + + if (func->isMutating()) { + if (diagnose) { + auto diag = func->diagnose(diag::asynchandler_mutating); + if (auto mutatingAttr = func->getAttrs().getAttribute()) { + diag.fixItRemove(mutatingAttr->getRange()); + } + } + + return true; + } + + return false; +} + +void swift::addAsyncNotes(FuncDecl *func) { + func->diagnose(diag::note_add_async_to_function, func->getName()); + + if (!checkAsyncHandler(func, /*diagnose=*/false)) { + func->diagnose( + diag::note_add_asynchandler_to_function, func->getName()) + .fixItInsert(func->getAttributeInsertionLoc(false), "@asyncHandler "); + } +} + +bool IsAsyncHandlerRequest::evaluate( + Evaluator &evaluator, FuncDecl *func) const { + // Check whether the attribute was explicitly specified. + if (auto attr = func->getAttrs().getAttribute()) { + // Check for well-formedness. + if (checkAsyncHandler(func, /*diagnose=*/true)) { + attr->setInvalid(); + return false; + } + + return true; + } + + if (!func->getASTContext().LangOpts.EnableExperimentalConcurrency) + return false; + + // Are we in a context where inference is possible? + auto dc = func->getDeclContext(); + if (!dc->isTypeContext() || !dc->getParentSourceFile() || + isa(dc) || !func->hasBody()) + return false; + + // Is it possible to infer @asyncHandler for this function at all? + if (checkAsyncHandler(func, /*diagnose=*/false)) + return false; + + // Add an implicit @asyncHandler attribute and return true. We're done. + auto addImplicitAsyncHandlerAttr = [&] { + func->getAttrs().add(new (func->getASTContext()) AsyncHandlerAttr(true)); + return true; + }; + + // Check whether any of the conformances in the context of the function + // implies @asyncHandler. + { + auto idc = cast(dc->getAsDecl()); + auto conformances = evaluateOrDefault( + dc->getASTContext().evaluator, + LookupAllConformancesInContextRequest{idc}, { }); + + for (auto conformance : conformances) { + auto protocol = conformance->getProtocol(); + for (auto found : protocol->lookupDirect(func->getName())) { + if (!isa(found->getDeclContext())) + continue; + + auto requirement = dyn_cast(found); + if (!requirement) + continue; + + if (!requirement->isAsyncHandler()) + continue; + + auto witness = conformance->getWitnessDecl(requirement); + if (witness != func) + continue; + + return addImplicitAsyncHandlerAttr(); + } + } + } + + // Look through dynamic replacements. + if (auto replaced = func->getDynamicallyReplacedDecl()) { + if (auto replacedFunc = dyn_cast(replaced)) + if (replacedFunc->isAsyncHandler()) + return addImplicitAsyncHandlerAttr(); + } + + return false; +} diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index bd6a0fc589bb1..8908b485d8040 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -477,15 +477,62 @@ static bool findNonMembers(ArrayRef lookupResults, return AllDeclRefs; } +/// Find the next element in a chain of members. If this expression is (or +/// could be) the base of such a chain, this will return \c nullptr. +static Expr *getMemberChainSubExpr(Expr *expr) { + assert(expr && "getMemberChainSubExpr called with null expr!"); + if (auto *UDE = dyn_cast(expr)) { + return UDE->getBase(); + } else if (auto *CE = dyn_cast(expr)) { + return CE->getFn(); + } else if (auto *BOE = dyn_cast(expr)) { + return BOE->getSubExpr(); + } else if (auto *FVE = dyn_cast(expr)) { + return FVE->getSubExpr(); + } else if (auto *SE = dyn_cast(expr)) { + return SE->getBase(); + } else if (auto *CCE = dyn_cast(expr)) { + return CCE->getBase(); + } else { + return nullptr; + } +} + +UnresolvedMemberExpr *TypeChecker::getUnresolvedMemberChainBase(Expr *expr) { + if (auto *subExpr = getMemberChainSubExpr(expr)) + return getUnresolvedMemberChainBase(subExpr); + else + return dyn_cast(expr); +} + +/// Whether this expression is a member of a member chain. +static bool isMemberChainMember(Expr *expr) { + return getMemberChainSubExpr(expr) != nullptr; +} +/// Whether this expression sits at the end of a chain of member accesses. +static bool isMemberChainTail(Expr *expr, Expr *parent) { + assert(expr && "isMemberChainTail called with null expr!"); + // If this expression's parent is not itself part of a chain (or, this expr + // has no parent expr), this must be the tail of the chain. + return parent == nullptr || !isMemberChainMember(parent); +} + /// 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) { + DeclContext *DC, + bool replaceInvalidRefsWithErrors) { // Process UnresolvedDeclRefExpr by doing an unqualified lookup. DeclNameRef Name = UDRE->getName(); SourceLoc Loc = UDRE->getLoc(); + auto errorResult = [&]() -> Expr * { + if (replaceInvalidRefsWithErrors) + return new (DC->getASTContext()) ErrorExpr(UDRE->getSourceRange()); + return UDRE; + }; + // Perform standard value name lookup. NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions; if (isa(DC)) @@ -496,6 +543,9 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, // name/module qualifier to access top-level name. lookupOptions |= NameLookupFlags::IncludeOuterResults; + if (Loc.isInvalid()) + DC = DC->getModuleScopeContext(); + auto Lookup = TypeChecker::lookupUnqualified(DC, Name, Loc, lookupOptions); auto &Context = DC->getASTContext(); @@ -506,7 +556,7 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, if (diagnoseRangeOperatorMisspell(Context.Diags, UDRE) || diagnoseIncDecOperator(Context.Diags, UDRE) || diagnoseOperatorJuxtaposition(UDRE, DC)) { - return new (Context) ErrorExpr(UDRE->getSourceRange()); + return errorResult(); } // Try ignoring access control. @@ -531,7 +581,7 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, // Don't try to recover here; we'll get more access-related diagnostics // downstream if the type of the inaccessible decl is also inaccessible. - return new (Context) ErrorExpr(UDRE->getSourceRange()); + return errorResult(); } // TODO: Name will be a compound name if it was written explicitly as @@ -625,7 +675,7 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, // TODO: consider recovering from here. We may want some way to suppress // downstream diagnostics, though. - return new (Context) ErrorExpr(UDRE->getSourceRange()); + return errorResult(); } // FIXME: Need to refactor the way we build an AST node from a lookup result! @@ -916,6 +966,10 @@ namespace { Expr *ParentExpr; + /// Indicates whether pre-check is allowed to insert + /// implicit `ErrorExpr` in place of invalid references. + bool UseErrorExprs; + /// A stack of expressions being walked, used to determine where to /// insert RebindSelfInConstructorExpr nodes. llvm::SmallVector ExprStack; @@ -962,12 +1016,12 @@ namespace { public: StrangeInterpolationRewriter(ASTContext &Ctx) : Context(Ctx) {} - virtual bool walkToDeclPre(Decl *D) { + virtual bool walkToDeclPre(Decl *D) override { // We don't want to look inside decls. return false; } - virtual std::pair walkToExprPre(Expr *E) { + virtual std::pair walkToExprPre(Expr *E) override { // One InterpolatedStringLiteralExpr should never be nested inside // another except as a child of a CallExpr, and we don't recurse into // the children of CallExprs. @@ -1055,8 +1109,10 @@ namespace { } public: - PreCheckExpression(DeclContext *dc, Expr *parent) - : Ctx(dc->getASTContext()), DC(dc), ParentExpr(parent) {} + PreCheckExpression(DeclContext *dc, Expr *parent, + bool replaceInvalidRefsWithErrors) + : Ctx(dc->getASTContext()), DC(dc), ParentExpr(parent), + UseErrorExprs(replaceInvalidRefsWithErrors) {} ASTContext &getASTContext() const { return Ctx; } @@ -1072,13 +1128,6 @@ namespace { } } - // If this is an unresolved member with a call argument (e.g., - // .some(x)), record the argument expression. - if (auto unresolvedMember = dyn_cast(expr)) { - if (auto arg = unresolvedMember->getArgument()) - CallArgs.insert(arg); - } - // FIXME(diagnostics): `InOutType` could appear here as a result // of successful re-typecheck of the one of the sub-expressions e.g. // `let _: Int = { (s: inout S) in s.bar() }`. On the first @@ -1122,7 +1171,8 @@ namespace { if (auto unresolved = dyn_cast(expr)) { TypeChecker::checkForForbiddenPrefix( getASTContext(), unresolved->getName().getBaseName()); - return finish(true, TypeChecker::resolveDeclRefExpr(unresolved, DC)); + return finish(true, TypeChecker::resolveDeclRefExpr(unresolved, DC, + UseErrorExprs)); } // Let's try to figure out if `InOutExpr` is out of place early @@ -1312,6 +1362,14 @@ namespace { if (auto *simplified = simplifyTypeConstructionWithLiteralArg(expr)) return simplified; + // If we find an unresolved member chain, wrap it in an + // UnresolvedMemberChainResultExpr (unless this has already been done). + auto *parent = Parent.getAsExpr(); + if (isMemberChainTail(expr, parent)) + if (auto *UME = TypeChecker::getUnresolvedMemberChainBase(expr)) + if (!parent || !isa(parent)) + return new (ctx) UnresolvedMemberChainResultExpr(expr, UME); + return expr; } @@ -1900,7 +1958,6 @@ void PreCheckExpression::resolveKeyPathExpr(KeyPathExpr *KPE) { // Key paths must be spelled with at least one component. if (components.empty()) { - DE.diagnose(KPE->getLoc(), diag::expr_swift_keypath_empty); // Passes further down the pipeline expect keypaths to always have at least // one component, so stuff an invalid component in the AST for recovery. components.push_back(KeyPathExpr::Component()); @@ -1980,8 +2037,9 @@ Expr *PreCheckExpression::simplifyTypeConstructionWithLiteralArg(Expr *E) { /// Pre-check the expression, validating any types that occur in the /// expression and folding sequence expressions. -bool ConstraintSystem::preCheckExpression(Expr *&expr, DeclContext *dc) { - PreCheckExpression preCheck(dc, expr); +bool ConstraintSystem::preCheckExpression(Expr *&expr, DeclContext *dc, + bool replaceInvalidRefsWithErrors) { + PreCheckExpression preCheck(dc, expr, replaceInvalidRefsWithErrors); // Perform the pre-check. if (auto result = expr->walk(preCheck)) { expr = result; @@ -2108,7 +2166,8 @@ TypeChecker::typeCheckExpression( // First, pre-check the expression, validating any types that occur in the // expression and folding sequence expressions. - if (ConstraintSystem::preCheckExpression(expr, dc)) { + if (ConstraintSystem::preCheckExpression( + expr, dc, /*replaceInvalidRefsWithErrors=*/true)) { target.setExpr(expr); return None; } @@ -2337,13 +2396,15 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) { // Precheck the sequence. Expr *sequence = stmt->getSequence(); - if (ConstraintSystem::preCheckExpression(sequence, dc)) + if (ConstraintSystem::preCheckExpression( + sequence, dc, /*replaceInvalidRefsWithErrors=*/true)) return failed(); stmt->setSequence(sequence); // Precheck the filtering condition. if (Expr *whereExpr = stmt->getWhere()) { - if (ConstraintSystem::preCheckExpression(whereExpr, dc)) + if (ConstraintSystem::preCheckExpression( + whereExpr, dc, /*replaceInvalidRefsWithErrors=*/true)) return failed(); stmt->setWhere(whereExpr); @@ -2401,8 +2462,9 @@ bool TypeChecker::typeCheckExprPattern(ExprPattern *EP, DeclContext *DC, auto lookupOptions = defaultUnqualifiedLookupOptions; lookupOptions |= NameLookupFlags::KnownPrivate; auto matchLookup = - lookupUnqualified(DC, DeclNameRef(Context.Id_MatchOperator), SourceLoc(), - lookupOptions); + lookupUnqualified(DC->getModuleScopeContext(), + DeclNameRef(Context.Id_MatchOperator), + SourceLoc(), lookupOptions); auto &diags = DC->getASTContext().Diags; if (!matchLookup) { diags.diagnose(EP->getLoc(), diag::no_match_operator); @@ -2905,7 +2967,7 @@ void ConstraintSystem::print(raw_ostream &out) const { out << " as "; Type(fixed).print(out, PO); } else { - getPotentialBindings(tv).dump(out, 1); + inferBindingsFor(tv).dump(out, 1); } } else { out << " equivalent to "; @@ -3109,21 +3171,14 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType, return CheckedCastKind::ValueCast; }; - // Strip optional wrappers off of the destination type in sync with - // stripping them off the origin type. + // TODO: Explore optionals using the same strategy used by the + // runtime. + // For now, if the target is more optional than the source, + // just defer it out for the runtime to handle. while (auto toValueType = toType->getOptionalObjectType()) { - // Complain if we're trying to increase optionality, e.g. - // casting an NSObject? to an NSString??. That's not a subtype - // relationship. auto fromValueType = fromType->getOptionalObjectType(); if (!fromValueType) { - if (!suppressDiagnostics) { - diags.diagnose(diagLoc, diag::downcast_to_more_optional, - origFromType, origToType) - .highlight(diagFromRange) - .highlight(diagToRange); - } - return CheckedCastKind::Unresolved; + return CheckedCastKind::ValueCast; } toType = toValueType; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index d8fb606a5c388..9956f191bc4ab 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -25,7 +25,6 @@ #include "TypeCheckType.h" #include "MiscDiagnostics.h" #include "swift/AST/AccessScope.h" -#include "swift/AST/ASTMangler.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTWalker.h" @@ -583,7 +582,7 @@ IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { // Property wrapper storage wrappers are final if the original property // is final. if (auto *original = VD->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { if (original->isFinal()) return true; } @@ -1066,7 +1065,7 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, if (TypeChecker::typeCheckExpression(exprToCheck, ED, rawTy, CTP_EnumCaseRawValue)) { - TypeChecker::checkEnumElementErrorHandling(elt, exprToCheck); + TypeChecker::checkEnumElementEffects(elt, exprToCheck); } } @@ -1682,7 +1681,7 @@ IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator, switch (decl->getKind()) { case DeclKind::Func: { - TyR = cast(decl)->getBodyResultTypeLoc().getTypeRepr(); + TyR = cast(decl)->getResultTypeRepr(); break; } @@ -1693,14 +1692,14 @@ IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator, auto *storage = accessor->getStorage(); if (auto *subscript = dyn_cast(storage)) - TyR = subscript->getElementTypeLoc().getTypeRepr(); + TyR = subscript->getElementTypeRepr(); else TyR = cast(storage)->getTypeReprOrParentPatternTypeRepr(); break; } case DeclKind::Subscript: - TyR = cast(decl)->getElementTypeLoc().getTypeRepr(); + TyR = cast(decl)->getElementTypeRepr(); break; case DeclKind::Param: { @@ -2003,7 +2002,12 @@ ResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { } } - auto *resultTyRepr = getResultTypeLoc().getTypeRepr(); + TypeRepr *resultTyRepr = nullptr; + if (const auto *const funcDecl = dyn_cast(decl)) { + resultTyRepr = funcDecl->getResultTypeRepr(); + } else { + resultTyRepr = cast(decl)->getElementTypeRepr(); + } // Nothing to do if there's no result type. if (resultTyRepr == nullptr) @@ -2148,9 +2152,21 @@ static Type validateParameterType(ParamDecl *decl) { decl->setInvalid(); return ErrorType::get(ctx); } + } - return Ty; + // async autoclosures can only occur as parameters to async functions. + if (decl->isAutoClosure()) { + if (auto fnType = Ty->getAs()) { + if (fnType->isAsync() && + !(isa(dc) && + cast(dc)->isAsyncContext())) { + decl->diagnose(diag::async_autoclosure_nonasync_function); + if (auto func = dyn_cast(dc)) + addAsyncNotes(func); + } + } } + return Ty; } @@ -2446,21 +2462,16 @@ namespace { // Utility class for deterministically ordering vtable entries for // synthesized methods. struct SortedFuncList { - using Entry = std::pair; + using Key = std::tuple; + using Entry = std::pair; SmallVector elts; bool sorted = false; void add(AbstractFunctionDecl *afd) { - Mangle::ASTMangler mangler; - std::string mangledName; - if (auto *cd = dyn_cast(afd)) - mangledName = mangler.mangleConstructorEntity(cd, /*allocator=*/false); - else if (auto *dd = dyn_cast(afd)) - mangledName = mangler.mangleDestructorEntity(dd, /*deallocating=*/false); - else - mangledName = mangler.mangleEntity(afd); + assert(!isa(afd)); - elts.push_back(std::make_pair(mangledName, afd)); + Key key{afd->getName(), afd->getInterfaceType().getString()}; + elts.emplace_back(key, afd); } bool empty() { return elts.empty(); } @@ -2489,60 +2500,52 @@ struct SortedFuncList { } // end namespace ArrayRef -EmittedMembersRequest::evaluate(Evaluator &evaluator, - ClassDecl *CD) const { - auto &Context = CD->getASTContext(); +SemanticMembersRequest::evaluate(Evaluator &evaluator, + IterableDeclContext *idc) const { + auto dc = cast(idc->getDecl()); + auto &Context = dc->getASTContext(); SmallVector result; - if (!CD->getParentSourceFile()) { - auto members = CD->getMembers(); + if (!dc->getParentSourceFile()) { + auto members = idc->getMembers(); result.append(members.begin(), members.end()); return Context.AllocateCopy(result); } - // We need to add implicit initializers because they - // affect vtable layout. - TypeChecker::addImplicitConstructors(CD); + auto nominal = dyn_cast(idc); - auto forceConformance = [&](ProtocolDecl *protocol) { - auto ref = CD->getParentModule()->lookupConformance( - CD->getDeclaredInterfaceType(), protocol); - if (ref.isInvalid()) { - return; - } + if (nominal) { + // We need to add implicit initializers because they + // affect vtable layout. + TypeChecker::addImplicitConstructors(nominal); + } - auto conformance = ref.getConcrete(); - if (conformance->getDeclContext() == CD && - conformance->getState() == ProtocolConformanceState::Incomplete) { + // Force any derivable conformances in this context. This ensures that any + // synthesized members will approach in the member list. + for (auto conformance : idc->getLocalConformances()) { + if (conformance->getState() == ProtocolConformanceState::Incomplete && + conformance->getProtocol()->getKnownDerivableProtocolKind()) TypeChecker::checkConformance(conformance->getRootNormalConformance()); - } - }; + } - // If the class is Encodable, Decodable or Hashable, force those - // conformances to ensure that the synthesized members appear in the vtable. - // - // FIXME: Generalize this to other protocols for which - // we can derive conformances. - forceConformance(Context.getProtocol(KnownProtocolKind::Decodable)); - forceConformance(Context.getProtocol(KnownProtocolKind::Encodable)); - forceConformance(Context.getProtocol(KnownProtocolKind::Hashable)); - forceConformance(Context.getProtocol(KnownProtocolKind::Differentiable)); - - // If the class conforms to Encodable or Decodable, even via an extension, + // If the type conforms to Encodable or Decodable, even via an extension, // the CodingKeys enum is synthesized as a member of the type itself. // Force it into existence. - (void) evaluateOrDefault(Context.evaluator, - ResolveImplicitMemberRequest{CD, - ImplicitMemberAction::ResolveCodingKeys}, - {}); + if (nominal) { + (void) evaluateOrDefault(Context.evaluator, + ResolveImplicitMemberRequest{nominal, + ImplicitMemberAction::ResolveCodingKeys}, + {}); + } - // If the class has a @main attribute, we need to force synthesis of the + // If the decl has a @main attribute, we need to force synthesis of the // $main function. - (void) evaluateOrDefault(Context.evaluator, - SynthesizeMainFunctionRequest{CD}, - nullptr); + (void) evaluateOrDefault( + Context.evaluator, + SynthesizeMainFunctionRequest{const_cast(idc->getDecl())}, + nullptr); - for (auto *member : CD->getMembers()) { + for (auto *member : idc->getMembers()) { if (auto *var = dyn_cast(member)) { // The projected storage wrapper ($foo) might have dynamically-dispatched // accessors, so force them to be synthesized. @@ -2553,7 +2556,7 @@ EmittedMembersRequest::evaluate(Evaluator &evaluator, SortedFuncList synthesizedMembers; - for (auto *member : CD->getMembers()) { + for (auto *member : idc->getMembers()) { if (auto *afd = dyn_cast(member)) { // Add synthesized members to a side table and sort them by their mangled // name, since they could have been added to the class in any order. diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index c6b98e0991863..617cb07357fa6 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -494,8 +494,11 @@ static bool isValidObjectiveCErrorResultType(DeclContext *dc, Type type) { bool swift::isRepresentableInObjC( const AbstractFunctionDecl *AFD, ObjCReason Reason, + Optional &asyncConvention, Optional &errorConvention) { - // Clear out the error convention. It will be added later if needed. + // Clear out the async and error conventions. They will be added later if + // needed. + asyncConvention = None; errorConvention = None; // If you change this function, you must add or modify a test in PrintAsObjC. @@ -596,7 +599,8 @@ bool swift::isRepresentableInObjC( if (auto FD = dyn_cast(AFD)) { Type ResultType = FD->mapTypeIntoContext(FD->getResultInterfaceType()); - if (!ResultType->hasError() && + if (!FD->hasAsync() && + !ResultType->hasError() && !ResultType->isVoid() && !ResultType->isUninhabited() && !ResultType->isRepresentableIn(ForeignLanguage::ObjectiveC, @@ -604,27 +608,103 @@ bool swift::isRepresentableInObjC( if (Diagnose) { AFD->diagnose(diag::objc_invalid_on_func_result_type, getObjCDiagnosticAttrKind(Reason)); - SourceRange Range = - FD->getBodyResultTypeLoc().getTypeRepr()->getSourceRange(); - diagnoseTypeNotRepresentableInObjC(FD, ResultType, Range); + diagnoseTypeNotRepresentableInObjC(FD, ResultType, + FD->getResultTypeSourceRange()); describeObjCReason(FD, Reason); } return false; } } - // Async functions cannot be mapped into Objective-C. if (AFD->hasAsync()) { - if (Diagnose) { - AFD->diagnose(diag::not_objc_function_async) - .highlight(AFD->getAsyncLoc()); - describeObjCReason(AFD, Reason); + // Asynchronous functions move all of the result value and thrown error + // information into a completion handler. + auto FD = dyn_cast(AFD); + if (!FD) { + if (Diagnose) { + AFD->diagnose(diag::not_objc_function_async) + .highlight(AFD->getAsyncLoc()); + describeObjCReason(AFD, Reason); + } + + return false; } - return false; - } - // Throwing functions must map to a particular error convention. - if (AFD->hasThrows()) { + // The completion handler transformation cannot properly represent a + // dynamic 'Self' type, so disallow @objc for such methods. + if (FD->hasDynamicSelfResult()) { + if (Diagnose) { + AFD->diagnose(diag::async_objc_dynamic_self) + .highlight(AFD->getAsyncLoc()); + describeObjCReason(AFD, Reason); + } + + return false; + } + + // The completion handler parameter always goes at the end. + unsigned completionHandlerParamIndex = AFD->getParameters()->size(); + + // Decompose the return type to form the parameter type of the completion + // handler. + SmallVector completionHandlerParams; + auto addCompletionHandlerParam = [&](Type type) { + // For a throwing asynchronous function, make each parameter type optional + // if that's representable in Objective-C. + if (AFD->hasThrows() && + !type->getOptionalObjectType() && + isValidObjectiveCErrorResultType(const_cast(FD), type)) { + type = OptionalType::get(type); + } + + completionHandlerParams.push_back(AnyFunctionType::Param(type)); + + // Make sure that the paraneter type is representable in Objective-C. + if (!type->isRepresentableIn( + ForeignLanguage::ObjectiveC, const_cast(FD))) { + if (Diagnose) { + AFD->diagnose(diag::objc_invalid_on_func_result_type, + getObjCDiagnosticAttrKind(Reason)); + diagnoseTypeNotRepresentableInObjC(FD, type, + FD->getResultTypeSourceRange()); + describeObjCReason(FD, Reason); + } + + return true; + } + + return false; + }; + + // Translate the result type of the function into parameters for the + // completion handler parameter, exploding one level of tuple if needed. + Type resultType = FD->mapTypeIntoContext(FD->getResultInterfaceType()); + if (auto tupleType = resultType->getAs()) { + for (const auto &tupleElt : tupleType->getElements()) { + addCompletionHandlerParam(tupleElt.getType()); + } + } else { + addCompletionHandlerParam(resultType); + } + + // For a throwing asynchronous function, an Error? parameter is added + // to the completion handler parameter, and will be non-nil to signal + // a thrown error. + Optional completionHandlerErrorParamIndex; + if (FD->hasThrows()) { + completionHandlerErrorParamIndex = completionHandlerParams.size(); + addCompletionHandlerParam(OptionalType::get(ctx.getExceptionType())); + } + + Type completionHandlerType = FunctionType::get( + completionHandlerParams, TupleType::getEmpty(ctx), + ASTExtInfoBuilder(FunctionTypeRepresentation::Block, false).build()); + + asyncConvention = ForeignAsyncConvention( + completionHandlerType->getCanonicalType(), completionHandlerParamIndex, + completionHandlerErrorParamIndex); + } else if (AFD->hasThrows()) { + // Synchronous throwing functions must map to a particular error convention. DeclContext *dc = const_cast(AFD); SourceLoc throwsLoc; Type resultType; @@ -928,7 +1008,7 @@ bool swift::isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason) { if (!IndexResult) TypeRange = SD->getIndices()->getSourceRange(); else - TypeRange = SD->getElementTypeLoc().getSourceRange(); + TypeRange = SD->getElementTypeSourceRange(); SD->diagnose(diag::objc_invalid_on_subscript, getObjCDiagnosticAttrKind(Reason)) .highlight(TypeRange); @@ -948,9 +1028,10 @@ bool swift::canBeRepresentedInObjC(const ValueDecl *decl) { return false; if (auto func = dyn_cast(decl)) { + Optional asyncConvention; Optional errorConvention; return isRepresentableInObjC(func, ObjCReason::MemberOfObjCMembersClass, - errorConvention); + asyncConvention, errorConvention); } if (auto var = dyn_cast(decl)) @@ -1307,6 +1388,7 @@ static bool isEnumObjC(EnumDecl *enumDecl) { /// Record that a declaration is @objc. static void markAsObjC(ValueDecl *D, ObjCReason reason, + Optional asyncConvention, Optional errorConvention); @@ -1394,6 +1476,7 @@ bool IsObjCRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const { } // If needed, check whether this declaration is representable in Objective-C. + Optional asyncConvention; Optional errorConvention; if (auto var = dyn_cast(VD)) { if (!isRepresentableInObjC(var, *isObjC)) { @@ -1408,14 +1491,15 @@ bool IsObjCRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const { } else if (isa(VD)) { // Destructors need no additional checking. } else if (auto func = dyn_cast(VD)) { - if (!isRepresentableInObjC(func, *isObjC, errorConvention)) { + if (!isRepresentableInObjC( + func, *isObjC, asyncConvention, errorConvention)) { makeNotObjC(); return false; } } // Note that this declaration is exposed to Objective-C. - markAsObjC(VD, *isObjC, errorConvention); + markAsObjC(VD, *isObjC, asyncConvention, errorConvention); return true; } @@ -1571,6 +1655,7 @@ static ObjCSelector inferObjCName(ValueDecl *decl) { /// If the declaration has a @nonobjc attribute, diagnose an error /// using the given Reason, if present. void markAsObjC(ValueDecl *D, ObjCReason reason, + Optional asyncConvention, Optional errorConvention) { ASTContext &ctx = D->getASTContext(); @@ -1588,19 +1673,28 @@ void markAsObjC(ValueDecl *D, ObjCReason reason, } if (auto method = dyn_cast(D)) { - // Determine the foreign error convention. - Optional inheritedConvention; - AbstractFunctionDecl *declProvidingInheritedConvention = nullptr; + // Determine the foreign async and error conventions. + Optional inheritedAsyncConvention; + AbstractFunctionDecl *declProvidingInheritedAsyncConvention = nullptr; + Optional inheritedErrorConvention; + AbstractFunctionDecl *declProvidingInheritedErrorConvention = nullptr; if (auto baseMethod = method->getOverriddenDecl()) { - // If the overridden method has a foreign error convention, - // adopt it. Set the foreign error convention for a throwing - // method. Note that the foreign error convention affects the + // If the overridden method has a foreign async or error convention, + // adopt it. Note that the foreign async or error convention affects the // selector, so we perform this before inferring a selector. + if (method->hasAsync()) { + if (auto baseAsyncConvention + = baseMethod->getForeignAsyncConvention()) { + inheritedAsyncConvention = baseAsyncConvention; + declProvidingInheritedAsyncConvention = baseMethod; + } + } + if (method->hasThrows()) { if (auto baseErrorConvention = baseMethod->getForeignErrorConvention()) { - inheritedConvention = baseErrorConvention; - declProvidingInheritedConvention = baseMethod; + inheritedErrorConvention = baseErrorConvention; + declProvidingInheritedErrorConvention = baseMethod; } } } @@ -1608,42 +1702,78 @@ void markAsObjC(ValueDecl *D, ObjCReason reason, for (auto req : findWitnessedObjCRequirements(method)) { auto reqMethod = dyn_cast(req); if (!reqMethod) continue; - + + // If the method witnesses an ObjC requirement that is async, adopt its + // async convention. + if (reqMethod->hasAsync()) { + if (auto reqAsyncConvention = reqMethod->getForeignAsyncConvention()) { + // Check for a conflict among protocol conformances or inherited + // methods. + if (declProvidingInheritedAsyncConvention + && inheritedAsyncConvention != reqAsyncConvention) { + method->diagnose(diag::objc_ambiguous_async_convention, + method->getName()); + declProvidingInheritedAsyncConvention->diagnose( + diag::objc_ambiguous_async_convention_candidate, + declProvidingInheritedAsyncConvention->getName()); + reqMethod->diagnose(diag::objc_ambiguous_async_convention_candidate, + reqMethod->getName()); + break; + } + + inheritedAsyncConvention = reqAsyncConvention; + declProvidingInheritedAsyncConvention = reqMethod; + } + } + // If the method witnesses an ObjC requirement that throws, adopt its // error convention. if (reqMethod->hasThrows()) { if (auto reqErrorConvention = reqMethod->getForeignErrorConvention()) { // Check for a conflict among protocol conformances or inherited // methods. - if (declProvidingInheritedConvention - && inheritedConvention != reqErrorConvention) { + if (declProvidingInheritedErrorConvention + && inheritedErrorConvention != reqErrorConvention) { method->diagnose(diag::objc_ambiguous_error_convention, method->getName()); - declProvidingInheritedConvention->diagnose( - diag::objc_ambiguous_error_convention_candidate, - declProvidingInheritedConvention->getName()); + declProvidingInheritedErrorConvention->diagnose( + diag::objc_ambiguous_error_convention_candidate, + declProvidingInheritedErrorConvention->getName()); reqMethod->diagnose(diag::objc_ambiguous_error_convention_candidate, reqMethod->getName()); break; } - inheritedConvention = reqErrorConvention; - declProvidingInheritedConvention = reqMethod; + inheritedErrorConvention = reqErrorConvention; + declProvidingInheritedErrorConvention = reqMethod; } } } + // Attach the foreign async convention. + if (inheritedAsyncConvention) { + if (!method->hasAsync()) + method->diagnose(diag::satisfy_async_objc, + isa(method)); + else + method->setForeignAsyncConvention(*inheritedAsyncConvention); + + } else if (method->hasAsync()) { + assert(asyncConvention && "Missing async convention"); + method->setForeignAsyncConvention(*asyncConvention); + } + // Attach the foreign error convention. - if (inheritedConvention) { + if (inheritedErrorConvention) { // Diagnose if this is a method that does not throw - // but inherits an ObjC error convention. + // but inherits an ObjC error convention. if (!method->hasThrows()) method->diagnose(diag::satisfy_throws_objc, isa(method)); else - method->setForeignErrorConvention(*inheritedConvention); + method->setForeignErrorConvention(*inheritedErrorConvention); - } else if (method->hasThrows()) { + } else if (method->hasThrows() && !method->hasAsync()) { assert(errorConvention && "Missing error convention"); method->setForeignErrorConvention(*errorConvention); } diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 9be81b3cdb722..153c37ed7df83 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1169,7 +1169,8 @@ bool OverrideMatcher::checkOverride(ValueDecl *baseDecl, // Private migration help for overrides of Objective-C methods. TypeLoc resultTL; if (auto *methodAsFunc = dyn_cast(method)) - resultTL = methodAsFunc->getBodyResultTypeLoc(); + resultTL = TypeLoc(methodAsFunc->getResultTypeRepr(), + methodAsFunc->getResultInterfaceType()); emittedMatchError |= diagnoseMismatchedOptionals( method, method->getParameters(), resultTL, baseDecl, @@ -1197,9 +1198,11 @@ bool OverrideMatcher::checkOverride(ValueDecl *baseDecl, emittedMatchError = true; } else if (mayHaveMismatchedOptionals) { + TypeLoc elementTL(subscript->getElementTypeRepr(), + subscript->getElementInterfaceType()); emittedMatchError |= diagnoseMismatchedOptionals( subscript, subscript->getIndices(), - subscript->getElementTypeLoc(), baseDecl, + elementTL, baseDecl, cast(baseDecl)->getIndices(), owningTy, mayHaveMismatchedOptionals); } @@ -1416,6 +1419,7 @@ namespace { UNINTERESTING_ATTR(AccessControl) UNINTERESTING_ATTR(Alignment) UNINTERESTING_ATTR(AlwaysEmitIntoClient) + UNINTERESTING_ATTR(AsyncHandler) UNINTERESTING_ATTR(Borrowed) UNINTERESTING_ATTR(CDecl) UNINTERESTING_ATTR(Consuming) diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index c307cca174ce5..e999479912259 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -754,35 +754,38 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const { declToDiagnose->diagnose(diag::invalid_redecl_implicit, current->getDescriptiveKind(), isProtocolRequirement, other->getName()); - } - // Emit a specialized note if the one of the declarations is - // the backing storage property ('_foo') or projected value - // property ('$foo') for a wrapped property. The backing or - // projected var has the same source location as the wrapped - // property we diagnosed above, so we don't need to extract - // the original property. - const VarDecl *varToDiagnose = nullptr; - auto kind = PropertyWrapperSynthesizedPropertyKind::Backing; - if (auto currentVD = dyn_cast(current)) { - if (auto currentKind = - currentVD->getPropertyWrapperSynthesizedPropertyKind()) { - varToDiagnose = currentVD; - kind = *currentKind; + // Emit a specialized note if the one of the declarations is + // the backing storage property ('_foo') or projected value + // property ('$foo') for a wrapped property. The backing or + // projected var has the same source location as the wrapped + // property we diagnosed above, so we don't need to extract + // the original property. + const VarDecl *varToDiagnose = nullptr; + auto kind = PropertyWrapperSynthesizedPropertyKind::Backing; + if (auto currentVD = dyn_cast(current)) { + if (auto currentKind = + currentVD->getPropertyWrapperSynthesizedPropertyKind()) { + varToDiagnose = currentVD; + kind = *currentKind; + } } - } - if (auto otherVD = dyn_cast(other)) { - if (auto otherKind = - otherVD->getPropertyWrapperSynthesizedPropertyKind()) { - varToDiagnose = otherVD; - kind = *otherKind; + if (auto otherVD = dyn_cast(other)) { + if (auto otherKind = + otherVD->getPropertyWrapperSynthesizedPropertyKind()) { + varToDiagnose = otherVD; + kind = *otherKind; + } } - } - if (varToDiagnose) { - varToDiagnose->diagnose( - diag::invalid_redecl_implicit_wrapper, varToDiagnose->getName(), - kind == PropertyWrapperSynthesizedPropertyKind::Backing); + if (varToDiagnose) { + assert(declToDiagnose); + varToDiagnose->diagnose( + diag::invalid_redecl_implicit_wrapper, varToDiagnose->getName(), + kind == PropertyWrapperSynthesizedPropertyKind::Backing); + } + + current->setInvalid(); } } else { ctx.Diags.diagnoseWithNotes( @@ -790,8 +793,9 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const { current->getName()), [&]() { other->diagnose(diag::invalid_redecl_prev, other->getName()); }); + + current->setInvalid(); } - current->setInvalid(); } // Make sure we don't do this checking again for the same decl. We also @@ -881,7 +885,7 @@ Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator, return new (ctx) ErrorExpr(initExpr->getSourceRange(), ErrorType::get(ctx)); } - TypeChecker::checkInitializerErrorHandling(dc, initExpr); + TypeChecker::checkInitializerEffects(dc, initExpr); // Walk the checked initializer and contextualize any closures // we saw there. @@ -1136,8 +1140,7 @@ static void diagnoseClassWithoutInitializers(ClassDecl *classDecl) { { C, DeclBaseName::createConstructor(), { C.Id_from } }); auto result = TypeChecker::lookupMember(superclassDecl, superclassType, initFrom, - NameLookupFlags::ProtocolMembers | - NameLookupFlags::IgnoreAccessControl); + NameLookupFlags::IgnoreAccessControl); if (!result.empty() && !result.front().getValueDecl()->isImplicit()) diagDest = result.front().getValueDecl(); @@ -1657,7 +1660,7 @@ class DeclChecker : public DeclVisitor { PBD->getInitContext(i)); if (initContext) { // Check safety of error-handling in the declaration, too. - TypeChecker::checkInitializerErrorHandling(initContext, init); + TypeChecker::checkInitializerEffects(initContext, init); TypeChecker::contextualizeInitializer(initContext, init); } } @@ -1850,9 +1853,11 @@ class DeclChecker : public DeclVisitor { if (auto rawTy = ED->getRawType()) { // The raw type must be one of the blessed literal convertible types. if (!computeAutomaticEnumValueKind(ED)) { - DE.diagnose(ED->getInherited().front().getSourceRange().Start, - diag::raw_type_not_literal_convertible, rawTy); - ED->getInherited().front().setInvalidType(getASTContext()); + if (!rawTy->is()) { + DE.diagnose(ED->getInherited().front().getSourceRange().Start, + diag::raw_type_not_literal_convertible, rawTy); + ED->getInherited().front().setType(ErrorType::get(getASTContext())); + } } // We need at least one case to have a raw value. @@ -2012,7 +2017,7 @@ class DeclChecker : public DeclVisitor { TypeChecker::checkDeclAttributes(CD); - for (Decl *Member : CD->getEmittedMembers()) + for (Decl *Member : CD->getSemanticMembers()) visit(Member); TypeChecker::checkPatternBindingCaptures(CD); @@ -2342,10 +2347,15 @@ class DeclChecker : public DeclVisitor { // FIXME: This needs to be moved to its own request if we want to // productize @_cdecl. if (auto CDeclAttr = FD->getAttrs().getAttribute()) { + Optional asyncConvention; Optional errorConvention; if (isRepresentableInObjC(FD, ObjCReason::ExplicitlyCDecl, - errorConvention)) { - if (FD->hasThrows()) { + asyncConvention, errorConvention)) { + if (FD->hasAsync()) { + FD->setForeignAsyncConvention(*asyncConvention); + getASTContext().Diags.diagnose(CDeclAttr->getLocation(), + diag::cdecl_async); + } else if (FD->hasThrows()) { FD->setForeignErrorConvention(*errorConvention); getASTContext().Diags.diagnose(CDeclAttr->getLocation(), diag::cdecl_throws); diff --git a/lib/Sema/TypeCheckError.cpp b/lib/Sema/TypeCheckEffects.cpp similarity index 79% rename from lib/Sema/TypeCheckError.cpp rename to lib/Sema/TypeCheckEffects.cpp index 92819337f75dc..09b4eaf4a3297 100644 --- a/lib/Sema/TypeCheckError.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -1,4 +1,4 @@ -//===--- TypeCheckError.cpp - Type Checking for Error Coverage ------------===// +//===--- TypeCheckEffects.cpp - Type Checking for Effects Coverage --------===// // // This source file is part of the Swift.org open source project // @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// // -// This file implements semantic analysis to ensure that errors are -// caught. +// This file implements semantic analysis to ensure that various effects (such +// as throwing and async) are properly handled. // //===----------------------------------------------------------------------===// @@ -184,9 +184,9 @@ enum ShouldRecurse_t : bool { }; /// A CRTP ASTWalker implementation that looks for interesting -/// nodes for error handling. +/// nodes for effects handling. template -class ErrorHandlingWalker : public ASTWalker { +class EffectsHandlingWalker : public ASTWalker { Impl &asImpl() { return *static_cast(this); } public: bool walkToDeclPre(Decl *D) override { @@ -221,7 +221,7 @@ class ErrorHandlingWalker : public ASTWalker { } else if (auto interpolated = dyn_cast(E)) { recurse = asImpl().checkInterpolatedStringLiteral(interpolated); } - // Error handling validation (via checkTopLevelErrorHandling) happens after + // Error handling validation (via checkTopLevelEffects) happens after // type checking. If an unchecked expression is still around, the code was // invalid. #define UNCHECKED_EXPR(KIND, BASE) \ @@ -253,7 +253,7 @@ class ErrorHandlingWalker : public ASTWalker { }; /// A potential reason why something might throw. -class PotentialReason { +class PotentialThrowReason { public: enum class Kind : uint8_t { /// The function throws unconditionally. @@ -275,21 +275,21 @@ class PotentialReason { Expr *TheExpression; Kind TheKind; - explicit PotentialReason(Kind kind) : TheKind(kind) {} + explicit PotentialThrowReason(Kind kind) : TheKind(kind) {} public: - static PotentialReason forRethrowsArgument(Expr *E) { - PotentialReason result(Kind::CallRethrowsWithExplicitThrowingArgument); + static PotentialThrowReason forRethrowsArgument(Expr *E) { + PotentialThrowReason result(Kind::CallRethrowsWithExplicitThrowingArgument); result.TheExpression = E; return result; } - static PotentialReason forDefaultArgument() { - return PotentialReason(Kind::CallRethrowsWithDefaultThrowingArgument); + static PotentialThrowReason forDefaultArgument() { + return PotentialThrowReason(Kind::CallRethrowsWithDefaultThrowingArgument); } - static PotentialReason forThrowingApply() { - return PotentialReason(Kind::CallThrows); + static PotentialThrowReason forThrowingApply() { + return PotentialThrowReason(Kind::CallThrows); } - static PotentialReason forThrow() { - return PotentialReason(Kind::Throw); + static PotentialThrowReason forThrow() { + return PotentialThrowReason(Kind::Throw); } Kind getKind() const { return TheKind; } @@ -321,16 +321,16 @@ enum class ThrowingKind { }; /// A type expressing the result of classifying whether a call or function -/// throws. +/// throws or is async. class Classification { bool IsInvalid = false; // The AST is malformed. Don't diagnose. bool IsAsync = false; ThrowingKind Result = ThrowingKind::None; - Optional Reason; + Optional Reason; public: Classification() : Result(ThrowingKind::None) {} - explicit Classification(ThrowingKind result, PotentialReason reason, + explicit Classification(ThrowingKind result, PotentialThrowReason reason, bool isAsync) : IsAsync(isAsync), Result(result) { if (result == ThrowingKind::Throws || @@ -341,7 +341,7 @@ class Classification { /// Return a classification saying that there's an unconditional /// throw site. - static Classification forThrow(PotentialReason reason, bool isAsync) { + static Classification forThrow(PotentialThrowReason reason, bool isAsync) { Classification result; result.Result = ThrowingKind::Throws; result.Reason = reason; @@ -363,7 +363,7 @@ class Classification { return result; } - static Classification forRethrowingOnly(PotentialReason reason) { + static Classification forRethrowingOnly(PotentialThrowReason reason) { Classification result; result.Result = ThrowingKind::RethrowingOnly; result.Reason = reason; @@ -378,7 +378,7 @@ class Classification { bool isInvalid() const { return IsInvalid; } ThrowingKind getResult() const { return Result; } - PotentialReason getThrowsReason() const { + PotentialThrowReason getThrowsReason() const { assert(getResult() == ThrowingKind::Throws || getResult() == ThrowingKind::RethrowingOnly); return *Reason; @@ -446,7 +446,7 @@ class ApplyClassifier { assert(args.size() > fnRef.getNumArgumentsForFullApply() && "partial application was throwing?"); - return Classification::forThrow(PotentialReason::forThrowingApply(), + return Classification::forThrow(PotentialThrowReason::forThrowingApply(), isAsync); } @@ -476,7 +476,7 @@ class ApplyClassifier { // Try to classify the implementation of functions that we have // local knowledge of. Classification result = - classifyThrowingFunctionBody(fnRef, PotentialReason::forThrowingApply()); + classifyThrowingFunctionBody(fnRef, PotentialThrowReason::forThrowingApply()); assert(result.getResult() != ThrowingKind::None && "body classification decided function was no-throw"); @@ -496,7 +496,7 @@ class ApplyClassifier { /// if the function is an autoclosure that simply doesn't throw at all. Classification classifyThrowingFunctionBody(const AbstractFunction &fn, - PotentialReason reason) { + PotentialThrowReason reason) { // If we're not checking a 'rethrows' context, we don't need to // distinguish between 'throws' and 'rethrows'. But don't even // trust 'throws' for autoclosures. @@ -517,7 +517,7 @@ class ApplyClassifier { } Classification classifyThrowingParameterBody(ParamDecl *param, - PotentialReason reason) { + PotentialThrowReason reason) { assert(param->getType() ->lookThroughAllOptionalTypes() ->castTo() @@ -542,7 +542,7 @@ class ApplyClassifier { } Classification classifyThrowingFunctionBody(AbstractFunctionDecl *fn, - PotentialReason reason) { + PotentialThrowReason reason) { // Functions can't be rethrowing-only unless they're defined // within the rethrows context. if (!isLocallyDefinedInRethrowsContext(fn) || !fn->hasBody()) @@ -556,7 +556,7 @@ class ApplyClassifier { } Classification classifyThrowingFunctionBody(AbstractClosureExpr *closure, - PotentialReason reason) { + PotentialThrowReason reason) { bool isAutoClosure = isa(closure); // Closures can't be rethrowing-only unless they're defined @@ -580,7 +580,7 @@ class ApplyClassifier { } class FunctionBodyClassifier - : public ErrorHandlingWalker { + : public EffectsHandlingWalker { ApplyClassifier &Self; public: bool IsInvalid = false; @@ -705,7 +705,7 @@ class ApplyClassifier { if (isa(arg)) { return classifyArgumentByType(arg->getType(), - PotentialReason::forDefaultArgument()); + PotentialThrowReason::forDefaultArgument()); } // If this argument is `nil` literal, it doesn't cause the call to throw. @@ -736,7 +736,7 @@ class ApplyClassifier { // parameter type included a throwing function type. return classifyArgumentByType( paramType, - PotentialReason::forRethrowsArgument(arg)); + PotentialThrowReason::forRethrowsArgument(arg)); } // FIXME: There's a case where we can end up with an ApplyExpr that @@ -751,7 +751,7 @@ class ApplyClassifier { if (!paramFnType || !paramFnType->isThrowing()) return Classification(); - PotentialReason reason = PotentialReason::forRethrowsArgument(arg); + PotentialThrowReason reason = PotentialThrowReason::forRethrowsArgument(arg); // TODO: partial applications? @@ -793,7 +793,7 @@ class ApplyClassifier { /// a throwing function in a way that is permitted to cause a /// 'rethrows' function to throw. static Classification classifyArgumentByType(Type paramType, - PotentialReason reason) { + PotentialThrowReason reason) { if (!paramType || paramType->hasError()) return Classification::forInvalidCode(); if (auto fnType = paramType->getAs()) { @@ -816,24 +816,12 @@ class ApplyClassifier { } }; -/// An error-handling context. +/// An context in which effects might be handled. class Context { public: enum class Kind : uint8_t { - /// A context that handles errors. - Handled, - - /// A non-throwing function. - NonThrowingFunction, - - /// A rethrowing function. - RethrowingFunction, - - /// A non-throwing autoclosure. - NonThrowingAutoClosure, - - /// A non-exhaustive catch within a non-throwing function. - NonExhaustiveCatch, + /// A context that potentially handles errors or async calls. + PotentiallyHandled, /// A default argument expression. DefaultArgument, @@ -858,26 +846,6 @@ class Context { }; private: - static Kind getKindForFunctionBody(Type type, unsigned numArgs) { - /// Determine whether calling a function of the specified type with the - /// specified number of arguments would throw. - if (!type) return Kind::Handled; - - assert(numArgs > 0); - while (true) { - auto fnType = type->getAs(); - if (!fnType) return Kind::Handled; - - if (fnType->getExtInfo().isThrowing()) - return Kind::Handled; - - if (--numArgs == 0) - return Kind::NonThrowingFunction; - - type = fnType->getResult(); - } - } - static Context getContextForPatternBinding(PatternBindingDecl *pbd) { if (!pbd->isStatic() && pbd->getDeclContext()->isTypeContext()) { return Context(Kind::IVarInitializer); @@ -887,29 +855,67 @@ class Context { } Kind TheKind; + Optional Function; + bool HandlesErrors = false; + bool HandlesAsync = false; + + /// Whether error-handling queries should ignore the function context, e.g., + /// for autoclosure and rethrows checks. + bool ErrorHandlingIgnoresFunction = false; + bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; - DeclContext *RethrowsDC = nullptr; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; - explicit Context(Kind kind) : TheKind(kind) {} + explicit Context(Kind kind) + : TheKind(kind), Function(None), HandlesErrors(false) { + assert(TheKind != Kind::PotentiallyHandled); + } + + explicit Context(bool handlesErrors, bool handlesAsync, + Optional function) + : TheKind(Kind::PotentiallyHandled), Function(function), + HandlesErrors(handlesErrors), HandlesAsync(handlesAsync) { } public: - static Context getHandled() { - return Context(Kind::Handled); + /// Whether this is a function that rethrows. + bool isRethrows() const { + if (!HandlesErrors) + return false; + + if (ErrorHandlingIgnoresFunction) + return false; + + if (!Function) + return false; + + auto fn = Function->getAbstractFunctionDecl(); + if (!fn) + return false; + + return fn->getAttrs().hasAttribute(); + } + + /// Whether this is an autoclosure. + bool isAutoClosure() const { + if (!Function) + return false; + + if (ErrorHandlingIgnoresFunction) + return false; + + auto closure = Function->getAbstractClosureExpr(); + if (!closure) + return false; + + return isa(closure); } static Context forTopLevelCode(TopLevelCodeDecl *D) { - // Top-level code implicitly handles errors. - return Context(Kind::Handled); + // Top-level code implicitly handles errors and 'async' calls. + return Context(/*handlesErrors=*/true, /*handlesAsync=*/true, None); } static Context forFunction(AbstractFunctionDecl *D) { - if (D->getAttrs().hasAttribute()) { - Context result(Kind::RethrowingFunction); - result.RethrowsDC = D; - return result; - } - // HACK: If the decl is the synthesized getter for a 'lazy' property, then // treat the context as a property initializer in order to produce a better // diagnostic; the only code we should be diagnosing on is within the @@ -926,8 +932,7 @@ class Context { } } - return Context(getKindForFunctionBody( - D->getInterfaceType(), D->getNumCurryLevels())); + return Context(D->hasThrows(), D->isAsyncContext(), AnyFunctionRef(D)); } static Context forDeferBody() { @@ -950,14 +955,17 @@ class Context { } static Context forClosure(AbstractClosureExpr *E) { - auto kind = getKindForFunctionBody(E->getType(), 1); - if (kind != Kind::Handled && isa(E)) - kind = Kind::NonThrowingAutoClosure; - return Context(kind); - } + // Determine whether the closure has throwing function type. + bool closureTypeThrows = true; + bool closureTypeIsAsync = true; + if (auto closureType = E->getType()) { + if (auto fnType = closureType->getAs()) { + closureTypeThrows = fnType->isThrowing(); + closureTypeIsAsync = fnType->isAsync(); + } + } - static Context forNonExhaustiveCatch(DoCatchStmt *S) { - return Context(Kind::NonExhaustiveCatch); + return Context(closureTypeThrows, closureTypeIsAsync, AnyFunctionRef(E)); } static Context forCatchPattern(CaseStmt *S) { @@ -978,11 +986,19 @@ class Context { return copy; } + /// Form a subcontext that handles all errors, e.g., for the body of a + /// do-catch with exhaustive catch clauses. + Context withHandlesErrors() const { + Context copy = *this; + copy.HandlesErrors = true; + copy.ErrorHandlingIgnoresFunction = true; + return copy; + } + Kind getKind() const { return TheKind; } bool handlesNothing() const { - return getKind() != Kind::Handled && - getKind() != Kind::RethrowingFunction; + return !HandlesErrors; } bool handles(ThrowingKind errorKind) const { switch (errorKind) { @@ -991,49 +1007,63 @@ class Context { // A call that's rethrowing-only can be handled by 'rethrows'. case ThrowingKind::RethrowingOnly: - return !handlesNothing(); + return HandlesErrors; // An operation that always throws can only be handled by an // all-handling context. case ThrowingKind::Throws: - return getKind() == Kind::Handled; + return HandlesErrors && !isRethrows(); } llvm_unreachable("bad error kind"); } - DeclContext *getRethrowsDC() const { return RethrowsDC; } + bool handlesAsync() const { + return HandlesAsync; + } + + DeclContext *getRethrowsDC() const { + if (!isRethrows()) + return nullptr; + + return Function->getAbstractFunctionDecl(); + } + InterpolatedStringLiteralExpr * getInterpolatedString() const { return InterpolatedString; } + void setNonExhaustiveCatch(bool value) { + IsNonExhaustiveCatch = value; + } + static void diagnoseThrowInIllegalContext(DiagnosticEngine &Diags, ASTNode node, - StringRef description) { + Kind kind) { if (auto *e = node.dyn_cast()) { if (isa(e)) { Diags.diagnose(e->getLoc(), diag::throwing_call_in_illegal_context, - description); + static_cast(kind)); return; } } Diags.diagnose(node.getStartLoc(), diag::throw_in_illegal_context, - description); + static_cast(kind)); } static void maybeAddRethrowsNote(DiagnosticEngine &Diags, SourceLoc loc, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { switch (reason.getKind()) { - case PotentialReason::Kind::Throw: + case PotentialThrowReason::Kind::Throw: llvm_unreachable("should already have been covered"); - case PotentialReason::Kind::CallThrows: + case PotentialThrowReason::Kind::CallThrows: // Already fully diagnosed. return; - case PotentialReason::Kind::CallRethrowsWithExplicitThrowingArgument: + case PotentialThrowReason::Kind::CallRethrowsWithExplicitThrowingArgument: Diags.diagnose(reason.getThrowingArgument()->getLoc(), diag::because_rethrows_argument_throws); return; - case PotentialReason::Kind::CallRethrowsWithDefaultThrowingArgument: + case PotentialThrowReason::Kind::CallRethrowsWithDefaultThrowingArgument: Diags.diagnose(loc, diag::because_rethrows_default_argument_throws); return; } @@ -1041,7 +1071,7 @@ class Context { } void diagnoseUncoveredThrowSite(ASTContext &ctx, ASTNode E, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { auto &Diags = ctx.Diags; auto message = diag::throwing_call_without_try; auto loc = E.getStartLoc(); @@ -1077,7 +1107,7 @@ class Context { // // Let's suggest couple of alternative fix-its // because complete context is unavailable. - if (reason.getKind() != PotentialReason::Kind::CallThrows) + if (reason.getKind() != PotentialThrowReason::Kind::CallThrows) return; Diags.diagnose(loc, diag::note_forgot_try) @@ -1090,7 +1120,7 @@ class Context { void diagnoseThrowInLegalContext(DiagnosticEngine &Diags, ASTNode node, bool isTryCovered, - const PotentialReason &reason, + const PotentialThrowReason &reason, Diag<> diagForThrow, Diag<> diagForThrowingCall, Diag<> diagForTrylessThrowingCall) { @@ -1103,8 +1133,7 @@ class Context { // Allow the diagnostic to fire on the 'try' if we don't have // anything else to say. if (isTryCovered && !reason.isRethrowsCall() && - (getKind() == Kind::NonThrowingFunction || - getKind() == Kind::NonExhaustiveCatch)) { + !isRethrows() && !isAutoClosure()) { DiagnoseErrorOnTry = true; return; } @@ -1119,91 +1148,123 @@ class Context { void diagnoseUnhandledThrowSite(DiagnosticEngine &Diags, ASTNode E, bool isTryCovered, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { switch (getKind()) { - case Kind::Handled: - llvm_unreachable("throw site is handled!"); + case Kind::PotentiallyHandled: + if (IsNonExhaustiveCatch) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_nonexhaustive_catch, + diag::throwing_call_in_nonexhaustive_catch, + diag::tryless_throwing_call_in_nonexhaustive_catch); + return; + } - // TODO: Doug suggested that we could generate one error per - // non-throwing function with throw sites within it, possibly with - // notes for the throw sites. + if (isAutoClosure()) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_nonthrowing_autoclosure, + diag::throwing_call_in_nonthrowing_autoclosure, + diag::tryless_throwing_call_in_nonthrowing_autoclosure); + return; + } - case Kind::RethrowingFunction: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_rethrows_function, - diag::throwing_call_in_rethrows_function, - diag::tryless_throwing_call_in_rethrows_function); - return; + if (isRethrows()) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_rethrows_function, + diag::throwing_call_in_rethrows_function, + diag::tryless_throwing_call_in_rethrows_function); + return; + } - case Kind::NonThrowingFunction: diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, diag::throw_in_nonthrowing_function, diag::throwing_call_unhandled, diag::tryless_throwing_call_unhandled); return; - case Kind::NonThrowingAutoClosure: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_nonthrowing_autoclosure, - diag::throwing_call_in_nonthrowing_autoclosure, - diag::tryless_throwing_call_in_nonthrowing_autoclosure); + case Kind::EnumElementInitializer: + case Kind::GlobalVarInitializer: + case Kind::IVarInitializer: + case Kind::DefaultArgument: + case Kind::CatchPattern: + case Kind::CatchGuard: + case Kind::DeferBody: + diagnoseThrowInIllegalContext(Diags, E, getKind()); return; + } + llvm_unreachable("bad context kind"); + } - case Kind::NonExhaustiveCatch: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_nonexhaustive_catch, - diag::throwing_call_in_nonexhaustive_catch, - diag::tryless_throwing_call_in_nonexhaustive_catch); + void diagnoseUnhandledTry(DiagnosticEngine &Diags, TryExpr *E) { + switch (getKind()) { + case Kind::PotentiallyHandled: + if (DiagnoseErrorOnTry) { + Diags.diagnose( + E->getTryLoc(), + IsNonExhaustiveCatch ? diag::try_unhandled_in_nonexhaustive_catch + : diag::try_unhandled); + } return; case Kind::EnumElementInitializer: - diagnoseThrowInIllegalContext(Diags, E, "an enum case raw value"); - return; - case Kind::GlobalVarInitializer: - diagnoseThrowInIllegalContext(Diags, E, "a global variable initializer"); - return; - case Kind::IVarInitializer: - diagnoseThrowInIllegalContext(Diags, E, "a property initializer"); - return; - case Kind::DefaultArgument: - diagnoseThrowInIllegalContext(Diags, E, "a default argument"); - return; - case Kind::CatchPattern: - diagnoseThrowInIllegalContext(Diags, E, "a catch pattern"); - return; - case Kind::CatchGuard: - diagnoseThrowInIllegalContext(Diags, E, "a catch guard expression"); - return; case Kind::DeferBody: - diagnoseThrowInIllegalContext(Diags, E, "a defer body"); + assert(!DiagnoseErrorOnTry); + // Diagnosed at the call sites. return; } llvm_unreachable("bad context kind"); } - void diagnoseUnhandledTry(DiagnosticEngine &Diags, TryExpr *E) { - switch (getKind()) { - case Kind::Handled: - case Kind::RethrowingFunction: - llvm_unreachable("try is handled!"); + void diagnoseUncoveredAsyncSite(ASTContext &ctx, ASTNode node) { + SourceRange highlight; + + // Generate more specific messages in some cases. + if (auto apply = dyn_cast_or_null(node.dyn_cast())) + highlight = apply->getSourceRange(); + + auto diag = diag::async_call_without_await; + if (isAutoClosure()) + diag = diag::async_call_without_await_in_autoclosure; + ctx.Diags.diagnose(node.getStartLoc(), diag) + .highlight(highlight); + } + + void diagnoseAsyncInIllegalContext(DiagnosticEngine &Diags, ASTNode node) { + if (auto *e = node.dyn_cast()) { + if (isa(e)) { + Diags.diagnose(e->getLoc(), diag::async_call_in_illegal_context, + static_cast(getKind())); + return; + } + } + + Diags.diagnose(node.getStartLoc(), diag::await_in_illegal_context, + static_cast(getKind())); + } - case Kind::NonThrowingFunction: - if (DiagnoseErrorOnTry) - Diags.diagnose(E->getTryLoc(), diag::try_unhandled); + void maybeAddAsyncNote(DiagnosticEngine &Diags) { + if (!Function) return; - case Kind::NonExhaustiveCatch: - if (DiagnoseErrorOnTry) - Diags.diagnose(E->getTryLoc(), - diag::try_unhandled_in_nonexhaustive_catch); + auto func = dyn_cast_or_null(Function->getAbstractFunctionDecl()); + if (!func) + return; + + addAsyncNotes(func); + } + + void diagnoseUnhandledAsyncSite(DiagnosticEngine &Diags, ASTNode node) { + switch (getKind()) { + case Kind::PotentiallyHandled: + Diags.diagnose(node.getStartLoc(), diag::async_in_nonasync_function, + node.isExpr(ExprKind::Await), isAutoClosure()); + maybeAddAsyncNote(Diags); return; - case Kind::NonThrowingAutoClosure: case Kind::EnumElementInitializer: case Kind::GlobalVarInitializer: case Kind::IVarInitializer: @@ -1211,23 +1272,20 @@ class Context { case Kind::CatchPattern: case Kind::CatchGuard: case Kind::DeferBody: - assert(!DiagnoseErrorOnTry); - // Diagnosed at the call sites. + diagnoseAsyncInIllegalContext(Diags, node); return; } - llvm_unreachable("bad context kind"); } }; /// A class to walk over a local context and validate the correctness /// of its error coverage. -class CheckErrorCoverage : public ErrorHandlingWalker { - friend class ErrorHandlingWalker; +class CheckEffectsCoverage : public EffectsHandlingWalker { + friend class EffectsHandlingWalker; ASTContext &Ctx; - ApplyClassifier Classifier; - + DeclContext *RethrowsDC = nullptr; Context CurContext; class ContextFlags { @@ -1271,6 +1329,29 @@ class CheckErrorCoverage : public ErrorHandlingWalker { void mergeFrom(ContextFlag flag, ContextFlags other) { Bits |= (other.Bits & flag); } + + void mergeFrom(ContextFlags flags, ContextFlags other) { + Bits |= (other.Bits & flags.Bits); + } + + // All of the flags that can be set by throw checking. + static ContextFlags throwFlags() { + ContextFlags result; + result.set(IsTryCovered); + result.set(IsInTry); + result.set(HasAnyThrowSite); + result.set(HasTryThrowSite); + return result; + } + + // All of the flags that can be set by async/await checking. + static ContextFlags asyncAwaitFlags() { + ContextFlags result; + result.set(IsAsyncCovered); + result.set(HasAnyAsyncSite); + result.set(HasAnyAwait); + return result; + } }; ContextFlags Flags; @@ -1288,15 +1369,15 @@ class CheckErrorCoverage : public ErrorHandlingWalker { /// An RAII object for restoring all the interesting state in an /// error-coverage. class ContextScope { - CheckErrorCoverage &Self; + CheckEffectsCoverage &Self; Context OldContext; DeclContext *OldRethrowsDC; ContextFlags OldFlags; ThrowingKind OldMaxThrowingKind; public: - ContextScope(CheckErrorCoverage &self, Optional newContext) + ContextScope(CheckEffectsCoverage &self, Optional newContext) : Self(self), OldContext(self.CurContext), - OldRethrowsDC(self.Classifier.RethrowsDC), + OldRethrowsDC(self.RethrowsDC), OldFlags(self.Flags), OldMaxThrowingKind(self.MaxThrowingKind) { if (newContext) self.CurContext = *newContext; @@ -1306,7 +1387,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ContextScope &operator=(const ContextScope &) = delete; void enterSubFunction() { - Self.Classifier.RethrowsDC = nullptr; + Self.RethrowsDC = nullptr; } void enterTry() { @@ -1329,6 +1410,12 @@ class CheckErrorCoverage : public ErrorHandlingWalker { Self.MaxThrowingKind = ThrowingKind::None; } + void resetCoverageForAutoclosureBody() { + Self.Flags.clear(ContextFlags::IsAsyncCovered); + Self.Flags.clear(ContextFlags::HasAnyAsyncSite); + Self.Flags.clear(ContextFlags::HasAnyAwait); + } + void resetCoverageForDoCatch() { Self.Flags.reset(); Self.MaxThrowingKind = ThrowingKind::None; @@ -1344,6 +1431,10 @@ class CheckErrorCoverage : public ErrorHandlingWalker { // body for the purposes of deciding whether a try contained // a throwing call. OldFlags.mergeFrom(ContextFlags::HasTryThrowSite, Self.Flags); + + // "await" doesn't work this way; the "await" needs to be part of + // the autoclosure expression itself, and the autoclosure must be + // 'async'. } void preserveCoverageFromNonExhaustiveCatch() { @@ -1353,16 +1444,21 @@ class CheckErrorCoverage : public ErrorHandlingWalker { void preserveCoverageFromAwaitOperand() { OldFlags.mergeFrom(ContextFlags::HasAnyAwait, Self.Flags); + OldFlags.mergeFrom(ContextFlags::throwFlags(), Self.Flags); + OldMaxThrowingKind = std::max(OldMaxThrowingKind, Self.MaxThrowingKind); } void preserveCoverageFromTryOperand() { OldFlags.mergeFrom(ContextFlags::HasAnyThrowSite, Self.Flags); + OldFlags.mergeFrom(ContextFlags::asyncAwaitFlags(), Self.Flags); OldMaxThrowingKind = std::max(OldMaxThrowingKind, Self.MaxThrowingKind); } void preserveCoverageFromInterpolatedString() { OldFlags.mergeFrom(ContextFlags::HasAnyThrowSite, Self.Flags); OldFlags.mergeFrom(ContextFlags::HasTryThrowSite, Self.Flags); + OldFlags.mergeFrom(ContextFlags::HasAnyAsyncSite, Self.Flags); + OldFlags.mergeFrom(ContextFlags::HasAnyAwait, Self.Flags); OldMaxThrowingKind = std::max(OldMaxThrowingKind, Self.MaxThrowingKind); } @@ -1372,19 +1468,19 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ~ContextScope() { Self.CurContext = OldContext; - Self.Classifier.RethrowsDC = OldRethrowsDC; + Self.RethrowsDC = OldRethrowsDC; Self.Flags = OldFlags; Self.MaxThrowingKind = OldMaxThrowingKind; } }; public: - CheckErrorCoverage(ASTContext &ctx, Context initialContext) + CheckEffectsCoverage(ASTContext &ctx, Context initialContext) : Ctx(ctx), CurContext(initialContext), MaxThrowingKind(ThrowingKind::None) { if (auto rethrowsDC = initialContext.getRethrowsDC()) { - Classifier.RethrowsDC = rethrowsDC; + RethrowsDC = rethrowsDC; } } @@ -1416,14 +1512,15 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ShouldRecurse_t checkAutoClosure(AutoClosureExpr *E) { ContextScope scope(*this, Context::forClosure(E)); scope.enterSubFunction(); + scope.resetCoverageForAutoclosureBody(); E->getBody()->walk(*this); scope.preserveCoverageFromAutoclosureBody(); return ShouldNotRecurse; } ThrowingKind checkExhaustiveDoBody(DoCatchStmt *S) { - // This is a handled context. - ContextScope scope(*this, Context::getHandled()); + // This is a context where errors are handled. + ContextScope scope(*this, CurContext.withHandlesErrors()); assert(!Flags.has(ContextFlags::IsInTry) && "do/catch within try?"); scope.resetCoverageForDoCatch(); @@ -1442,7 +1539,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { // If the enclosing context doesn't handle anything, use a // specialized diagnostic about non-exhaustive catches. if (CurContext.handlesNothing()) { - scope.refineLocalContext(Context::forNonExhaustiveCatch(S)); + CurContext.setNonExhaustiveCatch(true); } S->getBody()->walk(*this); @@ -1478,11 +1575,11 @@ class CheckErrorCoverage : public ErrorHandlingWalker { auto savedContext = CurContext; if (doThrowingKind != ThrowingKind::Throws && - CurContext.getKind() == Context::Kind::RethrowingFunction) { + CurContext.isRethrows()) { // If this catch clause is reachable at all, it's because a function - // parameter throws. So let's temporarily set our context to Handled so - // the catch body is allowed to throw. - CurContext = Context::getHandled(); + // parameter throws. So let's temporarily state that the body is allowed + // to throw. + CurContext = CurContext.withHandlesErrors(); } // The catch body just happens in the enclosing context. @@ -1494,7 +1591,9 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ShouldRecurse_t checkApply(ApplyExpr *E) { // An apply expression is a potential throw site if the function throws. // But if the expression didn't type-check, suppress diagnostics. - auto classification = Classifier.classifyApply(E); + ApplyClassifier classifier; + classifier.RethrowsDC = RethrowsDC; + auto classification = classifier.classifyApply(E); checkThrowAsyncSite(E, /*requiresTry*/ true, classification); @@ -1528,8 +1627,8 @@ class CheckErrorCoverage : public ErrorHandlingWalker { // 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) {} + CheckEffectsCoverage &CEC; + ConservativeThrowChecker(CheckEffectsCoverage &CEC) : CEC(CEC) {} Expr *walkToExprPost(Expr *E) override { if (isa(E)) @@ -1557,7 +1656,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ShouldRecurse_t checkThrow(ThrowStmt *S) { checkThrowAsyncSite(S, /*requiresTry*/ false, - Classification::forThrow(PotentialReason::forThrow(), + Classification::forThrow(PotentialThrowReason::forThrow(), /*async*/false)); return ShouldRecurse; } @@ -1577,17 +1676,14 @@ class CheckErrorCoverage : public ErrorHandlingWalker { if (classification.isAsync()) { // Remember that we've seen an async call. Flags.set(ContextFlags::HasAnyAsyncSite); - + + // Diagnose async calls in a context that doesn't handle async. + if (!CurContext.handlesAsync()) { + CurContext.diagnoseUnhandledAsyncSite(Ctx.Diags, E); + } // Diagnose async calls that are outside of an await context. - if (!Flags.has(ContextFlags::IsAsyncCovered)) { - SourceRange highlight; - - // Generate more specific messages in some cases. - if (auto e = dyn_cast_or_null(E.dyn_cast())) - highlight = e->getSourceRange(); - - Ctx.Diags.diagnose(E.getStartLoc(), diag::async_call_without_await) - .highlight(highlight); + else if (!Flags.has(ContextFlags::IsAsyncCovered)) { + CurContext.diagnoseUncoveredAsyncSite(Ctx, E); } } @@ -1631,10 +1727,16 @@ class CheckErrorCoverage : public ErrorHandlingWalker { scope.enterAwait(); E->getSubExpr()->walk(*this); - - // Warn about 'await' expressions that weren't actually needed. - if (!Flags.has(ContextFlags::HasAnyAsyncSite)) - Ctx.Diags.diagnose(E->getAwaitLoc(), diag::no_async_in_await); + + // Warn about 'await' expressions that weren't actually needed, unless of + // course we're in a context that could never handle an 'async'. Then, we + // produce an error. + if (!Flags.has(ContextFlags::HasAnyAsyncSite)) { + if (CurContext.handlesAsync()) + Ctx.Diags.diagnose(E->getAwaitLoc(), diag::no_async_in_await); + else + CurContext.diagnoseUnhandledAsyncSite(Ctx.Diags, E); + } // Inform the parent of the walk that an 'await' exists here. scope.preserveCoverageFromAwaitOperand(); @@ -1665,7 +1767,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ShouldRecurse_t checkForceTry(ForceTryExpr *E) { // Walk the operand. 'try!' handles errors. - ContextScope scope(*this, Context::getHandled()); + ContextScope scope(*this, CurContext.withHandlesErrors()); scope.enterTry(); E->getSubExpr()->walk(*this); @@ -1679,7 +1781,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ShouldRecurse_t checkOptionalTry(OptionalTryExpr *E) { // Walk the operand. 'try?' handles errors. - ContextScope scope(*this, Context::getHandled()); + ContextScope scope(*this, CurContext.withHandlesErrors()); scope.enterTry(); E->getSubExpr()->walk(*this); @@ -1694,9 +1796,9 @@ class CheckErrorCoverage : public ErrorHandlingWalker { } // end anonymous namespace -void TypeChecker::checkTopLevelErrorHandling(TopLevelCodeDecl *code) { +void TypeChecker::checkTopLevelEffects(TopLevelCodeDecl *code) { auto &ctx = code->getDeclContext()->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forTopLevelCode(code)); + CheckEffectsCoverage checker(ctx, Context::forTopLevelCode(code)); // In some language modes, we allow top-level code to omit 'try' marking. if (ctx.LangOpts.EnableThrowWithoutTry) @@ -1705,16 +1807,16 @@ void TypeChecker::checkTopLevelErrorHandling(TopLevelCodeDecl *code) { code->getBody()->walk(checker); } -void TypeChecker::checkFunctionErrorHandling(AbstractFunctionDecl *fn) { +void TypeChecker::checkFunctionEffects(AbstractFunctionDecl *fn) { #ifndef NDEBUG - PrettyStackTraceDecl debugStack("checking error handling for", fn); + PrettyStackTraceDecl debugStack("checking effects handling for", fn); #endif auto isDeferBody = isa(fn) && cast(fn)->isDeferBody(); auto context = isDeferBody ? Context::forDeferBody() : Context::forFunction(fn); auto &ctx = fn->getASTContext(); - CheckErrorCoverage checker(ctx, context); + CheckEffectsCoverage checker(ctx, context); // If this is a debugger function, suppress 'try' marking at the top level. if (fn->getAttrs().hasAttribute()) @@ -1728,14 +1830,14 @@ void TypeChecker::checkFunctionErrorHandling(AbstractFunctionDecl *fn) { superInit->walk(checker); } -void TypeChecker::checkInitializerErrorHandling(Initializer *initCtx, +void TypeChecker::checkInitializerEffects(Initializer *initCtx, Expr *init) { auto &ctx = initCtx->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forInitializer(initCtx)); + CheckEffectsCoverage checker(ctx, Context::forInitializer(initCtx)); init->walk(checker); } -/// Check the correctness of error handling within the given enum +/// Check the correctness of effects within the given enum /// element's raw value expression. /// /// The syntactic restrictions on such expressions should make it @@ -1743,15 +1845,15 @@ void TypeChecker::checkInitializerErrorHandling(Initializer *initCtx, /// ensures correctness if those restrictions are ever loosened, /// perhaps accidentally, and (2) allows the verifier to assert that /// all calls have been checked. -void TypeChecker::checkEnumElementErrorHandling(EnumElementDecl *elt, Expr *E) { +void TypeChecker::checkEnumElementEffects(EnumElementDecl *elt, Expr *E) { auto &ctx = elt->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forEnumElementInitializer(elt)); + CheckEffectsCoverage checker(ctx, Context::forEnumElementInitializer(elt)); E->walk(checker); } -void TypeChecker::checkPropertyWrapperErrorHandling( +void TypeChecker::checkPropertyWrapperEffects( PatternBindingDecl *binding, Expr *expr) { auto &ctx = binding->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forPatternBinding(binding)); + CheckEffectsCoverage checker(ctx, Context::forPatternBinding(binding)); expr->walk(checker); } diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 861ee21d75350..016345c4620bc 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -691,9 +691,9 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, // Gather requirements from the result type. auto *resultTypeRepr = [&subscr, &func]() -> TypeRepr * { if (subscr) { - return subscr->getElementTypeLoc().getTypeRepr(); + return subscr->getElementTypeRepr(); } else if (auto *FD = dyn_cast(func)) { - return FD->getBodyResultTypeLoc().getTypeRepr(); + return FD->getResultTypeRepr(); } else { return nullptr; } diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 6068b1a2c527f..6305169b4156d 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -113,8 +113,7 @@ namespace { // If this isn't a protocol member to be given special // treatment, just add the result. - if (!Options.contains(NameLookupFlags::ProtocolMembers) || - !isa(foundDC) || + if (!isa(foundDC) || isa(found) || isa(found) || (isa(found) && cast(found)->isOperator())) { @@ -124,9 +123,6 @@ namespace { assert(isa(foundDC)); - if (!Options.contains(NameLookupFlags::PerformConformanceCheck)) - return; - // If we found something within the protocol itself, and our // search began somewhere that is not in a protocol or extension // thereof, remap this declaration to the witness. @@ -210,11 +206,9 @@ namespace { static UnqualifiedLookupOptions convertToUnqualifiedLookupOptions(NameLookupOptions options) { - UnqualifiedLookupOptions newOptions; + UnqualifiedLookupOptions newOptions = UnqualifiedLookupFlags::AllowProtocolMembers; if (options.contains(NameLookupFlags::KnownPrivate)) newOptions |= UnqualifiedLookupFlags::KnownPrivate; - if (options.contains(NameLookupFlags::ProtocolMembers)) - newOptions |= UnqualifiedLookupFlags::AllowProtocolMembers; if (options.contains(NameLookupFlags::IgnoreAccessControl)) newOptions |= UnqualifiedLookupFlags::IgnoreAccessControl; if (options.contains(NameLookupFlags::IncludeOuterResults)) @@ -226,8 +220,26 @@ convertToUnqualifiedLookupOptions(NameLookupOptions options) { LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclNameRef name, SourceLoc loc, NameLookupOptions options) { - auto ulOptions = convertToUnqualifiedLookupOptions(options); auto &ctx = dc->getASTContext(); + // HACK: Qualified lookup cannot be allowed to synthesize CodingKeys because + // it would lead to a number of egregious cycles through + // QualifiedLookupRequest when we resolve the protocol conformance. Codable's + // magic has pushed its way so deeply into the compiler, we have to + // pessimistically force every nominal context above this one to synthesize + // it in the event the user needs it from e.g. a non-primary input. + // We can undo this if Codable's semantic content is divorced from its + // syntactic content - so we synthesize just enough to allow lookups to + // succeed, but don't force protocol conformances while we're doing it. + if (name.getBaseIdentifier() == ctx.Id_CodingKeys) { + for (auto typeCtx = dc->getInnermostTypeContext(); typeCtx != nullptr; + typeCtx = typeCtx->getParent()->getInnermostTypeContext()) { + if (auto *nominal = typeCtx->getSelfNominalTypeDecl()) { + nominal->synthesizeSemanticMembersIfNeeded(name.getFullName()); + } + } + } + + auto ulOptions = convertToUnqualifiedLookupOptions(options); auto descriptor = UnqualifiedLookupDescriptor(name, dc, loc, ulOptions); auto lookup = evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{descriptor}, {}); @@ -278,8 +290,7 @@ TypeChecker::lookupUnqualifiedType(DeclContext *dc, DeclNameRef name, auto lookup = evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{desc}, {}); - if (!lookup.allResults().empty() || - !options.contains(NameLookupFlags::ProtocolMembers)) + if (!lookup.allResults().empty()) return lookup; } @@ -302,18 +313,12 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, assert(type->mayHaveMembers()); LookupResult result; - NLOptions subOptions = NL_QualifiedDefault; + NLOptions subOptions = (NL_QualifiedDefault | NL_ProtocolMembers); if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::IgnoreAccessControl)) subOptions |= NL_IgnoreAccessControl; - if (options.contains(NameLookupFlags::ProtocolMembers)) - subOptions |= NL_ProtocolMembers; - - if (options.contains(NameLookupFlags::IncludeAttributeImplements)) - subOptions |= NL_IncludeAttributeImplements; - // We handle our own overriding/shadowing filtering. subOptions &= ~NL_RemoveOverridden; subOptions &= ~NL_RemoveNonVisible; @@ -333,7 +338,8 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, return result; } -bool TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) { +TypeChecker::UnsupportedMemberTypeAccessKind +TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) { // We don't allow lookups of a non-generic typealias of an unbound // generic type, because we have no way to model such a type in the // AST. @@ -341,10 +347,7 @@ bool TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) { // For generic typealiases, the typealias itself has an unbound // generic form whose parent type can be another unbound generic // type. - // - // FIXME: Could lift this restriction once we have sugared - // "member types". - if (type->is()) { + if (type->hasUnboundGenericType()) { // Generic typealiases can be accessed with an unbound generic // base, since we represent the member type as an unbound generic // type. @@ -354,12 +357,12 @@ bool TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) { if (auto *aliasDecl = dyn_cast(typeDecl)) { if (!aliasDecl->isGeneric() && aliasDecl->getUnderlyingType()->hasTypeParameter()) { - return true; + return UnsupportedMemberTypeAccessKind::TypeAliasOfUnboundGeneric; } } if (isa(typeDecl)) - return true; + return UnsupportedMemberTypeAccessKind::AssociatedTypeOfUnboundGeneric; } if (type->isExistentialType() && @@ -369,15 +372,13 @@ bool TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) { if (auto *aliasDecl = dyn_cast(typeDecl)) { if (aliasDecl->getUnderlyingType()->getCanonicalType() ->hasTypeParameter()) - return true; - } else { - // Don't allow lookups of other nested types of an existential type, - // because there is no way to represent such types. - return true; + return UnsupportedMemberTypeAccessKind::TypeAliasOfExistential; + } else if (isa(typeDecl)) { + return UnsupportedMemberTypeAccessKind::AssociatedTypeOfExistential; } } - return false; + return UnsupportedMemberTypeAccessKind::None; } LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, @@ -387,12 +388,10 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, // Look for members with the given name. SmallVector decls; - NLOptions subOptions = NL_QualifiedDefault | NL_OnlyTypes; + NLOptions subOptions = (NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers); if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; - if (options.contains(NameLookupFlags::ProtocolMembers)) - subOptions |= NL_ProtocolMembers; if (options.contains(NameLookupFlags::IgnoreAccessControl)) subOptions |= NL_IgnoreAccessControl; @@ -416,7 +415,8 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, continue; } - if (isUnsupportedMemberTypeAccess(type, typeDecl)) { + if (isUnsupportedMemberTypeAccess(type, typeDecl) + != TypeChecker::UnsupportedMemberTypeAccessKind::None) { auto memberType = typeDecl->getDeclaredInterfaceType(); // Add the type to the result set, so that we can diagnose the @@ -434,21 +434,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, if (auto assocType = dyn_cast(typeDecl)) { if (!type->is() && !type->isTypeParameter()) { - if (options.contains(NameLookupFlags::PerformConformanceCheck)) - inferredAssociatedTypes.push_back(assocType); - continue; - } - } - - // FIXME: This is a hack, we should be able to remove this entire 'if' - // statement once we learn how to deal with the circularity here. - if (auto *aliasDecl = dyn_cast(typeDecl)) { - if (isa(aliasDecl->getDeclContext()) && - !type->is() && - !type->isTypeParameter() && - aliasDecl->getUnderlyingType()->getCanonicalType() - ->hasTypeParameter() && - !options.contains(NameLookupFlags::PerformConformanceCheck)) { + inferredAssociatedTypes.push_back(assocType); continue; } } @@ -511,11 +497,6 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, return result; } -LookupResult TypeChecker::lookupConstructors(DeclContext *dc, Type type, - NameLookupOptions options) { - return lookupMember(dc, type, DeclNameRef::createConstructor(), options); -} - unsigned TypeChecker::getCallEditDistance(DeclNameRef writtenName, DeclName correctedName, unsigned maxEditDistance) { diff --git a/lib/Sema/TypeCheckObjC.h b/lib/Sema/TypeCheckObjC.h index 808bb9118c467..41a08f1fafd70 100644 --- a/lib/Sema/TypeCheckObjC.h +++ b/lib/Sema/TypeCheckObjC.h @@ -17,6 +17,7 @@ #ifndef SWIFT_SEMA_TYPE_CHECK_OBJC_H #define SWIFT_SEMA_TYPE_CHECK_OBJC_H +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "llvm/ADT/Optional.h" @@ -123,6 +124,7 @@ unsigned getObjCDiagnosticAttrKind(ObjCReason reason); /// and figure out its foreign error convention (if any). bool isRepresentableInObjC(const AbstractFunctionDecl *AFD, ObjCReason Reason, + Optional &asyncConvention, Optional &errorConvention); /// Determine whether the given variable can be represented in Objective-C. diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 6a5ec66b76cb1..72d5446207b30 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -122,7 +122,7 @@ lookupUnqualifiedEnumMemberElement(DeclContext *DC, DeclNameRef name, auto lookupOptions = defaultUnqualifiedLookupOptions; lookupOptions |= NameLookupFlags::KnownPrivate; auto lookup = - TypeChecker::lookupUnqualified(DC, name, SourceLoc(), lookupOptions); + TypeChecker::lookupUnqualified(DC, name, UseLoc, lookupOptions); return filterForEnumElement(DC, UseLoc, /*unqualifiedLookup=*/true, lookup); } @@ -446,18 +446,12 @@ class ResolvePattern : public ASTVisitorgetArgument()) { - subPattern = getSubExprPattern(arg); - } - if (ume->getName().getBaseName().isSpecial()) return nullptr; return new (Context) EnumElementPattern(ume->getDotLoc(), ume->getNameLoc(), ume->getName(), - subPattern, ume); + nullptr, ume); } // Member syntax 'T.Element' forms a pattern if 'T' is an enum and the @@ -530,9 +524,10 @@ class ResolvePattern : public ASTVisitor(ce->getFn())) return nullptr; + if (isa(ce->getFn())) { + auto *P = visit(ce->getFn()); + if (!P) + return nullptr; + + auto *EEP = cast(P); + EEP->setSubPattern(getSubExprPattern(ce->getArg())); + EEP->setUnresolvedOriginalExpr(ce); + + return P; + } + SmallVector components; if (!ExprToIdentTypeRepr(components, Context).visit(ce->getFn())) return nullptr; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index e68a7b2d095fa..60b25436f0c3a 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -19,6 +19,7 @@ #include "DerivedConformances.h" #include "MiscDiagnostics.h" #include "TypeAccessScopeChecker.h" +#include "TypeCheckAccess.h" #include "TypeCheckAvailability.h" #include "TypeCheckObjC.h" #include "swift/AST/ASTContext.h" @@ -850,7 +851,14 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache, Type openedFullWitnessType; Type reqType, openedFullReqType; - auto reqSig = req->getInnermostDeclContext()->getGenericSignatureOfContext(); + GenericSignature reqSig = proto->getGenericSignature(); + if (auto *funcDecl = dyn_cast(req)) { + if (funcDecl->isGeneric()) + reqSig = funcDecl->getGenericSignature(); + } else if (auto *subscriptDecl = dyn_cast(req)) { + if (subscriptDecl->isGeneric()) + reqSig = subscriptDecl->getGenericSignature(); + } ClassDecl *covariantSelf = nullptr; if (witness->getDeclContext()->getExtendedProtocolDecl()) { @@ -1105,16 +1113,25 @@ WitnessChecker::WitnessChecker(ASTContext &ctx, ProtocolDecl *proto, void WitnessChecker::lookupValueWitnessesViaImplementsAttr( ValueDecl *req, SmallVector &witnesses) { - auto lookupOptions = defaultMemberTypeLookupOptions; - lookupOptions -= NameLookupFlags::PerformConformanceCheck; - lookupOptions |= NameLookupFlags::IncludeAttributeImplements; - auto candidates = TypeChecker::lookupMember(DC, Adoptee, req->createNameRef(), - lookupOptions); - for (auto candidate : candidates) { - if (witnessHasImplementsAttrForExactRequirement(candidate.getValueDecl(), req)) { - witnesses.push_back(candidate.getValueDecl()); - } + + auto name = req->createNameRef(); + auto *nominal = Adoptee->getAnyNominal(); + + NLOptions subOptions = (NL_ProtocolMembers | NL_IncludeAttributeImplements); + + nominal->synthesizeSemanticMembersIfNeeded(name.getFullName()); + + SmallVector lookupResults; + DC->lookupQualified(nominal, name, subOptions, lookupResults); + + for (auto decl : lookupResults) { + if (!isa(decl->getDeclContext())) + if (witnessHasImplementsAttrForExactRequirement(decl, req)) + witnesses.push_back(decl); } + + removeOverriddenDecls(witnesses); + removeShadowedDecls(witnesses, DC); } SmallVector @@ -1147,23 +1164,34 @@ WitnessChecker::lookupValueWitnesses(ValueDecl *req, bool *ignoringNames) { } } else { // Variable/function/subscript requirements. - auto lookupOptions = defaultMemberTypeLookupOptions; - lookupOptions -= NameLookupFlags::PerformConformanceCheck; - - auto candidates = TypeChecker::lookupMember(DC, Adoptee, reqName, - lookupOptions); + auto *nominal = Adoptee->getAnyNominal(); + nominal->synthesizeSemanticMembersIfNeeded(reqName.getFullName()); + + SmallVector lookupResults; + bool addedAny = false; + DC->lookupQualified(nominal, reqName, NL_ProtocolMembers, lookupResults); + for (auto *decl : lookupResults) { + if (!isa(decl->getDeclContext())) { + witnesses.push_back(decl); + addedAny = true; + } + }; // If we didn't find anything with the appropriate name, look // again using only the base name. - if (candidates.empty() && ignoringNames) { - candidates = TypeChecker::lookupMember(DC, Adoptee, reqBaseName, - lookupOptions); + if (!addedAny && ignoringNames) { + lookupResults.clear(); + DC->lookupQualified(nominal, reqBaseName, NL_ProtocolMembers, lookupResults); + for (auto *decl : lookupResults) { + if (!isa(decl->getDeclContext())) + witnesses.push_back(decl); + } + *ignoringNames = true; } - for (auto candidate : candidates) { - witnesses.push_back(candidate.getValueDecl()); - } + removeOverriddenDecls(witnesses); + removeShadowedDecls(witnesses, DC); } return witnesses; @@ -2066,13 +2094,12 @@ SourceLoc OptionalAdjustment::getOptionalityLoc(ValueDecl *witness) const { // For a function, use the result type. if (auto func = dyn_cast(witness)) { return getOptionalityLoc( - func->getBodyResultTypeLoc().getTypeRepr()); + func->getResultTypeRepr()); } // For a subscript, use the element type. if (auto subscript = dyn_cast(witness)) { - return getOptionalityLoc( - subscript->getElementTypeLoc().getTypeRepr()); + return getOptionalityLoc(subscript->getElementTypeRepr()); } // Otherwise, we have a variable. @@ -3768,9 +3795,10 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDefault( # pragma mark Type witness resolution -CheckTypeWitnessResult swift::checkTypeWitness(Type type, - AssociatedTypeDecl *assocType, - NormalProtocolConformance *Conf) { +CheckTypeWitnessResult +swift::checkTypeWitness(Type type, AssociatedTypeDecl *assocType, + const NormalProtocolConformance *Conf, + SubstOptions options) { if (type->hasError()) return ErrorType::get(assocType->getASTContext()); @@ -3784,13 +3812,19 @@ CheckTypeWitnessResult swift::checkTypeWitness(Type type, : type; if (auto superclass = genericSig->getSuperclassBound(depTy)) { - // If the superclass has a type parameter, substitute in known type - // witnesses. if (superclass->hasTypeParameter()) { - const auto subMap = SubstitutionMap::getProtocolSubstitutions( - proto, Conf->getType(), ProtocolConformanceRef(Conf)); + // Replace type parameters with other known or tentative type witnesses. + superclass = superclass.subst( + [&](SubstitutableType *type) { + if (type->isEqual(proto->getSelfInterfaceType())) + return Conf->getType(); + + return Type(); + }, + LookUpConformanceInModule(dc->getParentModule()), options); - superclass = superclass.subst(subMap); + if (superclass->hasTypeParameter()) + superclass = dc->mapTypeIntoContext(superclass); } if (!superclass->isExactSuperclassOf(contextType)) return superclass; @@ -3862,36 +3896,86 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( abort(); } + NLOptions subOptions = (NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers); + // Look for a member type with the same name as the associated type. - auto candidates = TypeChecker::lookupMemberType( - DC, Adoptee, assocType->createNameRef(), - NameLookupFlags::ProtocolMembers); + SmallVector candidates; + + DC->lookupQualified(Adoptee->getAnyNominal(), + assocType->createNameRef(), + subOptions, candidates); // If there aren't any candidates, we're done. - if (!candidates) { + if (candidates.empty()) { return ResolveWitnessResult::Missing; } // Determine which of the candidates is viable. SmallVector viable; SmallVector, 2> nonViable; + SmallPtrSet viableTypes; + for (auto candidate : candidates) { - // Skip nested generic types. - if (auto *genericDecl = dyn_cast(candidate.Member)) - if (genericDecl->isGeneric()) - continue; + auto *typeDecl = cast(candidate); + + // Skip other associated types. + if (isa(typeDecl)) + continue; + + auto *genericDecl = cast(typeDecl); + + // If the declaration has generic parameters, it cannot witness an + // associated type. + if (genericDecl->isGeneric()) + continue; + + // As a narrow fix for a source compatibility issue with SwiftUI's + // swiftinterface, allow the conformance if the underlying type of + // the typealias is Never. + // + // FIXME: This should be conditionalized on a new language version. + bool skipRequirementCheck = false; + if (auto *typeAliasDecl = dyn_cast(typeDecl)) { + if (typeAliasDecl->getUnderlyingType()->isUninhabited()) + skipRequirementCheck = true; + } // Skip typealiases with an unbound generic type as their underlying type. - if (auto *typeAliasDecl = dyn_cast(candidate.Member)) + if (auto *typeAliasDecl = dyn_cast(typeDecl)) if (typeAliasDecl->getDeclaredInterfaceType()->is()) continue; + // Skip dependent protocol typealiases. + // + // FIXME: This should not be necessary. + if (auto *typeAliasDecl = dyn_cast(typeDecl)) { + if (isa(typeAliasDecl->getDeclContext()) && + typeAliasDecl->getUnderlyingType()->getCanonicalType() + ->hasTypeParameter()) { + continue; + } + } + + // If the type comes from a constrained extension or has a 'where' + // clause, check those requirements now. + if (!skipRequirementCheck && + !TypeChecker::checkContextualRequirements(genericDecl, Adoptee, + SourceLoc(), DC)) { + continue; + } + + auto memberType = TypeChecker::substMemberTypeWithBase(DC->getParentModule(), + typeDecl, Adoptee); + + if (!viableTypes.insert(memberType->getCanonicalType()).second) + continue; + // Check this type against the protocol requirements. if (auto checkResult = - checkTypeWitness(candidate.MemberType, assocType, Conformance)) { - nonViable.push_back({candidate.Member, checkResult}); + checkTypeWitness(memberType, assocType, Conformance)) { + nonViable.push_back({typeDecl, checkResult}); } else { - viable.push_back(candidate); + viable.push_back({typeDecl, memberType, nullptr}); } } @@ -3908,8 +3992,6 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( // If there is a single viable candidate, form a substitution for it. if (viable.size() == 1) { auto interfaceType = viable.front().MemberType; - if (interfaceType->hasArchetype()) - interfaceType = interfaceType->mapTypeOutOfContext(); recordTypeWitness(assocType, interfaceType, viable.front().Member); return ResolveWitnessResult::Success; } @@ -3958,7 +4040,8 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( static void checkExportability(Type depTy, Type replacementTy, const ProtocolConformance *conformance, NormalProtocolConformance *conformanceBeingChecked, - SourceFile *SF) { + DeclContext *DC) { + SourceFile *SF = DC->getParentSourceFile(); if (!SF) return; @@ -3968,13 +4051,17 @@ static void checkExportability(Type depTy, Type replacementTy, if (!subConformance.isConcrete()) continue; checkExportability(depTy, replacementTy, subConformance.getConcrete(), - conformanceBeingChecked, SF); + conformanceBeingChecked, DC); } const RootProtocolConformance *rootConformance = conformance->getRootConformance(); ModuleDecl *M = rootConformance->getDeclContext()->getParentModule(); - if (!SF->isImportedImplementationOnly(M)) + + auto originKind = getDisallowedOriginKind( + rootConformance->getDeclContext()->getAsDecl(), + *SF, DC->getAsDecl()); + if (originKind == DisallowedOriginKind::None) return; ASTContext &ctx = SF->getASTContext(); @@ -3985,14 +4072,16 @@ static void checkExportability(Type depTy, Type replacementTy, conformanceBeingChecked->getLoc(), diag::conformance_from_implementation_only_module, rootConformance->getType(), - rootConformance->getProtocol()->getName(), 0, M->getName()); + rootConformance->getProtocol()->getName(), 0, M->getName(), + static_cast(originKind)); } else { ctx.Diags.diagnose( conformanceBeingChecked->getLoc(), diag::assoc_conformance_from_implementation_only_module, rootConformance->getType(), rootConformance->getProtocol()->getName(), M->getName(), - depTy, replacementTy->getCanonicalType()); + depTy, replacementTy->getCanonicalType(), + static_cast(originKind)); } } @@ -4041,11 +4130,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() { // Now check that our associated conformances are at least as visible as // the conformance itself. - // - // FIXME: Do we need to check SPI here too? if (getRequiredAccessScope().isPublic() || isUsableFromInlineRequired()) { - auto *fileForCheckingExportability = DC->getParentSourceFile(); - for (auto req : proto->getRequirementSignature()) { if (req.getKind() == RequirementKind::Conformance) { auto depTy = req.getFirstType(); @@ -4055,7 +4140,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() { auto *concrete = conformance.getConcrete(); auto replacementTy = DC->mapTypeIntoContext(concrete->getType()); checkExportability(depTy, replacementTy, concrete, - Conformance, fileForCheckingExportability); + Conformance, DC); } } } @@ -5073,16 +5158,20 @@ diagnoseMissingAppendInterpolationMethod(NominalTypeDecl *typeDecl) { static bool hasValidMethod(NominalTypeDecl *typeDecl, SmallVectorImpl &invalid) { - auto type = typeDecl->getDeclaredType(); + NLOptions subOptions = NL_QualifiedDefault; + subOptions |= NL_ProtocolMembers; + DeclNameRef baseName(typeDecl->getASTContext().Id_appendInterpolation); - auto lookupOptions = defaultMemberTypeLookupOptions; - lookupOptions -= NameLookupFlags::PerformConformanceCheck; - for (auto resultEntry : - TypeChecker::lookupMember(typeDecl, type, baseName, lookupOptions)) { - auto method = dyn_cast(resultEntry.getValueDecl()); + SmallVector lookupResults; + typeDecl->lookupQualified(typeDecl, baseName, subOptions, lookupResults); + for (auto decl : lookupResults) { + auto method = dyn_cast(decl); if (!method) continue; - + + if (isa(method->getDeclContext())) + continue; + if (method->isStatic()) { invalid.emplace_back(method, Reason::Static); continue; @@ -5124,11 +5213,13 @@ diagnoseMissingAppendInterpolationMethod(NominalTypeDecl *typeDecl) { break; case InvalidMethod::Reason::ReturnType: - C.Diags - .diagnose(invalidMethod.method->getBodyResultTypeLoc().getLoc(), - diag::append_interpolation_void_or_discardable) - .fixItInsert(invalidMethod.method->getStartLoc(), - "@discardableResult "); + if (auto *const repr = invalidMethod.method->getResultTypeRepr()) { + C.Diags + .diagnose(repr->getLoc(), + diag::append_interpolation_void_or_discardable) + .fixItInsert(invalidMethod.method->getStartLoc(), + "@discardableResult "); + } break; case InvalidMethod::Reason::AccessControl: @@ -5691,6 +5782,8 @@ TypeChecker::deriveTypeWitness(DeclContext *DC, switch (*knownKind) { case KnownProtocolKind::RawRepresentable: return std::make_pair(derived.deriveRawRepresentable(AssocType), nullptr); + case KnownProtocolKind::CaseIterable: + return std::make_pair(derived.deriveCaseIterable(AssocType), nullptr); case KnownProtocolKind::Differentiable: return derived.deriveDifferentiable(AssocType); default: diff --git a/lib/Sema/TypeCheckProtocol.h b/lib/Sema/TypeCheckProtocol.h index badf16810d0b7..d51341300ac48 100644 --- a/lib/Sema/TypeCheckProtocol.h +++ b/lib/Sema/TypeCheckProtocol.h @@ -96,7 +96,8 @@ class CheckTypeWitnessResult { /// \returns an empty result on success, or a description of the error. CheckTypeWitnessResult checkTypeWitness(Type type, AssociatedTypeDecl *assocType, - NormalProtocolConformance *Conf); + const NormalProtocolConformance *Conf, + SubstOptions options = None); /// Describes the means of inferring an abstract type witness. enum class AbstractTypeWitnessKind : uint8_t { diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index 21fe9d350ff71..23a6957b930ef 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -595,15 +595,21 @@ AssociatedTypeInference::inferTypeWitnessesViaAssociatedType( defaultName = DeclNameRef(getASTContext().getIdentifier(defaultNameStr)); } + NLOptions subOptions = (NL_QualifiedDefault | + NL_OnlyTypes | + NL_ProtocolMembers); + // Look for types with the given default name that have appropriate // @_implements attributes. + SmallVector lookupResults; + dc->lookupQualified(adoptee->getAnyNominal(), defaultName, + subOptions, lookupResults); + InferredAssociatedTypesByWitnesses result; - auto lookupOptions = defaultMemberTypeLookupOptions; - lookupOptions -= NameLookupFlags::PerformConformanceCheck; - for (auto candidate : - TypeChecker::lookupMember(dc, adoptee, defaultName, lookupOptions)) { + + for (auto decl : lookupResults) { // We want type declarations. - auto typeDecl = dyn_cast(candidate.getValueDecl()); + auto typeDecl = dyn_cast(decl); if (!typeDecl || isa(typeDecl)) continue; @@ -1166,6 +1172,7 @@ AssociatedTypeDecl *AssociatedTypeInference::completeSolution( // Check each abstract type witness we computed against the generic // requirements on the corresponding associated type. + const auto substOptions = getSubstOptionsWithCurrentTypeWitnesses(); for (const auto &witness : abstractTypeWitnesses) { Type type = witness.getType(); if (type->hasTypeParameter()) { @@ -1178,8 +1185,7 @@ AssociatedTypeDecl *AssociatedTypeInference::completeSolution( return Type(); }, - LookUpConformanceInModule(dc->getParentModule()), - getSubstOptionsWithCurrentTypeWitnesses()); + LookUpConformanceInModule(dc->getParentModule()), substOptions); // If the substitution produced an error, we're done. if (type->hasError()) @@ -1188,8 +1194,8 @@ AssociatedTypeDecl *AssociatedTypeInference::completeSolution( type = dc->mapTypeIntoContext(type); } - if (const auto &failed = - checkTypeWitness(type, witness.getAssocType(), conformance)) { + if (const auto &failed = checkTypeWitness(type, witness.getAssocType(), + conformance, substOptions)) { // We failed to satisfy a requirement. If this is a default type // witness failure and we haven't seen one already, write it down. if (witness.getKind() == AbstractTypeWitnessKind::Default && diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 5de97e3012634..bf905c923c64c 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -303,11 +303,6 @@ static bool isDefer(DeclContext *dc) { /// same label. static void checkLabeledStmtShadowing( ASTContext &ctx, SourceFile *sourceFile, LabeledStmt *ls) { - // If ASTScope lookup is disabled, don't do this check at all. - // FIXME: Enable ASTScope lookup everywhere. - if (!ctx.LangOpts.EnableASTScopeLookup) - return; - auto name = ls->getLabelInfo().Name; if (name.empty() || !sourceFile || ls->getStartLoc().isInvalid()) return; @@ -404,20 +399,11 @@ static LabeledStmt *findUnlabeledBreakOrContinueStmtTarget( static LabeledStmt *findBreakOrContinueStmtTarget( ASTContext &ctx, SourceFile *sourceFile, SourceLoc loc, Identifier targetName, SourceLoc targetLoc, - bool isContinue, DeclContext *dc, - ArrayRef oldActiveLabeledStmts) { + bool isContinue, DeclContext *dc) { // Retrieve the active set of labeled statements. - // FIXME: Once everything uses ASTScope lookup, \c oldActiveLabeledStmts - // can go away. SmallVector activeLabeledStmts; - if (ctx.LangOpts.EnableASTScopeLookup) { - activeLabeledStmts = ASTScope::lookupLabeledStmts(sourceFile, loc); - } else { - activeLabeledStmts.insert( - activeLabeledStmts.end(), - oldActiveLabeledStmts.rbegin(), oldActiveLabeledStmts.rend()); - } + activeLabeledStmts = ASTScope::lookupLabeledStmts(sourceFile, loc); // Handle an unlabeled break separately; that's the easy case. if (targetName.empty()) { @@ -614,22 +600,13 @@ static void checkFallthroughPatternBindingsAndTypes( /// Check the correctness of a 'fallthrough' statement. /// /// \returns true if an error occurred. -static bool checkFallthroughStmt( - DeclContext *dc, FallthroughStmt *stmt, - CaseStmt *oldFallthroughSource, CaseStmt *oldFallthroughDest) { +static bool checkFallthroughStmt(DeclContext *dc, FallthroughStmt *stmt) { CaseStmt *fallthroughSource; CaseStmt *fallthroughDest; ASTContext &ctx = dc->getASTContext(); - if (ctx.LangOpts.EnableASTScopeLookup) { - auto sourceFile = dc->getParentSourceFile(); - std::tie(fallthroughSource, fallthroughDest) = - ASTScope::lookupFallthroughSourceAndDest(sourceFile, stmt->getLoc()); - assert(fallthroughSource == oldFallthroughSource); - assert(fallthroughDest == oldFallthroughDest); - } else { - fallthroughSource = oldFallthroughSource; - fallthroughDest = oldFallthroughDest; - } + auto sourceFile = dc->getParentSourceFile(); + std::tie(fallthroughSource, fallthroughDest) = + ASTScope::lookupFallthroughSourceAndDest(sourceFile, stmt->getLoc()); if (!fallthroughSource) { ctx.Diags.diagnose(stmt->getLoc(), diag::fallthrough_outside_switch); @@ -655,84 +632,11 @@ class StmtChecker : public StmtVisitor { /// DC - This is the current DeclContext. DeclContext *DC; - // Scope information for control flow statements - // (break, continue, fallthrough). - - /// The level of loop nesting. 'break' and 'continue' are valid only in scopes - /// where this is greater than one. - /// FIXME: Only required because EnableASTScopeLookup can be false - SmallVector ActiveLabeledStmts; - - /// The destination block for a 'fallthrough' statement. Null if the switch - /// scope depth is zero or if we are checking the final 'case' of the current - /// switch. - /// FIXME: Only required because EnableASTScopeLookup can be false - CaseStmt /*nullable*/ *FallthroughSource = nullptr; - CaseStmt /*nullable*/ *FallthroughDest = nullptr; - /// Skip type checking any elements inside 'BraceStmt', also this is /// propagated to ConstraintSystem. bool LeaveBraceStmtBodyUnchecked = false; ASTContext &getASTContext() const { return Ctx; }; - - struct AddLabeledStmt { - StmtChecker &SC; - AddLabeledStmt(StmtChecker &SC, LabeledStmt *LS) : SC(SC) { - // Verify that we don't have label shadowing. - auto sourceFile = SC.DC->getParentSourceFile(); - checkLabeledStmtShadowing(SC.getASTContext(), sourceFile, LS); - - // In any case, remember that we're in this labeled statement so that - // break and continue are aware of it. - SC.ActiveLabeledStmts.push_back(LS); - - // Verify that the ASTScope-based query for active labeled statements - // is equivalent to what we have here. - if (LS->getStartLoc().isValid() && sourceFile && - SC.getASTContext().LangOpts.EnableASTScopeLookup && - !SC.getASTContext().Diags.hadAnyError()) { - // The labeled statements from ASTScope lookup have the - // innermost labeled statement first, so reverse it to - // match the data structure maintained here. - auto activeFromASTScope = ASTScope::lookupLabeledStmts( - sourceFile, LS->getStartLoc()); - assert(activeFromASTScope.front() == LS); - std::reverse(activeFromASTScope.begin(), activeFromASTScope.end()); - if (activeFromASTScope != SC.ActiveLabeledStmts) { - llvm::errs() << "Old: "; - llvm::interleave(SC.ActiveLabeledStmts, [&](LabeledStmt *LS) { - llvm::errs() << LS; - }, [&] { - llvm::errs() << ' '; - }); - llvm::errs() << "\nNew: "; - llvm::interleave(activeFromASTScope, [&](LabeledStmt *LS) { - llvm::errs() << LS; - }, [&] { - llvm::errs() << ' '; - }); - llvm::errs() << "\n"; - } - assert(activeFromASTScope == SC.ActiveLabeledStmts); - } - } - ~AddLabeledStmt() { - SC.ActiveLabeledStmts.pop_back(); - } - }; - - struct AddSwitchNest { - StmtChecker &SC; - CaseStmt *OuterFallthroughDest; - AddSwitchNest(StmtChecker &SC) : SC(SC), - OuterFallthroughDest(SC.FallthroughDest) { - } - - ~AddSwitchNest() { - SC.FallthroughDest = OuterFallthroughDest; - } - }; StmtChecker(DeclContext *DC) : Ctx(DC->getASTContext()), DC(DC) { } @@ -988,7 +892,8 @@ class StmtChecker : public StmtVisitor { Stmt *visitIfStmt(IfStmt *IS) { typeCheckConditionForStatement(IS, DC); - AddLabeledStmt ifNest(*this, IS); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, IS); Stmt *S = IS->getThenStmt(); typeCheckStmt(S); @@ -1012,7 +917,9 @@ class StmtChecker : public StmtVisitor { } Stmt *visitDoStmt(DoStmt *DS) { - AddLabeledStmt loopNest(*this, DS); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, DS); + BraceStmt *S = DS->getBody(); typeCheckStmt(S); DS->setBody(S); @@ -1022,7 +929,9 @@ class StmtChecker : public StmtVisitor { Stmt *visitWhileStmt(WhileStmt *WS) { typeCheckConditionForStatement(WS, DC); - AddLabeledStmt loopNest(*this, WS); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, WS); + Stmt *S = WS->getBody(); typeCheckStmt(S); WS->setBody(S); @@ -1030,12 +939,12 @@ class StmtChecker : public StmtVisitor { return WS; } Stmt *visitRepeatWhileStmt(RepeatWhileStmt *RWS) { - { - AddLabeledStmt loopNest(*this, RWS); - Stmt *S = RWS->getBody(); - typeCheckStmt(S); - RWS->setBody(S); - } + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, RWS); + + Stmt *S = RWS->getBody(); + typeCheckStmt(S); + RWS->setBody(S); Expr *E = RWS->getCond(); TypeChecker::typeCheckCondition(E, DC); @@ -1048,7 +957,9 @@ class StmtChecker : public StmtVisitor { return nullptr; // Type-check the body of the loop. - AddLabeledStmt loopNest(*this, S); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, S); + BraceStmt *Body = S->getBody(); typeCheckStmt(Body); S->setBody(Body); @@ -1060,7 +971,7 @@ class StmtChecker : public StmtVisitor { if (auto target = findBreakOrContinueStmtTarget( getASTContext(), DC->getParentSourceFile(), S->getLoc(), S->getTargetName(), S->getTargetLoc(), /*isContinue=*/false, - DC, ActiveLabeledStmts)) { + DC)) { S->setTarget(target); } @@ -1071,7 +982,7 @@ class StmtChecker : public StmtVisitor { if (auto target = findBreakOrContinueStmtTarget( getASTContext(), DC->getParentSourceFile(), S->getLoc(), S->getTargetName(), S->getTargetLoc(), /*isContinue=*/true, - DC, ActiveLabeledStmts)) { + DC)) { S->setTarget(target); } @@ -1079,7 +990,7 @@ class StmtChecker : public StmtVisitor { } Stmt *visitFallthroughStmt(FallthroughStmt *S) { - if (checkFallthroughStmt(DC, S, FallthroughSource, FallthroughDest)) + if (checkFallthroughStmt(DC, S)) return nullptr; return S; @@ -1225,13 +1136,6 @@ class StmtChecker : public StmtVisitor { for (auto i = casesBegin; i != casesEnd; ++i) { auto *caseBlock = *i; - if (parentKind == CaseParentKind::Switch) { - // Fallthrough transfers control to the next case block. In the - // final case block, it is invalid. Only switch supports fallthrough. - FallthroughSource = caseBlock; - FallthroughDest = std::next(i) == casesEnd ? nullptr : *std::next(i); - } - // Check restrictions on '@unknown'. if (caseBlock->hasUnknownAttr()) { assert(parentKind == CaseParentKind::Switch && @@ -1258,8 +1162,8 @@ class StmtChecker : public StmtVisitor { Type subjectType = switchStmt->getSubjectExpr()->getType(); // Type-check the case blocks. - AddSwitchNest switchNest(*this); - AddLabeledStmt labelNest(*this, switchStmt); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, switchStmt); // Pre-emptively visit all Decls (#if/#warning/#error) that still exist in // the list of raw cases. @@ -1290,7 +1194,8 @@ class StmtChecker : public StmtVisitor { // The labels are in scope for both the 'do' and all of the catch // clauses. This allows the user to break out of (or restart) the // entire construct. - AddLabeledStmt loopNest(*this, S); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, S); // Type-check the 'do' body. Type failures in here will generally // not cause type failures in the 'catch' clauses. @@ -1698,7 +1603,7 @@ static Type getFunctionBuilderType(FuncDecl *FD) { bool TypeChecker::typeCheckAbstractFunctionBody(AbstractFunctionDecl *AFD) { auto res = evaluateOrDefault(AFD->getASTContext().evaluator, TypeCheckFunctionBodyRequest{AFD}, true); - TypeChecker::checkFunctionErrorHandling(AFD); + TypeChecker::checkFunctionEffects(AFD); TypeChecker::computeCaptures(AFD); return res; } @@ -1754,19 +1659,21 @@ static bool checkSuperInit(ConstructorDecl *fromCtor, // For an implicitly generated super.init() call, make sure there's // only one designated initializer. if (implicitlyGenerated) { - auto superclassTy = ctor->getDeclContext()->getDeclaredInterfaceType(); - auto lookupOptions = defaultConstructorLookupOptions; - lookupOptions |= NameLookupFlags::KnownPrivate; - - // If a constructor is only visible as a witness for a protocol - // requirement, it must be an invalid override. Also, protocol - // extensions cannot yet define designated initializers. - lookupOptions -= NameLookupFlags::ProtocolMembers; - lookupOptions -= NameLookupFlags::PerformConformanceCheck; - - for (auto member : TypeChecker::lookupConstructors(fromCtor, superclassTy, - lookupOptions)) { - auto superclassCtor = dyn_cast(member.getValueDecl()); + auto *dc = ctor->getDeclContext(); + auto *superclassDecl = dc->getSelfClassDecl(); + + superclassDecl->synthesizeSemanticMembersIfNeeded( + DeclBaseName::createConstructor()); + + NLOptions subOptions = NL_QualifiedDefault | NL_KnownNonCascadingDependency; + + SmallVector lookupResults; + fromCtor->lookupQualified(superclassDecl, + DeclNameRef::createConstructor(), + subOptions, lookupResults); + + for (auto decl : lookupResults) { + auto superclassCtor = dyn_cast(decl); if (!superclassCtor || !superclassCtor->isDesignatedInit() || superclassCtor == ctor) continue; @@ -2073,8 +1980,7 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator, // Typechecking, in particular ApplySolution is going to replace closures // with OpaqueValueExprs and then try to do lookups into the closures. // So, build out the body now. - if (ctx.LangOpts.EnableASTScopeLookup) - ASTScope::expandFunctionBody(AFD); + ASTScope::expandFunctionBody(AFD); // Type check the function body if needed. bool hadError = false; @@ -2152,7 +2058,7 @@ void TypeChecker::typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD) { BraceStmt *Body = TLCD->getBody(); StmtChecker(TLCD).typeCheckStmt(Body); TLCD->setBody(Body); - checkTopLevelErrorHandling(TLCD); + checkTopLevelEffects(TLCD); performTopLevelDeclDiagnostics(TLCD); } diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index eca917211a065..4f16d3263ac7f 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -590,7 +590,7 @@ getEnclosingSelfPropertyWrapperAccess(VarDecl *property, bool forProjected) { if (forProjected) { result.accessedProperty = - property->getPropertyWrapperBackingPropertyInfo().storageWrapperVar; + property->getPropertyWrapperBackingPropertyInfo().projectionVar; } else { result.accessedProperty = property; } @@ -1380,7 +1380,7 @@ synthesizeGetterBody(AccessorDecl *getter, ASTContext &ctx) { } if (var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { return synthesizeTrivialGetterBody(getter, TargetImpl::WrapperStorage, ctx); } @@ -1629,7 +1629,7 @@ synthesizeSetterBody(AccessorDecl *setter, ASTContext &ctx) { // Synthesize a setter for the storage wrapper property of a property // with an attached wrapper. if (auto original = var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { auto backingVar = original->getPropertyWrapperBackingProperty(); return synthesizeTrivialSetterBodyWithStorage(setter, TargetImpl::WrapperStorage, @@ -1743,7 +1743,7 @@ synthesizeCoroutineAccessorBody(AccessorDecl *accessor, ASTContext &ctx) { } if (var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { target = TargetImpl::WrapperStorage; } } @@ -1881,7 +1881,7 @@ static AccessorDecl *createGetterPrototype(AbstractStorageDecl *storage, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), genericParams, getterParams, - TypeLoc(), + Type(), storage->getDeclContext()); // If we're stealing the 'self' from a lazy initializer, set it now. @@ -1930,7 +1930,7 @@ static AccessorDecl *createSetterPrototype(AbstractStorageDecl *storage, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), genericParams, params, - TypeLoc(), + Type(), storage->getDeclContext()); if (isMutating) @@ -1961,7 +1961,7 @@ static AccessorDecl *createSetterPrototype(AbstractStorageDecl *storage, case PropertyWrapperSynthesizedPropertyKind::Backing: break; - case PropertyWrapperSynthesizedPropertyKind::StorageWrapper: { + case PropertyWrapperSynthesizedPropertyKind::Projection: { if (auto origVar = var->getOriginalWrappedProperty(wrapperSynthesizedKind)) { // The property wrapper info may not actually link back to a wrapper // implementation, if there was a semantic error checking the wrapper. @@ -2032,7 +2032,7 @@ createCoroutineAccessorPrototype(AbstractStorageDecl *storage, auto *params = buildIndexForwardingParamList(storage, {}, ctx); // Coroutine accessors always return (). - Type retTy = TupleType::getEmpty(ctx); + const Type retTy = TupleType::getEmpty(ctx); GenericParamList *genericParams = createAccessorGenericParams(storage); @@ -2041,7 +2041,7 @@ createCoroutineAccessorPrototype(AbstractStorageDecl *storage, kind, storage, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - genericParams, params, TypeLoc::withoutLoc(retTy), dc); + genericParams, params, retTy, dc); if (isMutating) accessor->setSelfAccessKind(SelfAccessKind::Mutating); @@ -2261,7 +2261,7 @@ IsAccessorTransparentRequest::evaluate(Evaluator &evaluator, } if (auto original = var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { auto backingVar = original->getPropertyWrapperBackingProperty(); if (backingVar->getFormalAccess() < var->getFormalAccess()) return false; @@ -2285,7 +2285,7 @@ IsAccessorTransparentRequest::evaluate(Evaluator &evaluator, break; } else if (var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { break; } } @@ -2381,7 +2381,7 @@ LazyStoragePropertyRequest::evaluate(Evaluator &evaluator, /// Synthesize a computed property `$foo` for a property with an attached /// wrapper that has a `projectedValue` property. -static VarDecl *synthesizePropertyWrapperStorageWrapperProperty( +static VarDecl *synthesizePropertyWrapperProjectionVar( ASTContext &ctx, VarDecl *var, Type wrapperType, VarDecl *wrapperVar) { // If the original property has a @_projectedValueProperty attribute, use @@ -2491,7 +2491,7 @@ static void typeCheckSynthesizedWrapperInitializer( dyn_cast_or_null(pbd->getInitContext(i))) { TypeChecker::contextualizeInitializer(initializerContext, initializer); } - TypeChecker::checkPropertyWrapperErrorHandling(pbd, initializer); + TypeChecker::checkPropertyWrapperEffects(pbd, initializer); } static PropertyWrapperMutability::Value @@ -2520,7 +2520,7 @@ PropertyWrapperMutabilityRequest::evaluate(Evaluator &, bool isProjectedValue = false; if (numWrappers < 1) { originalVar = var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper); + PropertyWrapperSynthesizedPropertyKind::Projection); if (!originalVar) return None; @@ -2598,7 +2598,7 @@ PropertyWrapperLValuenessRequest::evaluate(Evaluator &, bool isProjectedValue = false; if (numWrappers < 1) { VD = var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper); + PropertyWrapperSynthesizedPropertyKind::Projection); numWrappers = 1; // Can't compose projected values isProjectedValue = true; } @@ -2752,7 +2752,7 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator, // synthesize a computed property for '$foo'. VarDecl *storageVar = nullptr; if (wrapperInfo.projectedValueVar) { - storageVar = synthesizePropertyWrapperStorageWrapperProperty( + storageVar = synthesizePropertyWrapperProjectionVar( ctx, var, storageInterfaceType, wrapperInfo.projectedValueVar); } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index c28005a603b29..6e3dc8a61aa4e 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -197,7 +197,7 @@ Type TypeResolution::resolveDependentMemberType( TypoCorrectionResults corrections(ref->getNameRef(), ref->getNameLoc()); TypeChecker::performTypoCorrection(DC, DeclRefKind::Ordinary, MetatypeType::get(baseTy), - NameLookupFlags::ProtocolMembers, + defaultMemberLookupOptions, corrections, builder); // Check whether we have a single type result. @@ -597,26 +597,18 @@ static bool isPointerToVoid(ASTContext &Ctx, Type Ty, bool &IsMutable) { return BGT->getGenericArgs().front()->isVoid(); } -static Type checkContextualRequirements(Type type, - SourceLoc loc, - DeclContext *dc) { - // Even if the type is not generic, it might be inside of a generic - // context, so we need to check requirements. - GenericTypeDecl *decl; - Type parentTy; - if (auto *aliasTy = dyn_cast(type.getPointer())) { - decl = aliasTy->getDecl(); - parentTy = aliasTy->getParent(); - } else if (auto *nominalTy = type->getAs()) { - decl = nominalTy->getDecl(); - parentTy = nominalTy->getParent(); - } else { - return type; - } - +/// Even if the type is not generic, it might be inside of a generic +/// context or have a free-standing 'where' clause, so we need to +/// those check requirements too. +/// +/// Return true on success. +bool TypeChecker::checkContextualRequirements(GenericTypeDecl *decl, + Type parentTy, + SourceLoc loc, + DeclContext *dc) { if (!parentTy || parentTy->hasUnboundGenericType() || parentTy->hasTypeVariable()) { - return type; + return true; } auto &ctx = dc->getASTContext(); @@ -631,7 +623,7 @@ static Type checkContextualRequirements(Type type, else if (ext && ext->isConstrainedExtension()) noteLoc = ext->getLoc(); else - return type; + return true; if (noteLoc.isInvalid()) noteLoc = loc; @@ -640,15 +632,18 @@ static Type checkContextualRequirements(Type type, const auto subMap = parentTy->getContextSubstitutions(decl->getDeclContext()); const auto genericSig = decl->getGenericSignature(); if (!genericSig) { - ctx.Diags.diagnose(loc, diag::recursive_decl_reference, - decl->getDescriptiveKind(), decl->getName()); - decl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); - return ErrorType::get(ctx); + if (loc.isValid()) { + ctx.Diags.diagnose(loc, diag::recursive_decl_reference, + decl->getDescriptiveKind(), decl->getName()); + decl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); + } + return false; } const auto result = TypeChecker::checkGenericArguments( - dc, loc, noteLoc, type, + dc, loc, noteLoc, + decl->getDeclaredInterfaceType(), genericSig->getGenericParams(), genericSig->getRequirements(), QueryTypeSubstitutionMap{subMap}); @@ -656,9 +651,9 @@ static Type checkContextualRequirements(Type type, switch (result) { case RequirementCheckResult::Failure: case RequirementCheckResult::SubstitutionFailure: - return ErrorType::get(ctx); + return false; case RequirementCheckResult::Success: - return type; + return true; } llvm_unreachable("invalid requirement check type"); } @@ -709,7 +704,22 @@ static Type applyGenericArguments(Type type, TypeResolution resolution, if (resolution.getStage() == TypeResolutionStage::Structural) return type; - return checkContextualRequirements(type, loc, dc); + GenericTypeDecl *decl; + Type parentTy; + if (auto *aliasTy = dyn_cast(type.getPointer())) { + decl = aliasTy->getDecl(); + parentTy = aliasTy->getParent(); + } else if (auto *nominalTy = type->getAs()) { + decl = nominalTy->getDecl(); + parentTy = nominalTy->getParent(); + } else { + return type; + } + + if (TypeChecker::checkContextualRequirements(decl, parentTy, loc, dc)) + return type; + + return ErrorType::get(resolution.getASTContext()); } if (type->hasError()) { @@ -935,21 +945,32 @@ Type TypeChecker::applyUnboundGenericArguments(GenericTypeDecl *decl, /// Diagnose a use of an unbound generic type. static void diagnoseUnboundGenericType(Type ty, SourceLoc loc) { - auto unbound = ty->castTo(); - { - auto &ctx = ty->getASTContext(); - InFlightDiagnostic diag = ctx.Diags.diagnose(loc, - diag::generic_type_requires_arguments, ty); - if (auto *genericD = unbound->getDecl()) { + auto &ctx = ty->getASTContext(); + if (auto unbound = ty->getAs()) { + auto *decl = unbound->getDecl(); + { + InFlightDiagnostic diag = ctx.Diags.diagnose(loc, + diag::generic_type_requires_arguments, ty); SmallString<64> genericArgsToAdd; if (TypeChecker::getDefaultGenericArgumentsString(genericArgsToAdd, - genericD)) + decl)) diag.fixItInsertAfter(loc, genericArgsToAdd); } + + decl->diagnose(diag::kind_declname_declared_here, + DescriptiveDeclKind::GenericType, + decl->getName()); + } else { + ty.findIf([&](Type t) -> bool { + if (auto unbound = t->getAs()) { + ctx.Diags.diagnose(loc, + diag::generic_type_requires_arguments, t); + return true; + } + + return false; + }); } - unbound->getDecl()->diagnose(diag::kind_declname_declared_here, - DescriptiveDeclKind::GenericType, - unbound->getDecl()->getName()); } // Produce a diagnostic if the type we referenced was an @@ -1407,22 +1428,29 @@ static Type resolveNestedIdentTypeComponent(TypeResolution resolution, auto maybeDiagnoseBadMemberType = [&](TypeDecl *member, Type memberType, AssociatedTypeDecl *inferredAssocType) { - // Diagnose invalid cases. - if (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member)) { - if (!options.contains(TypeResolutionFlags::SilenceErrors)) { - if (parentTy->is()) - diagnoseUnboundGenericType(parentTy, parentRange.End); - else if (parentTy->isExistentialType() && - isa(member)) { - diags.diagnose(comp->getNameLoc(), diag::assoc_type_outside_of_protocol, - comp->getNameRef()); - } else if (parentTy->isExistentialType() && - isa(member)) { - diags.diagnose(comp->getNameLoc(), diag::typealias_outside_of_protocol, - comp->getNameRef()); - } - } + if (options.contains(TypeResolutionFlags::SilenceErrors)) { + if (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member) + != TypeChecker::UnsupportedMemberTypeAccessKind::None) + return ErrorType::get(ctx); + } + + switch (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member)) { + case TypeChecker::UnsupportedMemberTypeAccessKind::None: + break; + + case TypeChecker::UnsupportedMemberTypeAccessKind::TypeAliasOfUnboundGeneric: + case TypeChecker::UnsupportedMemberTypeAccessKind::AssociatedTypeOfUnboundGeneric: + diagnoseUnboundGenericType(parentTy, parentRange.End); + return ErrorType::get(ctx); + case TypeChecker::UnsupportedMemberTypeAccessKind::TypeAliasOfExistential: + diags.diagnose(comp->getNameLoc(), diag::typealias_outside_of_protocol, + comp->getNameRef()); + return ErrorType::get(ctx); + + case TypeChecker::UnsupportedMemberTypeAccessKind::AssociatedTypeOfExistential: + diags.diagnose(comp->getNameLoc(), diag::assoc_type_outside_of_protocol, + comp->getNameRef()); return ErrorType::get(ctx); } @@ -1489,8 +1517,6 @@ static Type resolveNestedIdentTypeComponent(TypeResolution resolution, NameLookupOptions lookupOptions = defaultMemberLookupOptions; if (isKnownNonCascading) lookupOptions |= NameLookupFlags::KnownPrivate; - if (options.is(TypeResolverContext::ExtensionBinding)) - lookupOptions -= NameLookupFlags::ProtocolMembers; LookupTypeResult memberTypes; if (parentTy->mayHaveMembers()) memberTypes = TypeChecker::lookupMemberType(DC, parentTy, @@ -2070,7 +2096,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, static const TypeAttrKind FunctionAttrs[] = { TAK_convention, TAK_pseudogeneric, TAK_callee_owned, TAK_callee_guaranteed, TAK_noescape, TAK_autoclosure, - TAK_differentiable, TAK_escaping, TAK_yield_once, TAK_yield_many + TAK_differentiable, TAK_escaping, TAK_yield_once, TAK_yield_many, TAK_async }; auto checkUnsupportedAttr = [&](TypeAttrKind attr) { @@ -2216,7 +2242,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // [TODO: Store-SIL-Clang-type] auto extInfo = SILFunctionType::ExtInfoBuilder( rep, attrs.has(TAK_pseudogeneric), - attrs.has(TAK_noescape), diffKind, nullptr) + attrs.has(TAK_noescape), attrs.has(TAK_async), + diffKind, nullptr) .build(); ty = resolveSILFunctionType(fnRepr, options, coroutineKind, extInfo, @@ -2462,6 +2489,13 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, attrs.clearAttribute(TAK_dynamic_self); } + // In SIL *only*, allow @async to specify an async function + if ((options & TypeResolutionFlags::SILMode) && attrs.has(TAK_async)) { + if (fnRepr != nullptr) { + attrs.clearAttribute(TAK_async); + } + } + for (unsigned i = 0; i != TypeAttrKind::TAK_Count; ++i) if (attrs.has((TypeAttrKind)i)) { diagnoseInvalid(repr, attrs.getLoc((TypeAttrKind)i), diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 1b4c38235c72b..9433f75177d5b 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -215,11 +215,17 @@ void swift::bindExtensions(ModuleDecl &mod) { if (!SF) continue; - for (auto D : SF->getTopLevelDecls()) { + auto visitTopLevelDecl = [&](Decl *D) { if (auto ED = dyn_cast(D)) if (!tryBindExtension(ED)) - worklist.push_back(ED); - } + worklist.push_back(ED);; + }; + + for (auto *D : SF->getTopLevelDecls()) + visitTopLevelDecl(D); + + for (auto *D : SF->getHoistedDecls()) + visitTopLevelDecl(D); } // Phase 2 - repeatedly go through the worklist and attempt to bind each @@ -285,9 +291,8 @@ TypeCheckSourceFileRequest::evaluate(Evaluator &eval, SourceFile *SF) const { // scope-based lookups. Only the top-level scopes because extensions have not // been bound yet. auto &Ctx = SF->getASTContext(); - if (Ctx.LangOpts.EnableASTScopeLookup) - SF->getScope() - .buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); + SF->getScope() + .buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); BufferIndirectlyCausingDiagnosticRAII cpr(*SF); diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index cefdf503fc1f6..ad0c427c4d564 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -188,27 +188,12 @@ inline TypeCheckExprOptions operator|(TypeCheckExprFlags flag1, enum class NameLookupFlags { /// Whether we know that this lookup is always a private dependency. KnownPrivate = 0x01, - /// Whether name lookup should be able to find protocol members. - ProtocolMembers = 0x02, - /// Whether we should map the requirement to the witness if we - /// find a protocol member and the base type is a concrete type. - /// - /// If this is not set but ProtocolMembers is set, we will - /// find protocol extension members, but not protocol requirements - /// that do not yet have a witness (such as inferred associated - /// types, or witnesses for derived conformances). - PerformConformanceCheck = 0x04, - /// Whether to perform 'dynamic' name lookup that finds @objc - /// members of any class or protocol. - DynamicLookup = 0x08, /// Whether to ignore access control for this lookup, allowing inaccessible /// results to be returned. IgnoreAccessControl = 0x10, /// Whether to include results from outside the innermost scope that has a /// result. IncludeOuterResults = 0x20, - /// Whether to consider synonyms declared through @_implements(). - IncludeAttributeImplements = 0x40, }; /// A set of options that control name lookup. @@ -220,24 +205,13 @@ inline NameLookupOptions operator|(NameLookupFlags flag1, } /// Default options for member name lookup. -const NameLookupOptions defaultMemberLookupOptions - = NameLookupFlags::ProtocolMembers | - NameLookupFlags::PerformConformanceCheck; - -/// Default options for constructor lookup. -const NameLookupOptions defaultConstructorLookupOptions - = NameLookupFlags::ProtocolMembers | - NameLookupFlags::PerformConformanceCheck; +const NameLookupOptions defaultMemberLookupOptions; /// Default options for member type lookup. -const NameLookupOptions defaultMemberTypeLookupOptions - = NameLookupFlags::ProtocolMembers | - NameLookupFlags::PerformConformanceCheck; +const NameLookupOptions defaultMemberTypeLookupOptions; /// Default options for unqualified name lookup. -const NameLookupOptions defaultUnqualifiedLookupOptions - = NameLookupFlags::ProtocolMembers | - NameLookupFlags::PerformConformanceCheck; +const NameLookupOptions defaultUnqualifiedLookupOptions; /// Describes the result of comparing two entities, of which one may be better /// or worse than the other, or they are unordered. @@ -315,7 +289,11 @@ Type getOptionalType(SourceLoc loc, Type elementType); /// 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); +/// +/// \param replaceInvalidRefsWithErrors Indicates whether it's allowed +/// to replace any discovered invalid member references with `ErrorExpr`. +Expr *resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *Context, + bool replaceInvalidRefsWithErrors); /// Check for unsupported protocol types in the given declaration. void checkUnsupportedProtocolType(Decl *decl); @@ -601,6 +579,11 @@ RequirementCheckResult checkGenericArguments( ArrayRef requirements, TypeSubstitutionFn substitutions, SubstOptions options = None); +bool checkContextualRequirements(GenericTypeDecl *decl, + Type parentTy, + SourceLoc loc, + DeclContext *dc); + /// Add any implicitly-defined constructors required for the given /// struct or class. void addImplicitConstructors(NominalTypeDecl *typeDecl); @@ -936,17 +919,6 @@ LookupTypeResult lookupMemberType(DeclContext *dc, Type type, DeclNameRef name, NameLookupOptions options = defaultMemberTypeLookupOptions); -/// Look up the constructors of the given type. -/// -/// \param dc The context that needs the constructor. -/// \param type The type for which we will look for constructors. -/// \param options Options that control name lookup. -/// -/// \returns the constructors found for this type. -LookupResult lookupConstructors( - DeclContext *dc, Type type, - NameLookupOptions options = defaultConstructorLookupOptions); - /// Given an expression that's known to be an infix operator, /// look up its precedence group. PrecedenceGroupDecl *lookupPrecedenceGroupForInfixOperator(DeclContext *dc, @@ -955,9 +927,18 @@ PrecedenceGroupDecl *lookupPrecedenceGroupForInfixOperator(DeclContext *dc, PrecedenceGroupLookupResult lookupPrecedenceGroup(DeclContext *dc, Identifier name, SourceLoc nameLoc); +enum class UnsupportedMemberTypeAccessKind : uint8_t { + None, + TypeAliasOfUnboundGeneric, + TypeAliasOfExistential, + AssociatedTypeOfUnboundGeneric, + AssociatedTypeOfExistential +}; + /// Check whether the given declaration can be written as a /// member of the given base type. -bool isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl); +UnsupportedMemberTypeAccessKind +isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl); /// @} @@ -1147,11 +1128,11 @@ void diagnoseIfDeprecated(SourceRange SourceRange, void checkForForbiddenPrefix(ASTContext &C, DeclBaseName Name); /// Check error handling in the given type-checked top-level code. -void checkTopLevelErrorHandling(TopLevelCodeDecl *D); -void checkFunctionErrorHandling(AbstractFunctionDecl *D); -void checkInitializerErrorHandling(Initializer *I, Expr *E); -void checkEnumElementErrorHandling(EnumElementDecl *D, Expr *expr); -void checkPropertyWrapperErrorHandling(PatternBindingDecl *binding, +void checkTopLevelEffects(TopLevelCodeDecl *D); +void checkFunctionEffects(AbstractFunctionDecl *D); +void checkInitializerEffects(Initializer *I, Expr *E); +void checkEnumElementEffects(EnumElementDecl *D, Expr *expr); +void checkPropertyWrapperEffects(PatternBindingDecl *binding, Expr *expr); /// If an expression references 'self.init' or 'super.init' in an @@ -1235,6 +1216,18 @@ bool requirePointerArgumentIntrinsics(ASTContext &ctx, SourceLoc loc); /// Require that the library intrinsics for creating /// array literals exist. bool requireArrayLiteralIntrinsics(ASTContext &ctx, SourceLoc loc); + +/// Gets the \c UnresolvedMemberExpr at the base of a chain of member accesses. +/// If \c expr is not part of a member chain or the base is something other than +/// an \c UnresolvedMemberExpr, \c nullptr is returned. +UnresolvedMemberExpr *getUnresolvedMemberChainBase(Expr *expr); + +/// Checks whether a function builder type has a well-formed function builder +/// method with the given name. If provided and non-empty, the argument labels +/// are verified against any candidates. +bool typeSupportsBuilderOp(Type builderType, DeclContext *dc, Identifier fnName, + ArrayRef argLabels = {}, + SmallVectorImpl *allResults = nullptr); }; // namespace TypeChecker /// Temporary on-stack storage and unescaping for encoded diagnostic @@ -1391,6 +1384,10 @@ void checkUnknownAttrRestrictions( /// it to later stages. void bindSwitchCasePatternVars(DeclContext *dc, CaseStmt *stmt); +/// Add notes suggesting the addition of 'async' or '@asyncHandler', as +/// appropriate, to a diagnostic for a function that isn't an async context. +void addAsyncNotes(FuncDecl *func); + } // end namespace swift #endif diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index ddbc8f9a513d0..f2f70f9be2ed0 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1611,6 +1611,14 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { getXRefDeclNameForError()); } + if (memberName.getKind() == DeclBaseName::Kind::Destructor) { + assert(isa(nominal)); + // Force creation of an implicit destructor + auto CD = dyn_cast(nominal); + values.push_back(CD->getDestructor()); + break; + } + if (!privateDiscriminator.empty()) { ModuleDecl *searchModule = M; if (!searchModule) @@ -2897,13 +2905,13 @@ class DeclDeserializer { } VarDecl *backingVar = cast(backingDecl.get()); - VarDecl *storageWrapperVar = nullptr; + VarDecl *projectionVar = nullptr; if (numBackingProperties > 1) { - storageWrapperVar = cast(MF.getDecl(backingPropertyIDs[1])); + projectionVar = cast(MF.getDecl(backingPropertyIDs[1])); } PropertyWrapperBackingPropertyInfo info( - backingVar, storageWrapperVar, nullptr, nullptr); + backingVar, projectionVar, nullptr, nullptr); ctx.evaluator.cacheOutput( PropertyWrapperBackingPropertyInfoRequest{var}, std::move(info)); ctx.evaluator.cacheOutput( @@ -2911,8 +2919,8 @@ class DeclDeserializer { backingVar->getInterfaceType()); backingVar->setOriginalWrappedProperty(var); - if (storageWrapperVar) - storageWrapperVar->setOriginalWrappedProperty(var); + if (projectionVar) + projectionVar->setOriginalWrappedProperty(var); } return var; @@ -2995,6 +3003,7 @@ class DeclDeserializer { DeclID accessorStorageDeclID; bool overriddenAffectsABI, needsNewVTableEntry, isTransparent; DeclID opaqueReturnTypeID; + bool isUserAccessible; ArrayRef nameAndDependencyIDs; if (!isAccessor) { @@ -3012,6 +3021,7 @@ class DeclDeserializer { rawAccessLevel, needsNewVTableEntry, opaqueReturnTypeID, + isUserAccessible, nameAndDependencyIDs); } else { decls_block::AccessorLayout::readRecord(scratch, contextID, isImplicit, @@ -3123,21 +3133,19 @@ class DeclDeserializer { if (declOrOffset.isComplete()) return declOrOffset; + const auto resultType = MF.getType(resultInterfaceTypeID); + if (declOrOffset.isComplete()) + return declOrOffset; + FuncDecl *fn; if (!isAccessor) { - fn = FuncDecl::createDeserialized( - ctx, /*StaticLoc=*/SourceLoc(), staticSpelling.getValue(), - /*FuncLoc=*/SourceLoc(), name, /*NameLoc=*/SourceLoc(), - async, /*AsyncLoc=*/SourceLoc(), - /*Throws=*/throws, /*ThrowsLoc=*/SourceLoc(), - genericParams, DC); + fn = FuncDecl::createDeserialized(ctx, staticSpelling.getValue(), name, + async, throws, genericParams, + resultType, DC); } else { auto *accessor = AccessorDecl::createDeserialized( - ctx, /*FuncLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(), - accessorKind, storage, - /*StaticLoc=*/SourceLoc(), staticSpelling.getValue(), - /*Throws=*/throws, /*ThrowsLoc=*/SourceLoc(), - genericParams, DC); + ctx, accessorKind, storage, staticSpelling.getValue(), + /*Throws=*/throws, genericParams, resultType, DC); accessor->setIsTransparent(isTransparent); fn = accessor; @@ -3173,8 +3181,6 @@ class DeclDeserializer { } fn->setStatic(isStatic); - - fn->getBodyResultTypeLoc().setType(MF.getType(resultInterfaceTypeID)); fn->setImplicitlyUnwrappedOptional(isIUO); ParameterList *paramList = MF.readParameterList(); @@ -3203,6 +3209,9 @@ class DeclDeserializer { cast(MF.getDecl(opaqueReturnTypeID))); } + if (!isAccessor) + fn->setUserAccessible(isUserAccessible); + return fn; } @@ -3850,11 +3859,12 @@ class DeclDeserializer { if (!staticSpelling.hasValue()) MF.fatal(); - auto subscript = MF.createDecl(name, - SourceLoc(), *staticSpelling, - SourceLoc(), nullptr, - SourceLoc(), TypeLoc(), - parent, genericParams); + const auto elemInterfaceType = MF.getType(elemInterfaceTypeID); + if (declOrOffset.isComplete()) + return declOrOffset; + + auto *const subscript = SubscriptDecl::createDeserialized( + ctx, name, *staticSpelling, elemInterfaceType, parent, genericParams); subscript->setIsGetterMutating(isGetterMutating); subscript->setIsSetterMutating(isSetterMutating); declOrOffset = subscript; @@ -3878,8 +3888,6 @@ class DeclDeserializer { MF.fatal(); } - auto elemInterfaceType = MF.getType(elemInterfaceTypeID); - subscript->getElementTypeLoc().setType(elemInterfaceType); subscript->setImplicitlyUnwrappedOptional(isIUO); if (isImplicit) @@ -5360,6 +5368,7 @@ class TypeDeserializer { Expected deserializeSILFunctionType(ArrayRef scratch, StringRef blobData) { + bool async; uint8_t rawCoroutineKind; uint8_t rawCalleeConvention; uint8_t rawRepresentation; @@ -5377,6 +5386,7 @@ class TypeDeserializer { ClangTypeID clangFunctionTypeID; decls_block::SILFunctionTypeLayout::readRecord(scratch, + async, rawCoroutineKind, rawCalleeConvention, rawRepresentation, @@ -5403,21 +5413,18 @@ class TypeDeserializer { if (!diffKind.hasValue()) MF.fatal(); - const clang::FunctionType *clangFunctionType = nullptr; + const clang::Type *clangFunctionType = nullptr; if (clangFunctionTypeID) { auto clangType = MF.getClangType(clangFunctionTypeID); if (!clangType) return clangType.takeError(); - // FIXME: allow block pointers here. - clangFunctionType = - dyn_cast_or_null(clangType.get()); - if (!clangFunctionType) - MF.fatal(); + clangFunctionType = clangType.get(); } auto extInfo = SILFunctionType::ExtInfoBuilder(*representation, pseudogeneric, - noescape, *diffKind, clangFunctionType) + noescape, async, *diffKind, + clangFunctionType) .build(); // Process the coroutine kind. diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 97c84001d009c..b3024b0939170 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -510,18 +510,17 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, IdentifierID replacedFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), + isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass, - funcTyID, replacedFunctionID, genericSigID, + isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), + isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, clangNodeOwnerID, SemanticsIDs); if (funcTyID == 0) { @@ -626,11 +625,6 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, MF->fatal(); } - if (fn->isAsync() != isAsync) { - LLVM_DEBUG(llvm::dbgs() << "SILFunction type mismatch.\n"); - MF->fatal(); - } - } else { // Otherwise, create a new function. fn = builder.createDeclaration(name, ty, loc); @@ -639,12 +633,13 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setSerialized(IsSerialized_t(isSerialized)); fn->setThunk(IsThunk_t(isThunk)); fn->setWithoutActuallyEscapingThunk(bool(isWithoutactuallyEscapingThunk)); - fn->setAsync((bool)isAsync); fn->setInlineStrategy(Inline_t(inlineStrategy)); fn->setSpecialPurpose(SILFunction::Purpose(specialPurpose)); fn->setEffectsKind(EffectsKind(effect)); fn->setOptimizationMode(OptimizationMode(optimizationMode)); fn->setAlwaysWeakImported(isWeakImported); + fn->setClassSubclassScope(SubclassScope(subclassScope)); + fn->setHasCReferences(bool(hasCReferences)); llvm::VersionTuple available; DECODE_VER_TUPLE(available); @@ -1184,7 +1179,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, // FIXME: validate SILInstructionKind OpCode = (SILInstructionKind) RawOpCode; - SILInstruction *ResultVal; + SILInstruction *ResultInst; switch (OpCode) { case SILInstructionKind::DebugValueInst: case SILInstructionKind::DebugValueAddrInst: @@ -1192,19 +1187,19 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::AllocBoxInst: assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); - ResultVal = Builder.createAllocBox(Loc, - cast(MF->getType(TyID)->getCanonicalType()), - None, /*bool hasDynamicLifetime*/ Attr != 0); + ResultInst = Builder.createAllocBox( + Loc, cast(MF->getType(TyID)->getCanonicalType()), None, + /*bool hasDynamicLifetime*/ Attr != 0); break; case SILInstructionKind::AllocStackInst: assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); - ResultVal = Builder.createAllocStack( + ResultInst = Builder.createAllocStack( Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), None, /*bool hasDynamicLifetime*/ Attr != 0); break; case SILInstructionKind::MetatypeInst: assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); - ResultVal = Builder.createMetatype( + ResultInst = Builder.createMetatype( Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); break; @@ -1212,7 +1207,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::ID##Inst: \ assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && \ "Layout should be OneTypeOneOperand."); \ - ResultVal = Builder.create##ID( \ + ResultInst = Builder.create##ID( \ Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), \ getLocalValue(ValID, getSILType(MF->getType(TyID2), \ (SILValueCategory)TyCategory2, Fn))); \ @@ -1227,7 +1222,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::DeallocBoxInst: assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); - ResultVal = Builder.createDeallocBox( + ResultInst = Builder.createDeallocBox( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn))); @@ -1235,7 +1230,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::OpenExistentialAddrInst: assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); - ResultVal = Builder.createOpenExistentialAddr( + ResultInst = Builder.createOpenExistentialAddr( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), @@ -1248,7 +1243,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::ID##Inst: \ assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && \ "Layout should be OneTypeOneOperand."); \ - ResultVal = Builder.create##ID( \ + ResultInst = Builder.create##ID( \ Loc, \ getLocalValue(ValID, getSILType(MF->getType(TyID2), \ (SILValueCategory)TyCategory2, Fn)), \ @@ -1288,7 +1283,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::ProjectBoxInst: { assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); - ResultVal = Builder.createProjectBox( + ResultInst = Builder.createProjectBox( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), @@ -1299,7 +1294,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); bool isLifetimeGuaranteed = Attr & 0x01; - ResultVal = Builder.createConvertEscapeToNoEscape( + ResultInst = Builder.createConvertEscapeToNoEscape( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), @@ -1311,7 +1306,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); bool withoutActuallyEscaping = Attr & 0x01; - ResultVal = Builder.createConvertFunction( + ResultInst = Builder.createConvertFunction( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), @@ -1324,18 +1319,18 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, "Layout should be OneTypeOneOperand."); bool isStrict = Attr & 0x01; bool isInvariant = Attr & 0x02; - ResultVal = Builder.createPointerToAddress( + ResultInst = Builder.createPointerToAddress( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), isStrict, - isInvariant); + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), + isStrict, isInvariant); break; } case SILInstructionKind::DeallocExistentialBoxInst: { assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); - ResultVal = Builder.createDeallocExistentialBox( + ResultInst = Builder.createDeallocExistentialBox( Loc, MF->getType(TyID)->getCanonicalType(), getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn))); @@ -1350,15 +1345,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto BitsTy = getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn); auto Bits = getLocalValue(ValID2, BitsTy); - - ResultVal = Builder.createRefToBridgeObject(Loc, Ref, Bits); + + ResultInst = Builder.createRefToBridgeObject(Loc, Ref, Bits); break; } case SILInstructionKind::ObjCProtocolInst: { auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); auto Proto = MF->getDecl(ValID); - ResultVal = Builder.createObjCProtocol(Loc, cast(Proto), Ty); + ResultInst = Builder.createObjCProtocol(Loc, cast(Proto), Ty); break; } @@ -1389,28 +1384,24 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, switch (OpCode) { default: llvm_unreachable("Out of sync with parent switch"); case SILInstructionKind::InitExistentialAddrInst: - ResultVal = Builder.createInitExistentialAddr(Loc, operand, - ConcreteTy, - Ty, - ctxConformances); + ResultInst = Builder.createInitExistentialAddr(Loc, operand, ConcreteTy, + Ty, ctxConformances); break; case SILInstructionKind::InitExistentialValueInst: - ResultVal = Builder.createInitExistentialValue(Loc, Ty, ConcreteTy, + ResultInst = Builder.createInitExistentialValue(Loc, Ty, ConcreteTy, operand, ctxConformances); break; case SILInstructionKind::InitExistentialMetatypeInst: - ResultVal = Builder.createInitExistentialMetatype(Loc, operand, Ty, - ctxConformances); + ResultInst = Builder.createInitExistentialMetatype(Loc, operand, Ty, + ctxConformances); break; case SILInstructionKind::InitExistentialRefInst: - ResultVal = Builder.createInitExistentialRef(Loc, Ty, - ConcreteTy, - operand, - ctxConformances); + ResultInst = Builder.createInitExistentialRef(Loc, Ty, ConcreteTy, + operand, ctxConformances); break; case SILInstructionKind::AllocExistentialBoxInst: - ResultVal = Builder.createAllocExistentialBox(Loc, Ty, ConcreteTy, - ctxConformances); + ResultInst = Builder.createAllocExistentialBox(Loc, Ty, ConcreteTy, + ctxConformances); break; } break; @@ -1444,12 +1435,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILType MetadataType = getSILType(MF->getType(ListOfValues[i+1]), SILValueCategory::Object, Fn); SILValue MetadataOp = getLocalValue(ListOfValues[i], MetadataType); - ResultVal = Builder.createAllocRefDynamic(Loc, MetadataOp, ClassTy, - isObjC, TailTypes, Counts); + ResultInst = Builder.createAllocRefDynamic(Loc, MetadataOp, ClassTy, + isObjC, TailTypes, Counts); } else { assert(i == NumVals); - ResultVal = Builder.createAllocRef(Loc, ClassTy, isObjC, canAllocOnStack, - TailTypes, Counts); + ResultInst = Builder.createAllocRef(Loc, ClassTy, isObjC, canAllocOnStack, + TailTypes, Counts); } break; } @@ -1474,13 +1465,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SubstitutionMap Substitutions = MF->getSubstitutionMap(NumSubs); if (OpCode == SILInstructionKind::ApplyInst) { - ResultVal = Builder.createApply(Loc, getLocalValue(ValID, FnTy), - Substitutions, Args, - IsNonThrowingApply != 0); + ResultInst = + Builder.createApply(Loc, getLocalValue(ValID, FnTy), Substitutions, + Args, IsNonThrowingApply != 0); } else { - ResultVal = Builder.createBeginApply(Loc, getLocalValue(ValID, FnTy), - Substitutions, Args, - IsNonThrowingApply != 0); + ResultInst = Builder.createBeginApply(Loc, getLocalValue(ValID, FnTy), + Substitutions, Args, + IsNonThrowingApply != 0); } break; } @@ -1510,9 +1501,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, I, Builder.getTypeExpansionContext()))); SubstitutionMap Substitutions = MF->getSubstitutionMap(NumSubs); - ResultVal = Builder.createTryApply(Loc, getLocalValue(ValID, FnTy), - Substitutions, Args, normalBB, - errorBB); + ResultInst = Builder.createTryApply(Loc, getLocalValue(ValID, FnTy), + Substitutions, Args, normalBB, errorBB); break; } case SILInstructionKind::PartialApplyInst: { @@ -1546,7 +1536,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, ? PartialApplyInst::OnStackKind::OnStack : PartialApplyInst::OnStackKind::NotOnStack; // FIXME: Why the arbitrary order difference in IRBuilder type argument? - ResultVal = Builder.createPartialApply( + ResultInst = Builder.createPartialApply( Loc, FnVal, Substitutions, Args, closureTy.castTo()->getCalleeConvention(), onStack); break; @@ -1563,9 +1553,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, } SubstitutionMap Substitutions = MF->getSubstitutionMap(NumSubs); Identifier Name = MF->getIdentifier(ValID); - - ResultVal = Builder.createBuiltin(Loc, Name, ResultTy, Substitutions, - Args); + + ResultInst = + Builder.createBuiltin(Loc, Name, ResultTy, Substitutions, Args); break; } case SILInstructionKind::AllocGlobalInst: { @@ -1576,7 +1566,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILGlobalVariable *g = getGlobalForReference(Name); assert(g && "Can't deserialize global variable"); - ResultVal = Builder.createAllocGlobal(Loc, g); + ResultInst = Builder.createAllocGlobal(Loc, g); break; } case SILInstructionKind::GlobalAddrInst: @@ -1598,20 +1588,20 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, (void)Ty; (void)expectedType; if (OpCode == SILInstructionKind::GlobalAddrInst) { - ResultVal = Builder.createGlobalAddr(Loc, g); + ResultInst = Builder.createGlobalAddr(Loc, g); } else { - ResultVal = Builder.createGlobalValue(Loc, g); + ResultInst = Builder.createGlobalValue(Loc, g); } break; } case SILInstructionKind::BaseAddrForOffsetInst: assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); - ResultVal = Builder.createBaseAddrForOffset(Loc, - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); + ResultInst = Builder.createBaseAddrForOffset( + Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); break; case SILInstructionKind::DeallocStackInst: { auto Ty = MF->getType(TyID); - ResultVal = Builder.createDeallocStack( + ResultInst = Builder.createDeallocStack( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn))); break; @@ -1619,7 +1609,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::DeallocRefInst: { auto Ty = MF->getType(TyID); bool OnStack = (bool)Attr; - ResultVal = Builder.createDeallocRef( + ResultInst = Builder.createDeallocRef( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), OnStack); @@ -1628,17 +1618,17 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::DeallocPartialRefInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createDeallocPartialRef(Loc, - getLocalValue(ValID, - getSILType(Ty, (SILValueCategory)TyCategory, Fn)), + ResultInst = Builder.createDeallocPartialRef( + Loc, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, - getSILType(Ty2, (SILValueCategory)TyCategory2, Fn))); + getSILType(Ty2, (SILValueCategory)TyCategory2, Fn))); break; } case SILInstructionKind::FunctionRefInst: { auto Ty = MF->getType(TyID); StringRef FuncName = MF->getIdentifierText(ValID); - ResultVal = Builder.createFunctionRef( + ResultInst = Builder.createFunctionRef( Loc, getFuncForReference( FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr))); @@ -1647,7 +1637,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::DynamicFunctionRefInst: { auto Ty = MF->getType(TyID); StringRef FuncName = MF->getIdentifierText(ValID); - ResultVal = Builder.createDynamicFunctionRef( + ResultInst = Builder.createDynamicFunctionRef( Loc, getFuncForReference( FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr))); @@ -1656,7 +1646,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::PreviousDynamicFunctionRefInst: { auto Ty = MF->getType(TyID); StringRef FuncName = MF->getIdentifierText(ValID); - ResultVal = Builder.createPreviousDynamicFunctionRef( + ResultInst = Builder.createPreviousDynamicFunctionRef( Loc, getFuncForReference( FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr))); @@ -1665,7 +1655,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::MarkDependenceInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createMarkDependence( + ResultInst = Builder.createMarkDependence( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, @@ -1675,7 +1665,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::CopyBlockWithoutEscapingInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createCopyBlockWithoutEscaping( + ResultInst = Builder.createCopyBlockWithoutEscaping( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, @@ -1685,7 +1675,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::IndexAddrInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createIndexAddr( + ResultInst = Builder.createIndexAddr( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, @@ -1696,7 +1686,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); auto ResultTy = MF->getType(TyID3); - ResultVal = Builder.createTailAddr( + ResultInst = Builder.createTailAddr( Loc, getLocalValue(ValID, getSILType(Ty, SILValueCategory::Address, Fn)), getLocalValue(ValID2, getSILType(Ty2, SILValueCategory::Object, Fn)), @@ -1706,7 +1696,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::IndexRawPointerInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createIndexRawPointer( + ResultInst = Builder.createIndexRawPointer( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, @@ -1720,7 +1710,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, bool negate = text[0] == '-'; if (negate) text = text.drop_front(); APInt value = intTy->getWidth().parse(text, 10, negate); - ResultVal = Builder.createIntegerLiteral( + ResultInst = Builder.createIntegerLiteral( Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), value); break; } @@ -1735,7 +1725,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, APFloat value(floatTy->getAPFloatSemantics(), bits); - ResultVal = Builder.createFloatLiteral( + ResultInst = Builder.createFloatLiteral( Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), value); break; } @@ -1743,15 +1733,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, StringRef StringVal = MF->getIdentifierText(ValID); auto encoding = fromStableStringEncoding(Attr); if (!encoding) return true; - ResultVal = Builder.createStringLiteral(Loc, StringVal, - encoding.getValue()); + ResultInst = + Builder.createStringLiteral(Loc, StringVal, encoding.getValue()); break; } case SILInstructionKind::CondFailInst: { SILValue Op = getLocalValue( ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); StringRef StringVal = MF->getIdentifierText(ValID2); - ResultVal = Builder.createCondFail(Loc, Op, StringVal); + ResultInst = Builder.createCondFail(Loc, Op, StringVal); break; } case SILInstructionKind::MarkFunctionEscapeInst: { @@ -1764,7 +1754,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, ListOfValues[I + 2], getSILType(EltTy, (SILValueCategory)ListOfValues[I + 1], Fn))); } - ResultVal = Builder.createMarkFunctionEscape(Loc, OpList); + ResultInst = Builder.createMarkFunctionEscape(Loc, OpList); break; } // Checked Conversion instructions. @@ -1777,7 +1767,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); CanType targetFormalType = MF->getType(ListOfValues[3])->getCanonicalType(); - ResultVal = Builder.createUnconditionalCheckedCast( + ResultInst = Builder.createUnconditionalCheckedCast( Loc, src, targetLoweredType, targetFormalType); break; } @@ -1785,7 +1775,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, #define UNARY_INSTRUCTION(ID) \ case SILInstructionKind::ID##Inst: \ assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); \ - ResultVal = Builder.create##ID( \ + ResultInst = Builder.create##ID( \ Loc, \ getLocalValue(ValID, getSILType(MF->getType(TyID), \ (SILValueCategory)TyCategory, Fn))); \ @@ -1794,7 +1784,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, #define REFCOUNTING_INSTRUCTION(ID) \ case SILInstructionKind::ID##Inst: \ assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); \ - ResultVal = Builder.create##ID( \ + ResultInst = Builder.create##ID( \ Loc, \ getLocalValue(ValID, getSILType(MF->getType(TyID), \ (SILValueCategory)TyCategory, Fn)), \ @@ -1844,7 +1834,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::IsEscapingClosureInst: { assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); unsigned verificationType = Attr; - ResultVal = Builder.createIsEscapingClosure( + ResultInst = Builder.createIsEscapingClosure( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)), @@ -1855,10 +1845,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::BeginCOWMutationInst: { assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); unsigned isNative = Attr; - ResultVal = Builder.createBeginCOWMutation( + ResultInst = Builder.createBeginCOWMutation( Loc, - getLocalValue(ValID, - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)), + getLocalValue(ValID, getSILType(MF->getType(TyID), + (SILValueCategory)TyCategory, Fn)), isNative != 0); break; } @@ -1866,7 +1856,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::EndCOWMutationInst: { assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); unsigned keepUnique = Attr; - ResultVal = Builder.createEndCOWMutation( + ResultInst = Builder.createEndCOWMutation( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)), @@ -1878,20 +1868,20 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); SILValue Operand = getLocalValue( ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); - ResultVal = Builder.createDestructureTuple(Loc, Operand); + ResultInst = Builder.createDestructureTuple(Loc, Operand); break; } case SILInstructionKind::DestructureStructInst: { assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); SILValue Operand = getLocalValue( ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); - ResultVal = Builder.createDestructureStruct(Loc, Operand); + ResultInst = Builder.createDestructureStruct(Loc, Operand); break; } case SILInstructionKind::UncheckedOwnershipConversionInst: { auto Ty = MF->getType(TyID); auto ResultKind = ValueOwnershipKind(Attr); - ResultVal = Builder.createUncheckedOwnershipConversion( + ResultInst = Builder.createUncheckedOwnershipConversion( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), ResultKind); @@ -1901,7 +1891,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::LoadInst: { auto Ty = MF->getType(TyID); auto Qualifier = LoadOwnershipQualifier(Attr); - ResultVal = Builder.createLoad( + ResultInst = Builder.createLoad( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), Qualifier); @@ -1914,7 +1904,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, bool isTake = (Attr > 0); \ auto Val = getLocalValue( \ ValID, getSILType(Ty, SILValueCategory(TyCategory), Fn)); \ - ResultVal = Builder.createLoad##Name(Loc, Val, IsTake_t(isTake)); \ + ResultInst = Builder.createLoad##Name(Loc, Val, IsTake_t(isTake)); \ break; \ } \ case SILInstructionKind::Store##Name##Inst: { \ @@ -1923,9 +1913,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto refType = addrType.castTo(); \ auto ValType = SILType::getPrimitiveObjectType(refType.getReferentType()); \ bool isInit = (Attr > 0); \ - ResultVal = Builder.createStore##Name(Loc, getLocalValue(ValID, ValType), \ - getLocalValue(ValID2, addrType), \ - IsInitialization_t(isInit)); \ + ResultInst = Builder.createStore##Name(Loc, getLocalValue(ValID, ValType), \ + getLocalValue(ValID2, addrType), \ + IsInitialization_t(isInit)); \ break; \ } #include "swift/AST/ReferenceStorage.def" @@ -1933,7 +1923,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); auto Kind = (MarkUninitializedInst::Kind)Attr; auto Val = getLocalValue(ValID, Ty); - ResultVal = Builder.createMarkUninitialized(Loc, Val, Kind); + ResultInst = Builder.createMarkUninitialized(Loc, Val, Kind); break; } case SILInstructionKind::StoreInst: { @@ -1941,16 +1931,17 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); SILType ValType = addrType.getObjectType(); auto Qualifier = StoreOwnershipQualifier(Attr); - ResultVal = Builder.createStore(Loc, getLocalValue(ValID, ValType), - getLocalValue(ValID2, addrType), Qualifier); + ResultInst = + Builder.createStore(Loc, getLocalValue(ValID, ValType), + getLocalValue(ValID2, addrType), Qualifier); break; } case SILInstructionKind::StoreBorrowInst: { auto Ty = MF->getType(TyID); SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); SILType ValType = addrType.getObjectType(); - ResultVal = Builder.createStoreBorrow(Loc, getLocalValue(ValID, ValType), - getLocalValue(ValID2, addrType)); + ResultInst = Builder.createStoreBorrow(Loc, getLocalValue(ValID, ValType), + getLocalValue(ValID2, addrType)); break; } case SILInstructionKind::BeginAccessInst: { @@ -1960,16 +1951,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto enforcement = SILAccessEnforcement((Attr >> 2) & 0x3); bool noNestedConflict = (Attr >> 4) & 0x01; bool fromBuiltin = (Attr >> 5) & 0x01; - ResultVal = - Builder.createBeginAccess(Loc, op, accessKind, enforcement, - noNestedConflict, fromBuiltin); + ResultInst = Builder.createBeginAccess(Loc, op, accessKind, enforcement, + noNestedConflict, fromBuiltin); break; } case SILInstructionKind::EndAccessInst: { SILValue op = getLocalValue( ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); bool aborted = Attr & 0x1; - ResultVal = Builder.createEndAccess(Loc, op, aborted); + ResultInst = Builder.createEndAccess(Loc, op, aborted); break; } case SILInstructionKind::BeginUnpairedAccessInst: { @@ -1982,9 +1972,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto enforcement = SILAccessEnforcement((Attr >> 2) & 0x03); bool noNestedConflict = (Attr >> 4) & 0x01; bool fromBuiltin = (Attr >> 5) & 0x01; - ResultVal = Builder.createBeginUnpairedAccess( - Loc, source, buffer, accessKind, enforcement, noNestedConflict, - fromBuiltin); + ResultInst = Builder.createBeginUnpairedAccess( + Loc, source, buffer, accessKind, enforcement, noNestedConflict, + fromBuiltin); break; } case SILInstructionKind::EndUnpairedAccessInst: { @@ -1993,8 +1983,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, bool aborted = Attr & 0x1; auto enforcement = SILAccessEnforcement((Attr >> 1) & 0x03); bool fromBuiltin = (Attr >> 3) & 0x01; - ResultVal = Builder.createEndUnpairedAccess(Loc, op, enforcement, aborted, - fromBuiltin); + ResultInst = Builder.createEndUnpairedAccess(Loc, op, enforcement, aborted, + fromBuiltin); break; } case SILInstructionKind::CopyAddrInst: { @@ -2002,11 +1992,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); bool isInit = (Attr & 0x2) > 0; bool isTake = (Attr & 0x1) > 0; - ResultVal = Builder.createCopyAddr(Loc, - getLocalValue(ValID, addrType), - getLocalValue(ValID2, addrType), - IsTake_t(isTake), - IsInitialization_t(isInit)); + ResultInst = Builder.createCopyAddr( + Loc, getLocalValue(ValID, addrType), getLocalValue(ValID2, addrType), + IsTake_t(isTake), IsInitialization_t(isInit)); break; } case SILInstructionKind::AssignInst: { @@ -2014,10 +2002,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); SILType valType = addrType.getObjectType(); auto qualifier = AssignOwnershipQualifier(Attr); - ResultVal = Builder.createAssign(Loc, - getLocalValue(ValID, valType), - getLocalValue(ValID2, addrType), - qualifier); + ResultInst = + Builder.createAssign(Loc, getLocalValue(ValID, valType), + getLocalValue(ValID2, addrType), qualifier); break; } case SILInstructionKind::AssignByWrapperInst: @@ -2026,7 +2013,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, assert(RecordKind == SIL_ONE_TYPE_VALUES && "Layout should be OneTypeValues."); auto Ty = MF->getType(TyID); // BoundTy - ResultVal = Builder.createBindMemory( + ResultInst = Builder.createBindMemory( Loc, getLocalValue(ListOfValues[2], getSILType(MF->getType(ListOfValues[0]), @@ -2047,11 +2034,11 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto ResultTy = Val->getType().getFieldType( Field, SILMod, Builder.getTypeExpansionContext()); if (OpCode == SILInstructionKind::StructElementAddrInst) - ResultVal = Builder.createStructElementAddr(Loc, Val, Field, - ResultTy.getAddressType()); + ResultInst = Builder.createStructElementAddr(Loc, Val, Field, + ResultTy.getAddressType()); else - ResultVal = Builder.createStructExtract(Loc, Val, Field, - ResultTy.getObjectType()); + ResultInst = Builder.createStructExtract(Loc, Val, Field, + ResultTy.getObjectType()); break; } case SILInstructionKind::StructInst: { @@ -2065,7 +2052,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, ListOfValues[I + 2], getSILType(EltTy, (SILValueCategory)ListOfValues[I + 1], Fn))); } - ResultVal = Builder.createStruct( + ResultInst = Builder.createStruct( Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), OpList); break; } @@ -2080,12 +2067,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, switch (OpCode) { default: llvm_unreachable("Out of sync with parent switch"); case SILInstructionKind::TupleElementAddrInst: - ResultVal = Builder.createTupleElementAddr( + ResultInst = Builder.createTupleElementAddr( Loc, getLocalValue(ValID, ST), TyID, getSILType(ResultTy, SILValueCategory::Address, Fn)); break; case SILInstructionKind::TupleExtractInst: - ResultVal = Builder.createTupleExtract( + ResultInst = Builder.createTupleExtract( Loc, getLocalValue(ValID, ST), TyID, getSILType(ResultTy, SILValueCategory::Object, Fn)); break; @@ -2105,7 +2092,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getLocalValue(ListOfValues[I], getSILType(EltTy, SILValueCategory::Object, Fn))); } - ResultVal = Builder.createTuple( + ResultInst = Builder.createTuple( Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), OpList); break; } @@ -2124,7 +2111,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILValue elementVal = getLocalValue(ListOfValues[i], elementType); elements.push_back(elementVal); } - ResultVal = Builder.createObject(Loc, ClassTy, elements, numBaseElements); + ResultInst = Builder.createObject(Loc, ClassTy, elements, numBaseElements); break; } case SILInstructionKind::BranchInst: { @@ -2135,8 +2122,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(ListOfValues[I]), (SILValueCategory)ListOfValues[I + 1], Fn))); - ResultVal = Builder.createBranch(Loc, getBBForReference(Fn, TyID), - Args); + ResultInst = Builder.createBranch(Loc, getBBForReference(Fn, TyID), Args); break; } case SILInstructionKind::CondBranchInst: { @@ -2166,9 +2152,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(ListOfValues[I]), (SILValueCategory)ListOfValues[I + 1], Fn))); - ResultVal = Builder.createCondBranch(Loc, Cond, - getBBForReference(Fn, ListOfValues[1]), TrueArgs, - getBBForReference(Fn, ListOfValues[2]), FalseArgs); + ResultInst = Builder.createCondBranch( + Loc, Cond, getBBForReference(Fn, ListOfValues[1]), TrueArgs, + getBBForReference(Fn, ListOfValues[2]), FalseArgs); break; } case SILInstructionKind::SwitchEnumInst: @@ -2191,10 +2177,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getBBForReference(Fn, ListOfValues[I+1])} ); } if (OpCode == SILInstructionKind::SwitchEnumInst) - ResultVal = Builder.createSwitchEnum(Loc, Cond, DefaultBB, CaseBBs); + ResultInst = Builder.createSwitchEnum(Loc, Cond, DefaultBB, CaseBBs); else - ResultVal = Builder.createSwitchEnumAddr(Loc, Cond, - DefaultBB, CaseBBs); + ResultInst = Builder.createSwitchEnumAddr(Loc, Cond, DefaultBB, CaseBBs); break; } case SILInstructionKind::SelectEnumInst: @@ -2223,11 +2208,11 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, Value}); } if (OpCode == SILInstructionKind::SelectEnumInst) - ResultVal = Builder.createSelectEnum(Loc, Cond, ResultTy, - DefaultVal, CaseVals); + ResultInst = + Builder.createSelectEnum(Loc, Cond, ResultTy, DefaultVal, CaseVals); else - ResultVal = Builder.createSelectEnumAddr(Loc, Cond, ResultTy, - DefaultVal, CaseVals); + ResultInst = Builder.createSelectEnumAddr(Loc, Cond, ResultTy, DefaultVal, + CaseVals); break; } case SILInstructionKind::SwitchValueInst: { @@ -2250,7 +2235,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto value = getLocalValue(ListOfValues[I], ResultTy); CaseBBs.push_back( {value, getBBForReference(Fn, ListOfValues[I+1])} ); } - ResultVal = Builder.createSwitchValue(Loc, Cond, DefaultBB, CaseBBs); + ResultInst = Builder.createSwitchValue(Loc, Cond, DefaultBB, CaseBBs); break; } case SILInstructionKind::SelectValueInst: { @@ -2278,8 +2263,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, CaseValuesAndResults.push_back({CaseValue, Result}); } - ResultVal = Builder.createSelectValue(Loc, Cond, ResultTy, - DefaultVal, CaseValuesAndResults); + ResultInst = Builder.createSelectValue(Loc, Cond, ResultTy, DefaultVal, + CaseValuesAndResults); break; } case SILInstructionKind::EnumInst: { @@ -2290,7 +2275,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, Operand = getLocalValue(ValID2, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)); - ResultVal = Builder.createEnum( + ResultInst = Builder.createEnum( Loc, Operand, cast(MF->getDecl(ValID)), getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); break; @@ -2302,9 +2287,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, (SILValueCategory) TyCategory, Fn); SILType ResultTy = OperandTy.getEnumElementType( Elt, SILMod, Builder.getTypeExpansionContext()); - ResultVal = Builder.createInitEnumDataAddr(Loc, - getLocalValue(ValID2, OperandTy), - Elt, ResultTy); + ResultInst = Builder.createInitEnumDataAddr( + Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } case SILInstructionKind::UncheckedEnumDataInst: { @@ -2314,9 +2298,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILType ResultTy = OperandTy.getEnumElementType( Elt, SILMod, Builder.getTypeExpansionContext()); - ResultVal = Builder.createUncheckedEnumData(Loc, - getLocalValue(ValID2, OperandTy), - Elt, ResultTy); + ResultInst = Builder.createUncheckedEnumData( + Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } case SILInstructionKind::UncheckedTakeEnumDataAddrInst: { @@ -2326,16 +2309,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILType ResultTy = OperandTy.getEnumElementType( Elt, SILMod, Builder.getTypeExpansionContext()); - ResultVal = Builder.createUncheckedTakeEnumDataAddr(Loc, - getLocalValue(ValID2, OperandTy), - Elt, ResultTy); + ResultInst = Builder.createUncheckedTakeEnumDataAddr( + Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } case SILInstructionKind::InjectEnumAddrInst: { // Use SILOneValueOneOperandLayout. EnumElementDecl *Elt = cast(MF->getDecl(ValID)); auto Ty = MF->getType(TyID); - ResultVal = Builder.createInjectEnumAddr( + ResultInst = Builder.createInjectEnumAddr( Loc, getLocalValue(ValID2, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), Elt); @@ -2349,15 +2331,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(Ty, (SILValueCategory)TyCategory, Fn)); auto ResultTy = Val->getType().getFieldType( Field, SILMod, Builder.getTypeExpansionContext()); - ResultVal = Builder.createRefElementAddr(Loc, Val, Field, - ResultTy, /*Immutable*/ Attr & 0x1); + ResultInst = Builder.createRefElementAddr(Loc, Val, Field, ResultTy, + /*Immutable*/ Attr & 0x1); break; } case SILInstructionKind::RefTailAddrInst: { assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); assert((SILValueCategory)TyCategory == SILValueCategory::Address); - ResultVal = Builder.createRefTailAddr( + ResultInst = Builder.createRefTailAddr( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), @@ -2385,24 +2367,24 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, switch (OpCode) { default: llvm_unreachable("Out of sync with parent switch"); case SILInstructionKind::ClassMethodInst: - ResultVal = Builder.createClassMethod(Loc, - getLocalValue(ListOfValues[NextValueIndex], operandTy), - DRef, Ty); + ResultInst = Builder.createClassMethod( + Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, + Ty); break; case SILInstructionKind::SuperMethodInst: - ResultVal = Builder.createSuperMethod(Loc, - getLocalValue(ListOfValues[NextValueIndex], operandTy), - DRef, Ty); + ResultInst = Builder.createSuperMethod( + Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, + Ty); break; case SILInstructionKind::ObjCMethodInst: - ResultVal = Builder.createObjCMethod(Loc, - getLocalValue(ListOfValues[NextValueIndex], operandTy), - DRef, Ty); + ResultInst = Builder.createObjCMethod( + Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, + Ty); break; case SILInstructionKind::ObjCSuperMethodInst: - ResultVal = Builder.createObjCSuperMethod(Loc, - getLocalValue(ListOfValues[NextValueIndex], operandTy), - DRef, Ty); + ResultInst = Builder.createObjCSuperMethod( + Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, + Ty); break; } break; @@ -2426,8 +2408,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, if (ValID3) ExistentialOperand = getLocalValue(ValID3, ExistentialOperandTy); } - ResultVal = Builder.createWitnessMethod( - Loc, Ty, Conformance, DRef, OperandTy); + ResultInst = + Builder.createWitnessMethod(Loc, Ty, Conformance, DRef, OperandTy); break; } case SILInstructionKind::DynamicMethodBranchInst: { @@ -2437,7 +2419,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex); assert(ListOfValues.size() == NextValueIndex + 2 && "Wrong number of entries for DynamicMethodBranchInst"); - ResultVal = Builder.createDynamicMethodBranch( + ResultInst = Builder.createDynamicMethodBranch( Loc, getLocalValue( ListOfValues[0], @@ -2460,9 +2442,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto *successBB = getBBForReference(Fn, ListOfValues[5]); auto *failureBB = getBBForReference(Fn, ListOfValues[6]); - ResultVal = Builder.createCheckedCastBranch( - Loc, isExact, op, targetLoweredType, targetFormalType, - successBB, failureBB); + ResultInst = + Builder.createCheckedCastBranch(Loc, isExact, op, targetLoweredType, + targetFormalType, successBB, failureBB); break; } case SILInstructionKind::CheckedCastValueBranchInst: { @@ -2477,9 +2459,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto *successBB = getBBForReference(Fn, ListOfValues[5]); auto *failureBB = getBBForReference(Fn, ListOfValues[6]); - ResultVal = Builder.createCheckedCastValueBranch( - Loc, op, srcFormalType, targetLoweredType, targetFormalType, - successBB, failureBB); + ResultInst = Builder.createCheckedCastValueBranch( + Loc, op, srcFormalType, targetLoweredType, targetFormalType, successBB, + failureBB); break; } case SILInstructionKind::UnconditionalCheckedCastValueInst: { @@ -2491,9 +2473,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILType targetLoweredType = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); CanType targetFormalType = MF->getType(ListOfValues[4])->getCanonicalType(); - ResultVal = Builder.createUnconditionalCheckedCastValue(Loc, src, srcFormalType, - targetLoweredType, - targetFormalType); + ResultInst = Builder.createUnconditionalCheckedCastValue( + Loc, src, srcFormalType, targetLoweredType, targetFormalType); break; } case SILInstructionKind::UnconditionalCheckedCastAddrInst: { @@ -2508,8 +2489,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILValue dest = getLocalValue(ListOfValues[5], targetLoweredType); - ResultVal = Builder.createUnconditionalCheckedCastAddr(Loc, src, srcFormalType, - dest, targetFormalType); + ResultInst = Builder.createUnconditionalCheckedCastAddr( + Loc, src, srcFormalType, dest, targetFormalType); break; } case SILInstructionKind::CheckedCastAddrBranchInst: { @@ -2528,10 +2509,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto *successBB = getBBForReference(Fn, ListOfValues[7]); auto *failureBB = getBBForReference(Fn, ListOfValues[8]); - ResultVal = Builder.createCheckedCastAddrBranch(Loc, consumption, - src, srcFormalType, - dest, targetFormalType, - successBB, failureBB); + ResultInst = Builder.createCheckedCastAddrBranch( + Loc, consumption, src, srcFormalType, dest, targetFormalType, successBB, + failureBB); break; } case SILInstructionKind::UncheckedRefCastAddrInst: { @@ -2546,8 +2526,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILValue dest = getLocalValue(ListOfValues[5], destAddrTy); - ResultVal = Builder.createUncheckedRefCastAddr(Loc, src, sourceType, - dest, targetType); + ResultInst = Builder.createUncheckedRefCastAddr(Loc, src, sourceType, dest, + targetType); break; } case SILInstructionKind::InitBlockStorageHeaderInst: { @@ -2568,16 +2548,16 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto SubMap = MF->getSubstitutionMap(ListOfValues[4]); - ResultVal = Builder.createInitBlockStorageHeader(Loc, storage, invoke, - blockTy, SubMap); + ResultInst = Builder.createInitBlockStorageHeader(Loc, storage, invoke, + blockTy, SubMap); break; } case SILInstructionKind::UnreachableInst: { - ResultVal = Builder.createUnreachable(Loc); + ResultInst = Builder.createUnreachable(Loc); break; } case SILInstructionKind::UnwindInst: { - ResultVal = Builder.createUnwind(Loc); + ResultInst = Builder.createUnwind(Loc); break; } case SILInstructionKind::YieldInst: { @@ -2594,7 +2574,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, ListOfValues[I + 2], getSILType(valueTy, valueCategory, Fn))); } - ResultVal = Builder.createYield(Loc, yieldedValues, resumeBB, unwindBB); + ResultInst = Builder.createYield(Loc, yieldedValues, resumeBB, unwindBB); break; } case SILInstructionKind::KeyPathInst: { @@ -2645,8 +2625,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto opCat = (SILValueCategory)ListOfValues[nextValue++]; operands.push_back(getLocalValue(opValue, getSILType(opTy, opCat, Fn))); } - - ResultVal = Builder.createKeyPath(Loc, pattern, subMap, operands, kpTy); + + ResultInst = Builder.createKeyPath(Loc, pattern, subMap, operands, kpTy); break; } case SILInstructionKind::DifferentiableFunctionInst: { @@ -2679,7 +2659,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, Optional> derivativeFunctions = None; if (hasDerivativeFunctions) derivativeFunctions = std::make_pair(operands[1], operands[2]); - ResultVal = Builder.createDifferentiableFunction( + ResultInst = Builder.createDifferentiableFunction( Loc, paramIndices, resultIndices, operands[0], derivativeFunctions); break; } @@ -2704,8 +2684,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, Optional transposeFunction = None; if (hasLinearFunction) transposeFunction = operands[1]; - ResultVal = Builder.createLinearFunction( - Loc, paramIndices, operands[0], transposeFunction); + ResultInst = Builder.createLinearFunction(Loc, paramIndices, operands[0], + transposeFunction); break; } case SILInstructionKind::DifferentiableFunctionExtractInst: { @@ -2716,7 +2696,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, Optional explicitExtracteeType = None; if (Attr2) explicitExtracteeType = silTy; - ResultVal = Builder.createDifferentiableFunctionExtract( + ResultInst = Builder.createDifferentiableFunctionExtract( Loc, extractee, val, explicitExtracteeType); break; } @@ -2725,7 +2705,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto silTy = getSILType(astTy, SILValueCategory::Object, Fn); auto val = getLocalValue(ValID, silTy); LinearDifferentiableFunctionTypeComponent extractee(Attr); - ResultVal = Builder.createLinearFunctionExtract(Loc, extractee, val); + ResultInst = Builder.createLinearFunctionExtract(Loc, extractee, val); break; } case SILInstructionKind::DifferentiabilityWitnessFunctionInst: { @@ -2737,13 +2717,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto astTy = MF->getType(TyID); if (TyID) explicitFnTy = getSILType(astTy, SILValueCategory::Object, Fn); - ResultVal = Builder.createDifferentiabilityWitnessFunction( + ResultInst = Builder.createDifferentiabilityWitnessFunction( Loc, witnessKind, witness, explicitFnTy); break; } } - for (auto result : ResultVal->getResults()) { + for (auto result : ResultInst->getResults()) { LastValueID = LastValueID + 1; setLocalValue(result, LastValueID); } @@ -2829,18 +2809,17 @@ bool SILDeserializer::hasSILFunction(StringRef Name, IdentifierID replacedFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), + isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass, - funcTyID, replacedFunctionID, genericSigID, + isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), + isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, clangOwnerID, SemanticsIDs); auto linkage = fromStableSILLinkage(rawLinkage); if (!linkage) { diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index c0d4b8ce4b931..7f0588858152e 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -19,149 +19,81 @@ #include "swift/Basic/FileTypes.h" #include "swift/Frontend/ModuleInterfaceLoader.h" #include "swift/Serialization/SerializedModuleLoader.h" +#include "swift/Serialization/ModuleDependencyScanner.h" #include "swift/Subsystems.h" using namespace swift; using llvm::ErrorOr; -namespace { -/// A module "loader" that looks for .swiftinterface and .swiftmodule files -/// for the purpose of determining dependencies, but does not attempt to -/// load the module files. -class ModuleDependencyScanner : public SerializedModuleLoaderBase { - /// The module we're scanning dependencies of. - Identifier moduleName; - - /// Scan the given interface file to determine dependencies. - ErrorOr scanInterfaceFile( - Twine moduleInterfacePath); - - InterfaceSubContextDelegate &astDelegate; -public: - Optional dependencies; - - /// Describes the kind of dependencies this scanner is able to identify - ModuleDependenciesKind dependencyKind; - - ModuleDependencyScanner( - ASTContext &ctx, ModuleLoadingMode LoadMode, Identifier moduleName, - InterfaceSubContextDelegate &astDelegate, - ModuleDependenciesKind dependencyKind = ModuleDependenciesKind::Swift) - : SerializedModuleLoaderBase(ctx, nullptr, LoadMode, - /*IgnoreSwiftSourceInfoFile=*/true), - moduleName(moduleName), astDelegate(astDelegate), - dependencyKind(dependencyKind) {} - - virtual std::error_code findModuleFilesInDirectory( - AccessPathElem ModuleID, - const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override { - using namespace llvm::sys; - - auto &fs = *Ctx.SourceMgr.getFileSystem(); - - auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile); - auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile); - - if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) { - if (fs.exists(ModPath)) { - // The module file will be loaded directly. - auto dependencies = scanModuleFile(ModPath); - if (dependencies) { - this->dependencies = std::move(dependencies.get()); - return std::error_code(); - } - return dependencies.getError(); - } else { - return std::make_error_code(std::errc::no_such_file_or_directory); +std::error_code ModuleDependencyScanner::findModuleFilesInDirectory( + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { + using namespace llvm::sys; + + auto &fs = *Ctx.SourceMgr.getFileSystem(); + + auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile); + auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile); + + if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) { + if (fs.exists(ModPath)) { + // The module file will be loaded directly. + auto dependencies = scanModuleFile(ModPath); + if (dependencies) { + this->dependencies = std::move(dependencies.get()); + return std::error_code(); } + return dependencies.getError(); + } else { + return std::make_error_code(std::errc::no_such_file_or_directory); } - assert(fs.exists(InPath)); - auto dependencies = scanInterfaceFile(InPath); - if (dependencies) { - this->dependencies = std::move(dependencies.get()); - return std::error_code(); - } - - return dependencies.getError(); } - - virtual void collectVisibleTopLevelModuleNames( - SmallVectorImpl &names) const override { - llvm_unreachable("Not used"); + assert(fs.exists(InPath)); + // Use the private interface file if exits. + auto PrivateInPath = + BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile); + if (fs.exists(PrivateInPath)) { + InPath = PrivateInPath; } -}; - -/// A ModuleLoader that loads placeholder dependency module stubs specified in -/// -placeholder-dependency-module-map-file -/// This loader is used only in dependency scanning to inform the scanner that a -/// set of modules constitute placeholder dependencies that are not visible to the -/// scanner but will nevertheless be provided by the scanner's clients. -/// This "loader" will not attempt to load any module files. -class PlaceholderSwiftModuleScanner : public ModuleDependencyScanner { - /// Scan the given placeholder module map - void parsePlaceholderModuleMap(StringRef fileName) { - ExplicitModuleMapParser parser(Allocator); - auto result = - parser.parseSwiftExplicitModuleMap(fileName, PlaceholderDependencyModuleMap); - if (result == std::errc::invalid_argument) { - Ctx.Diags.diagnose(SourceLoc(), - diag::placeholder_dependency_module_map_corrupted, - fileName); - } - else if (result == std::errc::no_such_file_or_directory) { - Ctx.Diags.diagnose(SourceLoc(), - diag::placeholder_dependency_module_map_missing, - fileName); - } + auto dependencies = scanInterfaceFile(InPath, IsFramework); + if (dependencies) { + this->dependencies = std::move(dependencies.get()); + return std::error_code(); } - llvm::StringMap PlaceholderDependencyModuleMap; - llvm::BumpPtrAllocator Allocator; + return dependencies.getError(); +} -public: - PlaceholderSwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode, - Identifier moduleName, - StringRef PlaceholderDependencyModuleMap, - InterfaceSubContextDelegate &astDelegate) - : ModuleDependencyScanner(ctx, LoadMode, moduleName, astDelegate, - ModuleDependenciesKind::SwiftPlaceholder) { - // FIXME: Find a better place for this map to live, to avoid - // doing the parsing on every module. - if (!PlaceholderDependencyModuleMap.empty()) { - parsePlaceholderModuleMap(PlaceholderDependencyModuleMap); - } +std::error_code PlaceholderSwiftModuleScanner::findModuleFilesInDirectory( + AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { + StringRef moduleName = ModuleID.Item.str(); + auto it = PlaceholderDependencyModuleMap.find(moduleName); + // If no placeholder module stub path is given matches the name, return with an + // error code. + if (it == PlaceholderDependencyModuleMap.end()) { + return std::make_error_code(std::errc::not_supported); } - - std::error_code findModuleFilesInDirectory( - AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override { - StringRef moduleName = ModuleID.Item.str(); - auto it = PlaceholderDependencyModuleMap.find(moduleName); - // If no placeholder module stub path is given matches the name, return with an - // error code. - if (it == PlaceholderDependencyModuleMap.end()) { - return std::make_error_code(std::errc::not_supported); - } - auto &moduleInfo = it->getValue(); - assert(!moduleInfo.moduleBuffer && - "Placeholder dependency module stubs cannot have an associated buffer"); - - auto dependencies = ModuleDependencies::forPlaceholderSwiftModuleStub( - moduleInfo.modulePath, moduleInfo.moduleDocPath, - moduleInfo.moduleSourceInfoPath); - this->dependencies = std::move(dependencies); - return std::error_code{}; - } -}; -} // namespace + auto &moduleInfo = it->getValue(); + assert(!moduleInfo.moduleBuffer && + "Placeholder dependency module stubs cannot have an associated buffer"); + + auto dependencies = ModuleDependencies::forPlaceholderSwiftModuleStub( + moduleInfo.modulePath, moduleInfo.moduleDocPath, + moduleInfo.moduleSourceInfoPath); + this->dependencies = std::move(dependencies); + return std::error_code{}; +} static std::vector getCompiledCandidates(ASTContext &ctx, StringRef moduleName, @@ -172,7 +104,7 @@ static std::vector getCompiledCandidates(ASTContext &ctx, } ErrorOr ModuleDependencyScanner::scanInterfaceFile( - Twine moduleInterfacePath) { + Twine moduleInterfacePath, bool isFramework) { // Create a module filename. // FIXME: Query the module interface loader to determine an appropriate // name for the module, which includes an appropriate hash. @@ -180,8 +112,8 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( llvm::SmallString<32> modulePath = moduleName.str(); llvm::sys::path::replace_extension(modulePath, newExt); Optional Result; - std::error_code code; - auto hasError = astDelegate.runInSubContext(moduleName.str(), + std::error_code code = + astDelegate.runInSubContext(moduleName.str(), moduleInterfacePath.str(), StringRef(), SourceLoc(), @@ -196,13 +128,13 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( compiledCandidates, Args, PCMArgs, - Hash); + Hash, + isFramework); // Open the interface file. auto &fs = *Ctx.SourceMgr.getFileSystem(); auto interfaceBuf = fs.getBufferForFile(moduleInterfacePath); if (!interfaceBuf) { - code = interfaceBuf.getError(); - return true; + return interfaceBuf.getError(); } // Create a source file. @@ -221,10 +153,10 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( for (auto name: imInfo.ModuleNames) { Result->addModuleDependency(name.str(), &alreadyAddedModules); } - return false; + return std::error_code(); }); - if (hasError) { + if (code) { return code; } return *Result; @@ -244,13 +176,19 @@ Optional SerializedModuleLoaderBase::getModuleDependencies( auto moduleId = Ctx.getIdentifier(moduleName); // Instantiate dependency scanning "loaders". SmallVector, 2> scanners; - scanners.push_back(std::make_unique( - Ctx, LoadMode, moduleId, delegate)); + // Placeholder dependencies must be resolved first, to prevent the ModuleDependencyScanner + // from first discovering artifacts of a previous build. Such artifacts are captured + // as compiledModuleCandidates in the dependency graph of the placeholder dependency module + // itself. scanners.push_back(std::make_unique( Ctx, LoadMode, moduleId, Ctx.SearchPathOpts.PlaceholderDependencyModuleMap, delegate)); + scanners.push_back(std::make_unique( + Ctx, LoadMode, moduleId, delegate)); // Check whether there is a module with this name that we can import. + assert(isa(scanners[0].get()) && + "Expected PlaceholderSwiftModuleScanner as the first dependency scanner loader."); for (auto &scanner : scanners) { if (scanner->canImportModule({moduleId, SourceLoc()})) { // Record the dependencies. diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index 7b17160859a72..80b4b9d57e857 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -349,17 +349,14 @@ ModuleFile::getModuleName(ASTContext &Ctx, StringRef modulePath, llvm::MemoryBuffer::getMemBuffer(llvm::MemoryBufferRef(*moduleBuf.get()), /*RequiresNullTerminator=*/false); std::shared_ptr loadedModuleFile; - ExtendedValidationInfo ExtInfo; bool isFramework = false; serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load(modulePath.str(), std::move(newBuf), nullptr, nullptr, - /*isFramework*/isFramework, loadedModuleFile, - &ExtInfo); - - Name = loadedModuleFile->Name; + /*isFramework*/isFramework, loadedModuleFile); + Name = loadedModuleFile->Name.str(); return std::move(moduleBuf.get()); } diff --git a/lib/Serialization/ModuleFile.h b/lib/Serialization/ModuleFile.h index 8a0c296a17a0c..413bd6a7d574a 100644 --- a/lib/Serialization/ModuleFile.h +++ b/lib/Serialization/ModuleFile.h @@ -438,11 +438,31 @@ class ModuleFile return Core->CompatibilityVersion; } + /// Whether this module is compiled with `-enable-private-imports`. + bool arePrivateImportsEnabled() const { + return Core->Bits.ArePrivateImportsEnabled; + } + /// Is this module file actually a .sib file? .sib files are serialized SIL at /// arbitrary granularity and arbitrary stage; unlike serialized Swift /// modules, which are assumed to contain canonical SIL for an entire module. bool isSIB() const { - return Core->IsSIB; + return Core->Bits.IsSIB; + } + + /// Whether this module file is compiled with '-enable-testing'. + bool isTestable() const { + return Core->Bits.IsTestable; + } + + /// Whether the module is resilient. ('-enable-library-evolution') + ResilienceStrategy getResilienceStrategy() const { + return ResilienceStrategy(Core->Bits.ResilienceStrategy); + } + + /// Whether this module is compiled with implicit dynamic. + bool isImplicitDynamicEnabled() const { + return Core->Bits.IsImplicitDynamicEnabled; } /// Associates this module file with the AST node representing it. diff --git a/lib/Serialization/ModuleFileCoreTableInfo.h b/lib/Serialization/ModuleFileCoreTableInfo.h index 3030d6a5f9770..63d69439e8c42 100644 --- a/lib/Serialization/ModuleFileCoreTableInfo.h +++ b/lib/Serialization/ModuleFileCoreTableInfo.h @@ -455,7 +455,7 @@ class ModuleFileSharedCore::DerivativeFunctionConfigTableInfo { while (data < limit) { DeclID genSigId = endian::readNext(data); int32_t nameLength = endian::readNext(data); - StringRef mangledName(reinterpret_cast(data), nameLength); + std::string mangledName(reinterpret_cast(data), nameLength); data += nameLength; result.push_back({mangledName, genSigId}); } diff --git a/lib/Serialization/ModuleFileSharedCore.cpp b/lib/Serialization/ModuleFileSharedCore.cpp index aa0adae1f635d..a2032f6715d0b 100644 --- a/lib/Serialization/ModuleFileSharedCore.cpp +++ b/lib/Serialization/ModuleFileSharedCore.cpp @@ -1087,8 +1087,7 @@ ModuleFileSharedCore::ModuleFileSharedCore( std::unique_ptr moduleInputBuffer, std::unique_ptr moduleDocInputBuffer, std::unique_ptr moduleSourceInfoInputBuffer, - bool isFramework, serialization::ValidationInfo &info, - serialization::ExtendedValidationInfo *extInfo) + bool isFramework, serialization::ValidationInfo &info) : ModuleInputBuffer(std::move(moduleInputBuffer)), ModuleDocInputBuffer(std::move(moduleDocInputBuffer)), ModuleSourceInfoInputBuffer(std::move(moduleSourceInfoInputBuffer)) { @@ -1134,10 +1133,11 @@ ModuleFileSharedCore::ModuleFileSharedCore( return; } + ExtendedValidationInfo extInfo; info = validateControlBlock(cursor, scratch, {SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR}, - extInfo); + &extInfo); if (info.status != Status::Valid) { error(info.status); return; @@ -1145,7 +1145,11 @@ ModuleFileSharedCore::ModuleFileSharedCore( Name = info.name; TargetTriple = info.targetTriple; CompatibilityVersion = info.compatibilityVersion; - IsSIB = extInfo->isSIB(); + Bits.ArePrivateImportsEnabled = extInfo.arePrivateImportsEnabled(); + Bits.IsSIB = extInfo.isSIB(); + Bits.IsTestable = extInfo.isTestable(); + Bits.ResilienceStrategy = unsigned(extInfo.getResilienceStrategy()); + Bits.IsImplicitDynamicEnabled = extInfo.isImplicitDynamicEnabled(); MiscVersion = info.miscVersion; hasValidControlBlock = true; diff --git a/lib/Serialization/ModuleFileSharedCore.h b/lib/Serialization/ModuleFileSharedCore.h index f7be1d18b9746..2caa4a3920487 100644 --- a/lib/Serialization/ModuleFileSharedCore.h +++ b/lib/Serialization/ModuleFileSharedCore.h @@ -69,11 +69,6 @@ class ModuleFileSharedCore { /// The data blob containing all of the module's identifiers. StringRef IdentifierData; - /// Is this module file actually a .sib file? .sib files are serialized SIL at - /// arbitrary granularity and arbitrary stage; unlike serialized Swift - /// modules, which are assumed to contain canonical SIL for an entire module. - bool IsSIB = false; - // Full blob from the misc. version field of the metadata block. This should // include the version string of the compiler that built the module. StringRef MiscVersion; @@ -307,6 +302,21 @@ class ModuleFileSharedCore { /// Whether an error has been detected setting up this module file. unsigned HasError : 1; + /// Whether this module is `-enable-private-imports`. + unsigned ArePrivateImportsEnabled : 1; + + /// Whether this module file is actually a .sib file. + unsigned IsSIB: 1; + + /// Whether this module file is compiled with '-enable-testing'. + unsigned IsTestable : 1; + + /// Discriminator for resilience strategy. + unsigned ResilienceStrategy : 2; + + /// Whether this module is compiled with implicit dynamic. + unsigned IsImplicitDynamicEnabled: 1; + // Explicitly pad out to the next word boundary. unsigned : 0; } Bits = {}; @@ -326,8 +336,7 @@ class ModuleFileSharedCore { ModuleFileSharedCore(std::unique_ptr moduleInputBuffer, std::unique_ptr moduleDocInputBuffer, std::unique_ptr moduleSourceInfoInputBuffer, - bool isFramework, serialization::ValidationInfo &info, - serialization::ExtendedValidationInfo *extInfo); + bool isFramework, serialization::ValidationInfo &info); /// Change the status of the current module. Status error(Status issue) { @@ -455,14 +464,17 @@ class ModuleFileSharedCore { std::unique_ptr moduleInputBuffer, std::unique_ptr moduleDocInputBuffer, std::unique_ptr moduleSourceInfoInputBuffer, - bool isFramework, std::shared_ptr &theModule, - serialization::ExtendedValidationInfo *extInfo = nullptr) { + bool isFramework, + std::shared_ptr &theModule) { serialization::ValidationInfo info; auto *core = new ModuleFileSharedCore( std::move(moduleInputBuffer), std::move(moduleDocInputBuffer), - std::move(moduleSourceInfoInputBuffer), isFramework, info, extInfo); - if (!moduleInterfacePath.empty()) - core->ModuleInterfacePath = moduleInterfacePath; + std::move(moduleSourceInfoInputBuffer), isFramework, info); + if (!moduleInterfacePath.empty()) { + ArrayRef path; + core->allocateBuffer(path, moduleInterfacePath); + core->ModuleInterfacePath = StringRef(path.data(), path.size()); + } theModule.reset(core); return info; } diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index b3a7a893f0932..a3e1f36a59277 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 568; // removed UTF16 +const uint16_t SWIFTMODULE_VERSION_MINOR = 576; // hasCReferences /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1049,6 +1049,7 @@ namespace decls_block { using SILFunctionTypeLayout = BCRecordLayout< SIL_FUNCTION_TYPE, + BCFixed<1>, // async? SILCoroutineKindField, // coroutine kind ParameterConventionField, // callee convention SILFunctionTypeRepresentationField, // representation @@ -1307,6 +1308,7 @@ namespace decls_block { AccessLevelField, // access level BCFixed<1>, // requires a new vtable slot DeclIDField, // opaque result type decl + BCFixed<1>, // isUserAccessible? BCArray // name components, // followed by TypeID dependencies // The record is trailed by: diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index dfa1ea155b886..696f06b0d82fa 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -277,10 +277,11 @@ namespace sil_block { BCFixed<2>, // serialized BCFixed<2>, // thunks: signature optimized/reabstraction BCFixed<1>, // without_actually_escaping - BCFixed<1>, // async BCFixed<3>, // specialPurpose BCFixed<2>, // inlineStrategy BCFixed<2>, // optimizationMode + BCFixed<2>, // classSubclassScope + BCFixed<1>, // hasCReferences BCFixed<3>, // side effect info. BCVBR<8>, // number of specialize attributes BCFixed<1>, // has qualified ownership diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index c17453abfcf41..6c5d3bf492457 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -46,6 +46,7 @@ #include "swift/Demangling/ManglingMacros.h" #include "swift/Serialization/SerializationOptions.h" #include "swift/Strings.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/RecordLayout.h" @@ -609,7 +610,8 @@ serialization::ClangTypeID Serializer::addClangTypeRef(const clang::Type *ty) { isSerializable = false; } if (!isSerializable) { - PrettyStackTraceClangType trace("staging a serialized reference to", ty); + PrettyStackTraceClangType trace(loader->getClangASTContext(), + "staging a serialized reference to", ty); llvm::report_fatal_error("Clang function type is not serializable"); } @@ -856,6 +858,8 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(sil_index_block, SIL_DEFAULT_WITNESS_TABLE_NAMES); BLOCK_RECORD(sil_index_block, SIL_DEFAULT_WITNESS_TABLE_OFFSETS); BLOCK_RECORD(sil_index_block, SIL_PROPERTY_OFFSETS); + BLOCK_RECORD(sil_index_block, SIL_DIFFERENTIABILITY_WITNESS_NAMES); + BLOCK_RECORD(sil_index_block, SIL_DIFFERENTIABILITY_WITNESS_OFFSETS); #undef BLOCK #undef BLOCK_RECORD @@ -2354,7 +2358,7 @@ class Serializer::DeclSerializer : public DeclVisitor { S.Out, S.ScratchRecord, abbrCode, (unsigned)SA->isExported(), (unsigned)SA->getSpecializationKind(), - S.addGenericSignatureRef(SA->getSpecializedSgnature())); + S.addGenericSignatureRef(SA->getSpecializedSignature())); return; } @@ -3310,9 +3314,9 @@ class Serializer::DeclSerializer : public DeclVisitor { ++numBackingProperties; arrayFields.push_back(S.addDeclRef(backingInfo.backingVar)); } - if (backingInfo.storageWrapperVar) { + if (backingInfo.projectionVar) { ++numBackingProperties; - arrayFields.push_back(S.addDeclRef(backingInfo.storageWrapperVar)); + arrayFields.push_back(S.addDeclRef(backingInfo.projectionVar)); } } for (Type dependency : collectDependenciesFromType(ty->getCanonicalType())) @@ -3435,6 +3439,7 @@ class Serializer::DeclSerializer : public DeclVisitor { rawAccessLevel, fn->needsNewVTableEntry(), S.addDeclRef(fn->getOpaqueResultTypeDecl()), + fn->isUserAccessible(), nameComponentsAndDependencies); writeGenericParams(fn->getGenericParams()); @@ -3922,6 +3927,10 @@ class Serializer::TypeSerializer : public TypeVisitor { llvm_unreachable("should not serialize an invalid type"); } + void visitHoleType(const HoleType *) { + llvm_unreachable("should not serialize an invalid type"); + } + void visitModuleType(const ModuleType *) { llvm_unreachable("modules are currently not first-class values"); } @@ -4230,7 +4239,7 @@ class Serializer::TypeSerializer : public TypeVisitor { unsigned abbrCode = S.DeclTypeAbbrCodes[SILFunctionTypeLayout::Code]; SILFunctionTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, - stableCoroutineKind, stableCalleeConvention, + fnTy->isAsync(), stableCoroutineKind, stableCalleeConvention, stableRepresentation, fnTy->isPseudogeneric(), fnTy->isNoEscape(), stableDiffKind, fnTy->hasErrorResult(), fnTy->getParameters().size(), fnTy->getNumYields(), fnTy->getNumResults(), @@ -4404,7 +4413,8 @@ class ClangToSwiftBasicWriter : void Serializer::writeASTBlockEntity(const clang::Type *ty) { using namespace decls_block; - PrettyStackTraceClangType traceRAII("serializing clang type", ty); + auto &ctx = getASTContext().getClangModuleLoader()->getClangASTContext(); + PrettyStackTraceClangType traceRAII(ctx, "serializing clang type", ty); assert(ClangTypesToSerialize.hasRef(ty)); // Serialize the type as an opaque sequence of data. @@ -5152,7 +5162,7 @@ void Serializer::writeAST(ModuleOrSourceFile DC) { DerivativeFunctionConfigTable derivativeConfigs; for (auto entry : uniquedDerivativeConfigs) { for (auto config : entry.second) { - auto paramIndices = config.first.str(); + std::string paramIndices = config.first.str().str(); auto genSigID = addGenericSignatureRef(config.second); derivativeConfigs[entry.first].push_back({paramIndices, genSigID}); } diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 00e9443213ea0..7c81a0c7bf579 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -248,6 +248,12 @@ namespace { void writeSILBlock(const SILModule *SILMod); void writeIndexTables(); + void writeNoOperandLayout(const SILInstruction *I) { + unsigned abbrCode = SILAbbrCodes[SILInstNoOperandLayout::Code]; + SILInstNoOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, + (unsigned)I->getKind()); + } + void writeConversionLikeInstruction(const SingleValueInstruction *I, unsigned attrs); void writeOneTypeLayout(SILInstructionKind valueKind, @@ -433,13 +439,13 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage), (unsigned)F.isTransparent(), (unsigned)F.isSerialized(), (unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(), - (unsigned)F.isAsync(), (unsigned)F.getSpecialPurpose(), - (unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(), - (unsigned)F.getEffectsKind(), (unsigned)numSpecAttrs, - (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), - LIST_VER_TUPLE_PIECES(available), (unsigned)F.isDynamicallyReplaceable(), - (unsigned)F.isExactSelfClass(), FnID, replacedFunctionID, genericSigID, - clangNodeOwnerID, SemanticsIDs); + (unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(), + (unsigned)F.getOptimizationMode(), (unsigned)F.getClassSubclassScope(), + (unsigned)F.hasCReferences(), (unsigned)F.getEffectsKind(), + (unsigned)numSpecAttrs, (unsigned)F.hasOwnership(), + F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available), + (unsigned)F.isDynamicallyReplaceable(), (unsigned)F.isExactSelfClass(), + FnID, replacedFunctionID, genericSigID, clangNodeOwnerID, SemanticsIDs); if (NoBody) return; @@ -763,9 +769,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { case SILInstructionKind::UnwindInst: case SILInstructionKind::UnreachableInst: { - unsigned abbrCode = SILAbbrCodes[SILInstNoOperandLayout::Code]; - SILInstNoOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, - (unsigned)SI.getKind()); + writeNoOperandLayout(&SI); break; } case SILInstructionKind::AllocExistentialBoxInst: @@ -2240,8 +2244,8 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { } case SILInstructionKind::LinearFunctionExtractInst: { auto *lfei = cast(&SI); - auto operandRef = addValueRef(lfei->getFunctionOperand()); - auto operandType = lfei->getFunctionOperand()->getType(); + auto operandRef = addValueRef(lfei->getOperand()); + auto operandType = lfei->getOperand()->getType(); auto operandTypeRef = S.addTypeRef(operandType.getASTType()); auto rawExtractee = (unsigned)lfei->getExtractee(); SILInstLinearFunctionExtractLayout::emitRecord(Out, ScratchRecord, @@ -2345,6 +2349,11 @@ void SILSerializer::writeIndexTables() { DefaultWitnessTableOffset); } + if (!PropertyOffset.empty()) { + Offset.emit(ScratchRecord, sil_index_block::SIL_PROPERTY_OFFSETS, + PropertyOffset); + } + if (!DifferentiabilityWitnessList.empty()) { writeIndexTable(S, List, sil_index_block::SIL_DIFFERENTIABILITY_WITNESS_NAMES, @@ -2354,11 +2363,6 @@ void SILSerializer::writeIndexTables() { DifferentiabilityWitnessOffset); } - if (!PropertyOffset.empty()) { - Offset.emit(ScratchRecord, sil_index_block::SIL_PROPERTY_OFFSETS, - PropertyOffset); - } - } void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) { diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 77d0a0a2154a0..33c84e84cdbf4 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -22,13 +22,14 @@ #include "swift/Basic/STLExtras.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Version.h" + #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" -#include "llvm/Support/Debug.h" #include using namespace swift; @@ -386,17 +387,15 @@ llvm::ErrorOr SerializedModuleLoaderBase::scanModuleFile( // Load the module file without validation. std::shared_ptr loadedModuleFile; bool isFramework = false; - serialization::ExtendedValidationInfo extInfo; serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load(modulePath.str(), std::move(moduleBuf.get()), nullptr, nullptr, - isFramework, loadedModuleFile, - &extInfo); + isFramework, loadedModuleFile); // Map the set of dependencies over to the "module dependencies". - auto dependencies = ModuleDependencies::forSwiftModule(modulePath.str()); + auto dependencies = ModuleDependencies::forSwiftModule(modulePath.str(), isFramework); llvm::StringSet<> addedModuleNames; for (const auto &dependency : loadedModuleFile->getDependencies()) { // FIXME: Record header dependency? @@ -422,7 +421,8 @@ std::error_code ImplicitSerializedModuleLoader::findModuleFilesInDirectory( SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) { + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { assert(((ModuleBuffer && ModuleDocBuffer) || (!ModuleBuffer && !ModuleDocBuffer)) && "Module and Module Doc buffer must both be initialized or NULL"); @@ -538,7 +538,7 @@ SerializedModuleLoaderBase::findModule(AccessPathElem moduleID, /// Returns true if a target-specific module file was found, false if an error /// was diagnosed, or None if neither one happened and the search should /// continue. - auto findTargetSpecificModuleFiles = [&]() -> Optional { + auto findTargetSpecificModuleFiles = [&](bool IsFramework) -> Optional { Optional firstAbsoluteBaseName; for (const auto &targetSpecificBaseName : targetSpecificBaseNames) { @@ -552,7 +552,8 @@ SerializedModuleLoaderBase::findModule(AccessPathElem moduleID, absoluteBaseName, moduleInterfacePath, moduleBuffer, moduleDocBuffer, - moduleSourceInfoBuffer); + moduleSourceInfoBuffer, + IsFramework); if (!result) { return true; } else if (result == std::errc::not_supported) { @@ -603,13 +604,13 @@ SerializedModuleLoaderBase::findModule(AccessPathElem moduleID, if (checkTargetSpecificModule) // A .swiftmodule directory contains architecture-specific files. - return findTargetSpecificModuleFiles(); + return findTargetSpecificModuleFiles(isFramework); SerializedModuleBaseName absoluteBaseName{currPath, genericBaseName}; auto result = findModuleFilesInDirectory( moduleID, absoluteBaseName, moduleInterfacePath, - moduleBuffer, moduleDocBuffer, moduleSourceInfoBuffer); + moduleBuffer, moduleDocBuffer, moduleSourceInfoBuffer, isFramework); if (!result) return true; else if (result == std::errc::not_supported) @@ -628,7 +629,7 @@ SerializedModuleLoaderBase::findModule(AccessPathElem moduleID, // Frameworks always use architecture-specific files within a // .swiftmodule directory. llvm::sys::path::append(currPath, "Modules"); - return findTargetSpecificModuleFiles(); + return findTargetSpecificModuleFiles(isFramework); } } llvm_unreachable("covered switch"); @@ -680,7 +681,6 @@ FileUnit *SerializedModuleLoaderBase::loadAST( std::unique_ptr moduleSourceInfoInputBuffer, bool isFramework) { assert(moduleInputBuffer); - StringRef moduleBufferID = moduleInputBuffer->getBufferIdentifier(); StringRef moduleDocBufferID; if (moduleDocInputBuffer) @@ -693,7 +693,6 @@ FileUnit *SerializedModuleLoaderBase::loadAST( return nullptr; } - serialization::ExtendedValidationInfo extendedInfo; std::unique_ptr loadedModuleFile; std::shared_ptr loadedModuleFileCore; serialization::ValidationInfo loadInfo = @@ -701,20 +700,19 @@ FileUnit *SerializedModuleLoaderBase::loadAST( std::move(moduleInputBuffer), std::move(moduleDocInputBuffer), std::move(moduleSourceInfoInputBuffer), - isFramework, loadedModuleFileCore, - &extendedInfo); + isFramework, loadedModuleFileCore); if (loadInfo.status == serialization::Status::Valid) { loadedModuleFile = std::make_unique(std::move(loadedModuleFileCore)); - M.setResilienceStrategy(extendedInfo.getResilienceStrategy()); + M.setResilienceStrategy(loadedModuleFile->getResilienceStrategy()); // We've loaded the file. Now try to bring it into the AST. auto fileUnit = new (Ctx) SerializedASTFile(M, *loadedModuleFile); - if (extendedInfo.isTestable()) + if (loadedModuleFile->isTestable()) M.setTestingEnabled(); - if (extendedInfo.arePrivateImportsEnabled()) + if (loadedModuleFile->arePrivateImportsEnabled()) M.setPrivateImportsEnabled(); - if (extendedInfo.isImplicitDynamicEnabled()) + if (loadedModuleFile->isImplicitDynamicEnabled()) M.setImplicitDynamicEnabled(); auto diagLocOrInvalid = diagLoc.getValueOr(SourceLoc()); @@ -742,7 +740,7 @@ FileUnit *SerializedModuleLoaderBase::loadAST( if (diagLoc) serialization::diagnoseSerializedASTLoadFailure( - Ctx, *diagLoc, loadInfo, extendedInfo, moduleBufferID, + Ctx, *diagLoc, loadInfo, moduleBufferID, moduleDocBufferID, loadedModuleFile.get(), M.getName()); // Even though the module failed to load, it's possible its contents include @@ -759,7 +757,6 @@ FileUnit *SerializedModuleLoaderBase::loadAST( void swift::serialization::diagnoseSerializedASTLoadFailure( ASTContext &Ctx, SourceLoc diagLoc, const serialization::ValidationInfo &loadInfo, - const serialization::ExtendedValidationInfo &extendedInfo, StringRef moduleBufferID, StringRef moduleDocBufferID, ModuleFile *loadedModuleFile, Identifier ModuleName) { auto diagnoseDifferentLanguageVersion = [&](StringRef shortVersion) -> bool { @@ -989,11 +986,8 @@ SerializedModuleLoaderBase::loadModule(SourceLoc importLoc, Ctx.addLoadedModule(M); SWIFT_DEFER { M->setHasResolvedImports(); }; - StringRef moduleInterfacePathStr = - Ctx.AllocateCopy(moduleInterfacePath.str()); - auto *file = - loadAST(*M, moduleID.Loc, moduleInterfacePathStr, + loadAST(*M, moduleID.Loc, moduleInterfacePath, std::move(moduleInputBuffer), std::move(moduleDocInputBuffer), std::move(moduleSourceInfoInputBuffer), isFramework); if (file) { @@ -1081,7 +1075,8 @@ std::error_code MemoryBufferSerializedModuleLoader::findModuleFilesInDirectory( SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) { + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { // This is a soft error instead of an llvm_unreachable because this API is // primarily used by LLDB which makes it more likely that unwitting changes to // the Swift compiler accidentally break the contract. diff --git a/lib/SymbolGraphGen/DeclarationFragmentPrinter.cpp b/lib/SymbolGraphGen/DeclarationFragmentPrinter.cpp index 4ef5f70b5ab4b..be82f22395e37 100644 --- a/lib/SymbolGraphGen/DeclarationFragmentPrinter.cpp +++ b/lib/SymbolGraphGen/DeclarationFragmentPrinter.cpp @@ -138,7 +138,15 @@ void DeclarationFragmentPrinter::printTypeRef(Type T, const TypeDecl *RefTo, openFragment(FragmentKind::TypeIdentifier); printText(Name.str()); USR.clear(); - if (Name.str() != "Self") { + + auto ShouldLink = Name.str() != "Self"; + if (const auto *TD = T->getAnyNominal()) { + if (SG->isImplicitlyPrivate(TD)) { + ShouldLink = false; + } + } + + if (ShouldLink) { llvm::raw_svector_ostream OS(USR); ide::printDeclUSR(RefTo, OS); } diff --git a/lib/SymbolGraphGen/DeclarationFragmentPrinter.h b/lib/SymbolGraphGen/DeclarationFragmentPrinter.h index 580a37e2303ff..16e011669e062 100644 --- a/lib/SymbolGraphGen/DeclarationFragmentPrinter.h +++ b/lib/SymbolGraphGen/DeclarationFragmentPrinter.h @@ -59,6 +59,9 @@ class DeclarationFragmentPrinter : public ASTPrinter { Text, }; private: + /// The symbol graph for which a declaration is being printed. + const SymbolGraph *SG; + /// The output stream to print fragment objects to. llvm::json::OStream &OS; @@ -81,9 +84,11 @@ class DeclarationFragmentPrinter : public ASTPrinter { unsigned NumFragments; public: - DeclarationFragmentPrinter(llvm::json::OStream &OS, + DeclarationFragmentPrinter(const SymbolGraph *SG, + llvm::json::OStream &OS, Optional Key = None) - : OS(OS), + : SG(SG), + OS(OS), Kind(FragmentKind::None), NumFragments(0) { if (Key) { diff --git a/lib/SymbolGraphGen/SymbolGraph.cpp b/lib/SymbolGraphGen/SymbolGraph.cpp index 8ef75088237b8..cb2a2a1741504 100644 --- a/lib/SymbolGraphGen/SymbolGraph.cpp +++ b/lib/SymbolGraphGen/SymbolGraph.cpp @@ -558,7 +558,7 @@ void SymbolGraph::serializeDeclarationFragments(StringRef Key, const Symbol &S, llvm::json::OStream &OS) { - DeclarationFragmentPrinter Printer(OS, Key); + DeclarationFragmentPrinter Printer(this, OS, Key); auto Options = getDeclarationFragmentsPrintOptions(); if (S.getSynthesizedBaseType()) { Options.setBaseType(S.getSynthesizedBaseType()); @@ -570,7 +570,7 @@ void SymbolGraph::serializeNavigatorDeclarationFragments(StringRef Key, const Symbol &S, llvm::json::OStream &OS) { - DeclarationFragmentPrinter Printer(OS, Key); + DeclarationFragmentPrinter Printer(this, OS, Key); if (const auto *TD = dyn_cast(S.getSymbolDecl())) { Printer.printAbridgedType(TD, /*PrintKeyword=*/false); @@ -587,7 +587,7 @@ void SymbolGraph::serializeSubheadingDeclarationFragments(StringRef Key, const Symbol &S, llvm::json::OStream &OS) { - DeclarationFragmentPrinter Printer(OS, Key); + DeclarationFragmentPrinter Printer(this, OS, Key); if (const auto *TD = dyn_cast(S.getSymbolDecl())) { Printer.printAbridgedType(TD, /*PrintKeyword=*/true); @@ -603,7 +603,7 @@ SymbolGraph::serializeSubheadingDeclarationFragments(StringRef Key, void SymbolGraph::serializeDeclarationFragments(StringRef Key, Type T, llvm::json::OStream &OS) { - DeclarationFragmentPrinter Printer(OS, Key); + DeclarationFragmentPrinter Printer(this, OS, Key); T->print(Printer, getDeclarationFragmentsPrintOptions()); } diff --git a/lib/SymbolGraphGen/SymbolGraphASTWalker.h b/lib/SymbolGraphGen/SymbolGraphASTWalker.h index 9a1ebae5e4908..81c9db978468c 100644 --- a/lib/SymbolGraphGen/SymbolGraphASTWalker.h +++ b/lib/SymbolGraphGen/SymbolGraphASTWalker.h @@ -86,7 +86,7 @@ struct SymbolGraphASTWalker : public SourceEntityWalker { // MARK: - SourceEntityWalker - virtual bool walkToDeclPre(Decl *D, CharSourceRange Range); + virtual bool walkToDeclPre(Decl *D, CharSourceRange Range) override; }; } // end namespace symbolgraphgen diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index bb90f41674faa..623e3d02ffb3e 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -61,16 +61,15 @@ static bool isGlobalOrStaticVar(VarDecl *VD) { return VD->isStatic() || VD->getDeclContext()->isModuleScopeContext(); } -TBDGenVisitor::TBDGenVisitor(TBDGenDescriptor desc, +TBDGenVisitor::TBDGenVisitor(const TBDGenDescriptor &desc, SymbolCallbackFn symbolCallback) : TBDGenVisitor(desc.getTarget(), desc.getDataLayout(), desc.getParentModule(), desc.getOptions(), symbolCallback) {} -void TBDGenVisitor::addSymbolInternal(StringRef name, - llvm::MachO::SymbolKind kind, - bool isLinkerDirective) { - if (!isLinkerDirective && Opts.LinkerDirectivesOnly) +void TBDGenVisitor::addSymbolInternal(StringRef name, SymbolKind kind, + SymbolSource source) { + if (!source.isLinkerDirective() && Opts.LinkerDirectivesOnly) return; #ifndef NDEBUG @@ -81,7 +80,7 @@ void TBDGenVisitor::addSymbolInternal(StringRef name, } } #endif - SymbolCallback(name, kind); + SymbolCallback(name, kind, source); } static std::vector @@ -337,8 +336,8 @@ void TBDGenVisitor::addLinkerDirectiveSymbolsLdPrevious(StringRef name, OS << IntroVer->getMajor() << "." << getMinor(IntroVer->getMinor()) << "$"; OS << Ver.Version.getMajor() << "." << getMinor(Ver.Version.getMinor()) << "$"; OS << name << "$"; - addSymbolInternal(OS.str(), llvm::MachO::SymbolKind::GlobalSymbol, - /*LinkerDirective*/true); + addSymbolInternal(OS.str(), SymbolKind::GlobalSymbol, + SymbolSource::forLinkerDirective()); } } @@ -383,18 +382,19 @@ void TBDGenVisitor::addLinkerDirectiveSymbolsLdHide(StringRef name, llvm::SmallString<64> Buffer; llvm::raw_svector_ostream OS(Buffer); OS << "$ld$hide$os" << CurMaj << "." << CurMin << "$" << name; - addSymbolInternal(OS.str(), llvm::MachO::SymbolKind::GlobalSymbol, - /*LinkerDirective*/true); + addSymbolInternal(OS.str(), SymbolKind::GlobalSymbol, + SymbolSource::forLinkerDirective()); } } } -void TBDGenVisitor::addSymbol(StringRef name, SymbolKind kind) { +void TBDGenVisitor::addSymbol(StringRef name, SymbolSource source, + SymbolKind kind) { // The linker expects to see mangled symbol names in TBD files, so make sure // to mangle before inserting the symbol. SmallString<32> mangled; llvm::Mangler::getNameWithPrefix(mangled, name, DataLayout); - addSymbolInternal(mangled, kind); + addSymbolInternal(mangled, kind, source); if (previousInstallNameMap) { addLinkerDirectiveSymbolsLdPrevious(mangled, kind); } else { @@ -406,8 +406,10 @@ void TBDGenVisitor::addSymbol(SILDeclRef declRef) { auto linkage = effectiveLinkageForClassMember( declRef.getLinkage(ForDefinition), declRef.getSubclassScope()); - if (linkage == SILLinkage::Public) - addSymbol(declRef.mangle()); + if (Opts.PublicSymbolsOnly && linkage != SILLinkage::Public) + return; + + addSymbol(declRef.mangle(), SymbolSource::forSILDeclRef(declRef)); } void TBDGenVisitor::addSymbol(LinkEntity entity) { @@ -418,8 +420,10 @@ void TBDGenVisitor::addSymbol(LinkEntity entity) { llvm::GlobalValue::isExternalLinkage(linkage.getLinkage()) && linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility; - if (externallyVisible) - addSymbol(linkage.getName()); + if (Opts.PublicSymbolsOnly && !externallyVisible) + return; + + addSymbol(linkage.getName(), SymbolSource::forIRLinkEntity(entity)); } void TBDGenVisitor::addDispatchThunk(SILDeclRef declRef) { @@ -486,13 +490,21 @@ void TBDGenVisitor::addConformances(const IterableDeclContext *IDC) { auto addSymbolIfNecessary = [&](ValueDecl *requirementDecl, ValueDecl *witnessDecl) { auto witnessRef = SILDeclRef(witnessDecl); - if (conformanceIsFixed && - (isa(rootConformance) || - fixmeWitnessHasLinkageThatNeedsToBePublic(witnessRef))) { - Mangle::ASTMangler Mangler; - addSymbol( - Mangler.mangleWitnessThunk(rootConformance, requirementDecl)); + if (Opts.PublicSymbolsOnly) { + if (!conformanceIsFixed) + return; + + if (!isa(rootConformance) && + !fixmeWitnessHasLinkageThatNeedsToBePublic(witnessRef)) { + return; + } } + + Mangle::ASTMangler Mangler; + + // FIXME: We should have a SILDeclRef SymbolSource for this. + addSymbol(Mangler.mangleWitnessThunk(rootConformance, requirementDecl), + SymbolSource::forUnknown()); }; rootConformance->forEachValueWitness([&](ValueDecl *valueReq, @@ -523,11 +535,11 @@ void TBDGenVisitor::addAutoDiffLinearMapFunction(AbstractFunctionDecl *original, auto declRef = SILDeclRef(original).asForeign(requiresForeignEntryPoint(original)); - if (!declRef.isSerialized()) - return; - // Linear maps are public only when the original function is serialized. - if (!declRef.isSerialized()) + // Linear maps are public only when the original function is serialized. So + // if we're only including public symbols and it's not serialized, bail. + if (Opts.PublicSymbolsOnly && !declRef.isSerialized()) return; + // Differential functions are emitted only when forward-mode is enabled. if (kind == AutoDiffLinearMapKind::Differential && !ctx.LangOpts.EnableExperimentalForwardModeDifferentiation) @@ -542,7 +554,7 @@ void TBDGenVisitor::addAutoDiffLinearMapFunction(AbstractFunctionDecl *original, original->getGenericSignature(), config.derivativeGenericSignature)}; std::string linearMapName = mangler.mangleAutoDiffLinearMapHelper(declRef.mangle(), kind, silConfig); - addSymbol(linearMapName); + addSymbol(linearMapName, SymbolSource::forSILDeclRef(declRef)); } void TBDGenVisitor::addAutoDiffDerivativeFunction( @@ -571,7 +583,7 @@ void TBDGenVisitor::addDifferentiabilityWitness( auto originalLinkage = declRef.getLinkage(ForDefinition); if (foreign) originalLinkage = stripExternalFromLinkage(originalLinkage); - if (originalLinkage != SILLinkage::Public) + if (Opts.PublicSymbolsOnly && originalLinkage != SILLinkage::Public) return; auto *silParamIndices = autodiff::getLoweredParameterIndices( @@ -587,7 +599,7 @@ void TBDGenVisitor::addDifferentiabilityWitness( Mangle::ASTMangler mangler; auto mangledName = mangler.mangleSILDifferentiabilityWitnessKey(key); - addSymbol(mangledName); + addSymbol(mangledName, SymbolSource::forSILDeclRef(declRef)); } void TBDGenVisitor::addDerivativeConfiguration(AbstractFunctionDecl *original, @@ -629,7 +641,7 @@ static bool shouldUseAllocatorMangling(const AbstractFunctionDecl *afd) { void TBDGenVisitor::visitDefaultArguments(ValueDecl *VD, ParameterList *PL) { auto publicDefaultArgGenerators = SwiftModule->isTestingEnabled() || SwiftModule->arePrivateImportsEnabled(); - if (!publicDefaultArgGenerators) + if (Opts.PublicSymbolsOnly && !publicDefaultArgGenerators) return; // In Swift 3 (or under -enable-testing), default arguments (of public @@ -769,10 +781,12 @@ void TBDGenVisitor::visitVarDecl(VarDecl *VD) { // statically/globally stored variables have some special handling. if (VD->hasStorage() && isGlobalOrStaticVar(VD)) { - if (getDeclLinkage(VD) == FormalLinkage::PublicUnique) { + if (!Opts.PublicSymbolsOnly || + getDeclLinkage(VD) == FormalLinkage::PublicUnique) { // The actual variable has a symbol. + // FIXME: We ought to have a symbol source for this. Mangle::ASTMangler mangler; - addSymbol(mangler.mangleEntity(VD)); + addSymbol(mangler.mangleEntity(VD), SymbolSource::forUnknown()); } if (VD->isLazilyInitializedGlobal()) @@ -811,7 +825,8 @@ void TBDGenVisitor::visitNominalTypeDecl(NominalTypeDecl *NTD) { } void TBDGenVisitor::visitClassDecl(ClassDecl *CD) { - if (getDeclLinkage(CD) != FormalLinkage::PublicUnique) + if (Opts.PublicSymbolsOnly && + getDeclLinkage(CD) != FormalLinkage::PublicUnique) return; auto &ctxt = CD->getASTContext(); @@ -835,8 +850,10 @@ void TBDGenVisitor::visitClassDecl(ClassDecl *CD) { addSymbol(LinkEntity::forSwiftMetaclassStub(CD)); if (addObjCClass) { + // FIXME: We ought to have a symbol source for this. SmallString<128> buffer; - addSymbol(CD->getObjCRuntimeName(buffer), SymbolKind::ObjectiveCClass); + addSymbol(CD->getObjCRuntimeName(buffer), SymbolSource::forUnknown(), + SymbolKind::ObjectiveCClass); } } @@ -1048,8 +1065,10 @@ void TBDGenVisitor::visitEnumElementDecl(EnumElementDecl *EED) { void TBDGenVisitor::addFirstFileSymbols() { if (!Opts.ModuleLinkName.empty()) { + // FIXME: We ought to have a symbol source for this. SmallString<32> buf; - addSymbol(irgen::encodeForceLoadSymbolName(buf, Opts.ModuleLinkName)); + addSymbol(irgen::encodeForceLoadSymbolName(buf, Opts.ModuleLinkName), + SymbolSource::forUnknown()); } } @@ -1196,7 +1215,7 @@ TBDFile GenerateTBDRequest::evaluate(Evaluator &evaluator, } llvm::MachO::TargetList targets{target}; - auto addSymbol = [&](StringRef symbol, SymbolKind kind) { + auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source) { file.addSymbol(kind, symbol, targets); }; @@ -1209,7 +1228,7 @@ std::vector PublicSymbolsRequest::evaluate(Evaluator &evaluator, TBDGenDescriptor desc) const { std::vector symbols; - auto addSymbol = [&](StringRef symbol, SymbolKind kind) { + auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source) { if (kind == SymbolKind::GlobalSymbol) symbols.push_back(symbol.str()); }; @@ -1231,3 +1250,24 @@ void swift::writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os, llvm::cantFail(llvm::MachO::TextAPIWriter::writeToStream(os, file), "YAML writing should be error-free"); } + +SymbolSourceMap SymbolSourceMapRequest::evaluate(Evaluator &evaluator, + TBDGenDescriptor desc) const { + using Map = SymbolSourceMap::Storage; + Map symbolSources; + + auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source) { + symbolSources.insert({symbol, source}); + }; + + TBDGenVisitor visitor(desc, addSymbol); + visitor.visit(desc); + + // FIXME: Once the evaluator supports returning a reference to a cached value + // in storage, this won't be necessary. + auto &ctx = desc.getParentModule()->getASTContext(); + auto *memory = ctx.Allocate(); + *memory = std::move(symbolSources); + ctx.addCleanup([memory](){ memory->~Map(); }); + return SymbolSourceMap(memory); +} diff --git a/lib/TBDGen/TBDGenVisitor.h b/lib/TBDGen/TBDGenVisitor.h index 0f14e71476568..3c93e8d02db56 100644 --- a/lib/TBDGen/TBDGenVisitor.h +++ b/lib/TBDGen/TBDGenVisitor.h @@ -42,6 +42,7 @@ namespace swift { class TBDGenDescriptor; struct TBDGenOptions; +class SymbolSource; namespace tbdgen { @@ -72,7 +73,8 @@ class TBDGenVisitor : public ASTVisitor { const TBDGenOptions &Opts; using SymbolKind = llvm::MachO::SymbolKind; - using SymbolCallbackFn = llvm::function_ref; + using SymbolCallbackFn = + llvm::function_ref; SymbolCallbackFn SymbolCallback; @@ -90,11 +92,11 @@ class TBDGenVisitor : public ASTVisitor { std::unique_ptr> parsePreviousModuleInstallNameMap(); void addSymbolInternal(StringRef name, llvm::MachO::SymbolKind kind, - bool isLinkerDirective = false); + SymbolSource source); void addLinkerDirectiveSymbolsLdHide(StringRef name, llvm::MachO::SymbolKind kind); void addLinkerDirectiveSymbolsLdPrevious(StringRef name, llvm::MachO::SymbolKind kind); - void addSymbol(StringRef name, llvm::MachO::SymbolKind kind = - llvm::MachO::SymbolKind::GlobalSymbol); + void addSymbol(StringRef name, SymbolSource source, + SymbolKind kind = SymbolKind::GlobalSymbol); void addSymbol(SILDeclRef declRef); @@ -150,7 +152,7 @@ class TBDGenVisitor : public ASTVisitor { /// Create a new visitor using the target and layout information from a /// TBDGenDescriptor. - TBDGenVisitor(TBDGenDescriptor desc, SymbolCallbackFn symbolCallback); + TBDGenVisitor(const TBDGenDescriptor &desc, SymbolCallbackFn symbolCallback); ~TBDGenVisitor() { assert(DeclStack.empty()); } void addMainIfNecessary(FileUnit *file) { @@ -160,8 +162,9 @@ class TBDGenVisitor : public ASTVisitor { // // Make sure to only add the main symbol for the module that we're emitting // TBD for, and not for any statically linked libraries. + // FIXME: We should have a SymbolSource for main. if (file->hasEntryPoint() && file->getParentModule() == SwiftModule) - addSymbol("main"); + addSymbol("main", SymbolSource::forUnknown()); } /// Adds the global symbols associated with the first file. diff --git a/localization/CMakeLists.txt b/localization/CMakeLists.txt index 764b378f97b44..53c7e05e2a757 100644 --- a/localization/CMakeLists.txt +++ b/localization/CMakeLists.txt @@ -4,12 +4,17 @@ add_custom_command(TARGET diagnostic-database COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/diagnostics/ ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ COMMAND - $ + "${SWIFT_NATIVE_SWIFT_TOOLS_PATH}/swift-def-to-yaml-converter" + --output-directory ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ + COMMAND + "${SWIFT_NATIVE_SWIFT_TOOLS_PATH}/swift-serialize-diagnostics" --input-file-path ${CMAKE_BINARY_DIR}/share/swift/diagnostics/en.yaml --output-directory ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ ) add_dependencies(swift-frontend diagnostic-database) +add_dependencies(diagnostic-database swift-serialize-diagnostics) +add_dependencies(diagnostic-database swift-def-to-yaml-converter) swift_install_in_component( DIRECTORY ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ diff --git a/localization/diagnostics/.gitkeep b/localization/diagnostics/.gitkeep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml deleted file mode 100644 index 8c3be67b2c0db..0000000000000 --- a/localization/diagnostics/en.yaml +++ /dev/null @@ -1,11833 +0,0 @@ -#===--- en.yaml - Localized diagnostic messages for English ---*- YAML -*-===# -# -# This source file is part of the Swift.org open source project -# -# Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -# Licensed under Apache License v2.0 with Runtime Library Exception -# -# See https://swift.org/LICENSE.txt for license information -# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -# -#===----------------------------------------------------------------------===# -# -# This file defines the diagnostic messages for the English language. -# Each diagnostic is described in the following format: -# - id: -# msg: >- -# -# -#===----------------------------------------------------------------------===# - -- id: invalid_diagnostic - msg: >- - INTERNAL ERROR: this diagnostic should not be produced - -- id: not_implemented - msg: >- - INTERNAL ERROR: feature not implemented: %0 - -- id: error_opening_output - msg: >- - error opening '%0' for output: %1 - -- id: cannot_find_group_info_file - msg: >- - cannot find group info file at path: '%0' - -- id: cannot_parse_group_info_file - msg: >- - cannot parse group info file at path: '%0' - -- id: error_no_group_info - msg: >- - no group info found for file: '%0' - -- id: previous_decldef - msg: >- - previous definition of %0 is here - -- id: brace_stmt_suggest_do - msg: >- - did you mean to use a 'do' statement? - -- id: while_parsing_as_left_angle_bracket - msg: >- - while parsing this '<' as a type parameter bracket - -- id: remark_max_determinism_overriding - msg: >- - SWIFTC_MAXIMUM_DETERMINISM overriding %0 - -- id: super_not_in_class_method - msg: >- - 'super' cannot be used outside of class members - -- id: class_func_not_in_class - msg: >- - class methods are only allowed within classes; use 'static' to declare a - %select{static|requirement fulfilled by either a static or class}0 method - -- id: class_var_not_in_class - msg: >- - class properties are only allowed within classes; use 'static' to declare - a %select{static|requirement fulfilled by either a static or class}0 - property - -- id: class_subscript_not_in_class - msg: >- - class subscripts are only allowed within classes; use 'static' to declare - a %select{static|requirement fulfilled by either a static or class}0 - subscript - -- id: func_decl_without_brace - msg: >- - expected '{' in body of function declaration - -- id: convert_let_to_var - msg: >- - change 'let' to 'var' to make it mutable - -- id: note_typo_candidate - msg: >- - did you mean '%0'? - -- id: profile_read_error - msg: >- - failed to load profile data '%0': '%1' - -- id: protocol_extension_redundant_requirement - msg: >- - requirement of '%1' to '%2' is redundant in an extension of '%0' - -- id: attr_only_on_parameters - msg: >- - '%0' may only be used on parameters - -- id: function_type_no_parens - msg: >- - single argument function types require parentheses - -- id: error_underlying_module_not_found - msg: >- - underlying Objective-C module %0 not found - -- id: generic_signature_not_minimal - msg: >- - generic requirement '%0' is redundant in %1 - -- id: generic_signature_not_valid - msg: >- - generic signature %0 is invalid - -- id: generic_signature_not_equal - msg: >- - generic signature %0 is not equal to new signature %1 - -- id: sdk_node_unrecognized_key - msg: >- - unrecognized key '%0' in SDK node - -- id: sdk_node_unrecognized_node_kind - msg: >- - unrecognized SDK node kind '%0' - -- id: sdk_node_unrecognized_type_attr_kind - msg: >- - unrecognized type attribute '%0' in SDK node - -- id: sdk_node_unrecognized_decl_attr_kind - msg: >- - unrecognized declaration attribute '%0' in SDK node - -- id: sdk_node_unrecognized_decl_kind - msg: >- - unrecognized declaration kind '%0' in SDK node - -- id: sdk_node_unrecognized_accessor_kind - msg: >- - unrecognized accessor kind '%0' in SDK node - -- id: source_location_creates_file_id_conflicts - msg: >- - '#sourceLocation' directive produces '#fileID' string of '%0', which - conflicts with '#fileID' strings produced by other paths in the module - -- id: fixit_correct_source_location_file - msg: >- - change file in '#sourceLocation' to '%0' - -- id: circular_reference - msg: >- - circular reference - -- id: circular_reference_through - msg: >- - through reference here - -- id: circular_class_inheritance - msg: >- - %0 inherits from itself - -- id: circular_enum_inheritance - msg: >- - %0 has a raw type that depends on itself - -- id: circular_protocol_def - msg: >- - protocol %0 refines itself - -- id: kind_declname_declared_here - msg: >- - %0 %1 declared here - -- id: warn_property_wrapper_module_scope - msg: >- - ignoring associated type %0 in favor of module-scoped property wrapper - %0; please qualify the reference with %1 - -- id: circular_type_resolution_note - msg: >- - while resolving type %0 - -- id: cannot_load_swiftoverlay_file - msg: >- - cannot load cross-import overlay for '%0' and '%1': %2 (declared by '%3') - -- id: cannot_list_swiftcrossimport_dir - msg: >- - cannot list cross-import overlays for '%0': %1 (declared in '%2') - -- id: cross_imported_by_both_modules - msg: >- - modules %0 and %1 both declare module %2 as a cross-import overlay, which - may cause paradoxical behavior when looking up names in them; please report this - bug to the maintainers of these modules - -- id: opening_brace - msg: >- - to match this opening '{' - -- id: opening_bracket - msg: >- - to match this opening '[' - -- id: opening_paren - msg: >- - to match this opening '(' - -- id: opening_angle - msg: >- - to match this opening '<' - -- id: extra_rbrace - msg: >- - extraneous '}' at top level - -- id: structure_overflow - msg: >- - structure nesting level exceeded maximum of %0 - -- id: expected_close_to_if_directive - msg: >- - expected #else or #endif at end of conditional compilation block - -- id: expected_close_after_else_directive - msg: >- - further conditions after #else are unreachable - -- id: unexpected_conditional_compilation_block_terminator - msg: >- - unexpected conditional compilation block terminator - -- id: incomplete_conditional_compilation_directive - msg: >- - incomplete condition in conditional compilation directive - -- id: extra_tokens_conditional_compilation_directive - msg: >- - extra tokens following conditional compilation directive - -- id: unexpected_rbrace_in_conditional_compilation_block - msg: >- - unexpected '}' in conditional compilation block - -- id: unexpected_if_following_else_compilation_directive - msg: >- - unexpected 'if' keyword following '#else' conditional compilation - directive; did you mean '#elseif'? - -- id: pound_diagnostic_expected_string - msg: >- - expected string literal in %select{#warning|#error}0 directive - -- id: pound_diagnostic_expected - msg: >- - expected '%0' in %select{#warning|#error}1 directive - -- id: pound_diagnostic_expected_parens - msg: >- - %select{#warning|#error}0 directive requires parentheses - -- id: pound_diagnostic_interpolation - msg: >- - string interpolation is not allowed in %select{#warning|#error}0 - directives - -- id: extra_tokens_pound_diagnostic_directive - msg: >- - extra tokens following %select{#warning|#error}0 directive - -- id: sourceLocation_expected - msg: >- - expected '%0' in #sourceLocation directive - -- id: unexpected_line_directive - msg: >- - parameterless closing #sourceLocation() directive without prior opening - #sourceLocation(file:,line:) directive - -- id: expected_line_directive_number - msg: >- - expected starting line number for #sourceLocation directive - -- id: expected_line_directive_name - msg: >- - expected filename string literal for #sourceLocation directive - -- id: extra_tokens_line_directive - msg: >- - extra tokens at the end of #sourceLocation directive - -- id: line_directive_line_zero - msg: >- - the line number needs to be greater than zero - -- id: escaped_parameter_name - msg: >- - keyword '%0' does not need to be escaped in argument list - -- id: forbidden_interpolated_string - msg: >- - %0 cannot be an interpolated string literal - -- id: forbidden_extended_escaping_string - msg: >- - %0 cannot be an extended escaping string literal - -- id: lex_nul_character - msg: >- - nul character embedded in middle of file - -- id: lex_utf16_bom_marker - msg: >- - input files must be encoded as UTF-8 instead of UTF-16 - -- id: lex_hashbang_not_allowed - msg: >- - hashbang line is allowed only in the main file - -- id: lex_unprintable_ascii_character - msg: >- - unprintable ASCII character found in source file - -- id: lex_invalid_utf8 - msg: >- - invalid UTF-8 found in source file - -- id: lex_single_quote_string - msg: >- - single-quoted string literal found, use '"' - -- id: lex_invalid_curly_quote - msg: >- - unicode curly quote found, replace with '"' - -- id: lex_confusable_character - msg: >- - unicode character '%0' (%1) looks similar to '%2' (%3); did you mean to use '%2' (%3)? - -- id: lex_nonbreaking_space - msg: >- - non-breaking space (U+00A0) used instead of regular space - -- id: lex_unterminated_block_comment - msg: >- - unterminated '/*' comment - -- id: lex_comment_start - msg: >- - comment started here - -- id: lex_unterminated_string - msg: >- - unterminated string literal - -- id: lex_invalid_escape - msg: >- - invalid escape sequence in literal - -- id: lex_invalid_u_escape - msg: >- - \u{...} escape sequence expects between 1 and 8 hex digits - -- id: lex_invalid_u_escape_rbrace - msg: >- - expected '}' in \u{...} escape sequence - -- id: lex_invalid_escape_delimiter - msg: >- - too many '#' characters in delimited escape - -- id: lex_invalid_closing_delimiter - msg: >- - too many '#' characters in closing delimiter - -- id: lex_invalid_unicode_scalar - msg: >- - invalid unicode scalar - -- id: lex_unicode_escape_braces - msg: >- - expected hexadecimal code in braces after unicode escape - -- id: lex_illegal_multiline_string_start - msg: >- - multi-line string literal content must begin on a new line - -- id: lex_illegal_multiline_string_end - msg: >- - multi-line string literal closing delimiter must begin on a new line - -- id: lex_multiline_string_indent_inconsistent - msg: >- - %select{unexpected space in|unexpected tab in|insufficient}2 indentation - of %select{line|next %1 lines}0 in multi-line string literal - -- id: lex_multiline_string_indent_should_match_here - msg: >- - should match %select{space|tab}0 here - -- id: lex_multiline_string_indent_change_line - msg: >- - change indentation of %select{this line|these lines}0 to match closing - delimiter - -- id: lex_escaped_newline_at_lastline - msg: >- - escaped newline at the last line is not allowed - -- id: lex_invalid_character - msg: >- - invalid character in source file - -- id: lex_invalid_identifier_start_character - msg: >- - an identifier cannot begin with this character - -- id: lex_expected_digit_in_fp_exponent - msg: >- - expected a digit in floating point exponent - -- id: lex_invalid_digit_in_fp_exponent - msg: >- - '%0' is not a valid %select{digit|first character}1 in floating point - exponent - -- id: lex_invalid_digit_in_int_literal - msg: >- - '%0' is not a valid %select{binary digit (0 or 1)|octal digit - (0-7)|digit|hexadecimal digit (0-9, A-F)}1 in integer literal - -- id: lex_expected_binary_exponent_in_hex_float_literal - msg: >- - hexadecimal floating point literal must end with an exponent - -- id: lex_unexpected_block_comment_end - msg: >- - unexpected end of block comment - -- id: lex_unary_equal - msg: >- - '=' must have consistent whitespace on both sides - -- id: extra_whitespace_period - msg: >- - extraneous whitespace after '.' is not permitted - -- id: lex_editor_placeholder - msg: >- - editor placeholder in source file - -- id: lex_editor_placeholder_in_playground - msg: >- - editor placeholder in source file - -- id: lex_conflict_marker_in_file - msg: >- - source control conflict marker in source file - -- id: note_in_decl_extension - msg: >- - in %select{declaration|extension}0 of %1 - -- id: line_directive_style_deprecated - msg: >- - #line directive was renamed to #sourceLocation - -- id: declaration_same_line_without_semi - msg: >- - consecutive declarations on a line must be separated by ';' - -- id: expected_decl - msg: >- - expected declaration - -- id: expected_identifier_in_decl - msg: >- - expected identifier in %0 declaration - -- id: expected_keyword_in_decl - msg: >- - expected '%0' keyword in %1 declaration - -- id: number_cant_start_decl_name - msg: >- - %0 name can only start with a letter or underscore, not a number - -- id: expected_identifier_after_case_comma - msg: >- - expected identifier after comma in enum 'case' declaration - -- id: decl_redefinition - msg: >- - definition conflicts with previous value - -- id: let_cannot_be_computed_property - msg: >- - 'let' declarations cannot be computed properties - -- id: let_cannot_be_observing_property - msg: >- - 'let' declarations cannot be observing properties - -- id: let_cannot_be_addressed_property - msg: >- - 'let' declarations cannot have addressors - -- id: disallowed_var_multiple_getset - msg: >- - 'var' declarations with multiple variables cannot have explicit - getters/setters - -- id: disallowed_init - msg: >- - initial value is not allowed here - -- id: var_init_self_referential - msg: >- - variable used within its own initial value - -- id: disallowed_enum_element - msg: >- - enum 'case' is not allowed outside of an enum - -- id: decl_inner_scope - msg: >- - declaration is only valid at file scope - -- id: decl_not_static - msg: >- - declaration cannot be marked %0 - -- id: cskeyword_not_attribute - msg: >- - '%0' is a declaration modifier, not an attribute - -- id: decl_already_static - msg: >- - %0 cannot appear after another 'static' or 'class' keyword - -- id: enum_case_dot_prefix - msg: >- - extraneous '.' in enum 'case' declaration - -- id: static_var_decl_global_scope - msg: >- - %select{%error|static properties|class properties}0 may only be declared - on a type - -- id: computed_property_no_accessors - msg: >- - %select{computed property|subscript}0 must have accessors specified - -- id: expected_getset_in_protocol - msg: >- - expected get or set in a protocol property - -- id: computed_property_missing_type - msg: >- - computed property must have an explicit type - -- id: getset_nontrivial_pattern - msg: >- - getter/setter can only be defined for a single variable - -- id: expected_rbrace_in_getset - msg: >- - expected '}' at end of variable get/set clause - -- id: duplicate_accessor - msg: >- - %select{variable|subscript}0 already has %1 - -- id: conflicting_accessor - msg: >- - %select{variable|subscript}0 cannot provide both %1 and %2 - -- id: previous_accessor - msg: >- - %select{|previous definition of }1%0 %select{defined |}1here - -- id: expected_accessor_parameter_name - msg: >- - expected %select{setter|willSet|didSet}0 parameter name - -- id: expected_rparen_set_name - msg: >- - expected ')' after setter parameter name - -- id: expected_rparen_willSet_name - msg: >- - expected ')' after willSet parameter name - -- id: expected_rparen_didSet_name - msg: >- - expected ')' after didSet parameter name - -- id: expected_lbrace_accessor - msg: >- - expected '{' to start %0 definition - -- id: expected_accessor_kw - msg: >- - expected 'get', 'set', 'willSet', or 'didSet' keyword to start an - accessor definition - -- id: missing_getter - msg: >- - %select{variable|subscript}0 with %1 must also have a getter - -- id: missing_reading_accessor - msg: >- - %select{variable|subscript}0 with %1 must also have a getter, addressor, - or 'read' accessor - -- id: observing_accessor_conflicts_with_accessor - msg: >- - %select{'willSet'|'didSet'}0 cannot be provided together with %1 - -- id: observing_accessor_in_subscript - msg: >- - %select{'willSet'|'didSet'}0 is not allowed in subscripts - -- id: getset_cannot_be_implied - msg: >- - variable with implied type cannot have implied getter/setter - -- id: decl_expected_module_name - msg: >- - expected module name in import declaration - -- id: expected_lbrace_extension - msg: >- - expected '{' in extension - -- id: expected_rbrace_extension - msg: >- - expected '}' at end of extension - -- id: extension_type_expected - msg: >- - expected type name in extension declaration - -- id: expected_equal_in_typealias - msg: >- - expected '=' in type alias declaration - -- id: expected_type_in_typealias - msg: >- - expected type in type alias declaration - -- id: expected_type_in_associatedtype - msg: >- - expected type in associated type declaration - -- id: associated_type_generic_parameter_list - msg: >- - associated types must not have a generic parameter list - -- id: func_decl_without_paren - msg: >- - expected '(' in argument list of function declaration - -- id: static_func_decl_global_scope - msg: >- - %select{%error|static methods|class methods}0 may only be declared on a - type - -- id: func_decl_expected_arrow - msg: >- - expected '->' after function parameter tuple - -- id: operator_static_in_protocol - msg: >- - operator '%0' declared in protocol must be 'static' - -- id: expected_lbrace_enum - msg: >- - expected '{' in enum - -- id: expected_rbrace_enum - msg: >- - expected '}' at end of enum - -- id: expected_lbrace_struct - msg: >- - expected '{' in struct - -- id: expected_rbrace_struct - msg: >- - expected '}' in struct - -- id: expected_lbrace_class - msg: >- - expected '{' in class - -- id: expected_rbrace_class - msg: >- - expected '}' in class - -- id: expected_colon_class - msg: >- - expected ':' to begin inheritance clause - -- id: generic_arguments_protocol - msg: >- - protocols do not allow generic parameters; use associated types instead - -- id: expected_lbrace_protocol - msg: >- - expected '{' in protocol type - -- id: expected_rbrace_protocol - msg: >- - expected '}' in protocol - -- id: protocol_setter_name - msg: >- - setter in a protocol cannot have a name - -- id: protocol_method_with_body - msg: >- - protocol methods must not have bodies - -- id: protocol_init_with_body - msg: >- - protocol initializers must not have bodies - -- id: subscript_decl_wrong_scope - msg: >- - 'subscript' functions may only be declared within a type - -- id: expected_lparen_subscript - msg: >- - expected '(' for subscript parameters - -- id: subscript_has_name - msg: >- - subscripts cannot have a name - -- id: expected_arrow_subscript - msg: >- - expected '->' for subscript element type - -- id: expected_type_subscript - msg: >- - expected subscripting element type - -- id: expected_lbrace_subscript - msg: >- - expected '{' in subscript to specify getter and setter implementation - -- id: expected_lbrace_subscript_protocol - msg: >- - subscript in protocol must have explicit { get } or { get set } specifier - -- id: subscript_without_get - msg: >- - subscript declarations must have a getter - -- id: invalid_nested_init - msg: >- - missing '%select{super.|self.}0' at initializer invocation - -- id: initializer_decl_wrong_scope - msg: >- - initializers may only be declared within a type - -- id: expected_lparen_initializer - msg: >- - expected '(' for initializer parameters - -- id: initializer_has_name - msg: >- - initializers cannot have a name - -- id: destructor_decl_outside_class - msg: >- - deinitializers may only be declared within a class - -- id: expected_lbrace_destructor - msg: >- - expected '{' for deinitializer - -- id: destructor_has_name - msg: >- - deinitializers cannot have a name - -- id: opened_destructor_expected_rparen - msg: >- - expected ')' to close parameter list - -- id: destructor_params - msg: >- - no parameter clause allowed on deinitializer - -- id: operator_decl_inner_scope - msg: >- - 'operator' may only be declared at file scope - -- id: expected_operator_name_after_operator - msg: >- - expected operator name in operator declaration - -- id: identifier_within_operator_name - msg: >- - '%0' is considered an identifier and must not appear within an operator - name - -- id: operator_name_invalid_char - msg: >- - '%0' is not allowed in operator names - -- id: postfix_operator_name_cannot_start_with_unwrap - msg: >- - postfix operator names starting with '?' or '!' are disallowed to avoid - collisions with built-in unwrapping operators - -- id: deprecated_operator_body - msg: >- - operator should no longer be declared with body - -- id: deprecated_operator_body_use_group - msg: >- - operator should no longer be declared with body; use a precedence group - instead - -- id: operator_decl_no_fixity - msg: >- - operator must be declared as 'prefix', 'postfix', or 'infix' - -- id: operator_decl_expected_type - msg: >- - expected designated type in operator declaration - -- id: operator_decl_trailing_comma - msg: >- - trailing comma in operator declaration - -- id: precedencegroup_not_infix - msg: >- - only infix operators may declare a precedence - -- id: expected_precedencegroup_name - msg: >- - expected identifier after 'precedencegroup' - -- id: expected_precedencegroup_lbrace - msg: >- - expected '{' after name of precedence group - -- id: expected_precedencegroup_attribute - msg: >- - expected operator attribute identifier in precedence group body - -- id: unknown_precedencegroup_attribute - msg: >- - '%0' is not a valid precedence group attribute - -- id: expected_precedencegroup_attribute_colon - msg: >- - expected colon after attribute name in precedence group - -- id: precedencegroup_attribute_redeclared - msg: >- - '%0' attribute for precedence group declared multiple times - -- id: expected_precedencegroup_associativity - msg: >- - expected 'none', 'left', or 'right' after 'associativity' - -- id: expected_precedencegroup_assignment - msg: >- - expected 'true' or 'false' after 'assignment' - -- id: expected_precedencegroup_relation - msg: >- - expected name of related precedence group after '%0' - -- id: expected_sil_keyword - msg: >- - expected SIL keyword - -- id: inout_not_attribute - msg: >- - @inout is no longer an attribute - -- id: only_allowed_in_sil - msg: >- - '%0' only allowed in SIL modules - -- id: expected_sil_type - msg: >- - expected type in SIL code - -- id: expected_sil_colon_value_ref - msg: >- - expected ':' before type in SIL value reference - -- id: expected_sil_value_name - msg: >- - expected SIL value name - -- id: expected_sil_type_kind - msg: >- - expected SIL type to %0 - -- id: expected_sil_constant - msg: >- - expected constant in SIL code - -- id: referenced_value_no_accessor - msg: >- - referenced declaration has no %select{getter|setter}0 - -- id: expected_sil_value_ownership_kind - msg: >- - expected value ownership kind in SIL code - -- id: silfunc_and_silarg_have_incompatible_sil_value_ownership - msg: >- - SILFunction and SILArgument have mismatching ValueOwnershipKinds. - Function type specifies: '@%0'. SIL argument specifies: '@%1'. - -- id: expected_sil_colon - msg: >- - expected ':' before %0 - -- id: expected_sil_tuple_index - msg: >- - expected tuple element index - -- id: invalid_index_subset - msg: >- - invalid index subset; expected '[SU]+' where 'S' represents set indices - and 'U' represents unset indices - -- id: sil_value_redefinition - msg: >- - redefinition of value '%0' - -- id: sil_value_use_type_mismatch - msg: >- - value '%0' defined with mismatching type %1 (expected %2) - -- id: sil_value_def_type_mismatch - msg: >- - value '%0' used with mismatching type %1 (expected %2) - -- id: sil_use_of_undefined_value - msg: >- - use of undefined value '%0' - -- id: sil_prior_reference - msg: >- - prior reference was here - -- id: expected_colon_in_sil_location - msg: >- - expected ':' in SIL location - -- id: sil_invalid_line_in_sil_location - msg: >- - line number must be a positive integer - -- id: sil_invalid_column_in_sil_location - msg: >- - column number must be a positive integer - -- id: sil_invalid_scope_slot - msg: >- - scope number must be a positive integer - -- id: sil_scope_undeclared - msg: >- - scope number %0 needs to be declared before first use - -- id: sil_scope_redefined - msg: >- - scope number %0 is already defined - -- id: expected_sil_instr_start_of_line - msg: >- - SIL instructions must be at the start of a line - -- id: expected_equal_in_sil_instr - msg: >- - expected '=' in SIL instruction - -- id: wrong_result_count_in_sil_instr - msg: >- - wrong number of results for SIL instruction, expected %0 - -- id: expected_sil_instr_opcode - msg: >- - expected SIL instruction opcode - -- id: expected_tok_in_sil_instr - msg: >- - expected '%0' in SIL instruction - -- id: sil_property_generic_signature_mismatch - msg: >- - sil_property generic signature must match original declaration - -- id: sil_string_no_encoding - msg: >- - string_literal instruction requires an encoding - -- id: sil_string_invalid_encoding - msg: >- - unknown string literal encoding '%0' - -- id: expected_tuple_type_in_tuple - msg: >- - tuple instruction requires a tuple type - -- id: sil_tuple_inst_wrong_value_count - msg: >- - tuple instruction requires %0 values - -- id: sil_tuple_inst_wrong_field - msg: >- - tuple instruction requires a field number - -- id: sil_struct_inst_wrong_field - msg: >- - struct instruction requires a field name - -- id: sil_ref_inst_wrong_field - msg: >- - ref_element_addr instruction requires a field name - -- id: sil_invalid_instr_operands - msg: >- - invalid instruction operands - -- id: sil_operand_not_address - msg: >- - %0 operand of '%1' must have address type - -- id: sil_operand_not_ref_storage_address - msg: >- - %0 operand of '%1' must have address of %2 type - -- id: sil_integer_literal_not_integer_type - msg: >- - integer_literal instruction requires a 'Builtin.Int' type - -- id: sil_integer_literal_not_well_formed - msg: >- - integer_literal value not well-formed for type %0 - -- id: sil_float_literal_not_float_type - msg: >- - float_literal instruction requires a 'Builtin.FP' type - -- id: sil_substitutions_on_non_polymorphic_type - msg: >- - apply of non-polymorphic function cannot have substitutions - -- id: sil_witness_method_not_protocol - msg: >- - witness_method is not a protocol method - -- id: sil_witness_method_type_does_not_conform - msg: >- - witness_method type does not conform to protocol - -- id: sil_member_decl_not_found - msg: >- - member not found - -- id: sil_named_member_decl_not_found - msg: >- - member %0 not found in type %1 - -- id: sil_member_lookup_bad_type - msg: >- - cannot lookup member %0 in non-nominal, non-module type %1 - -- id: sil_member_decl_type_mismatch - msg: >- - member defined with mismatching type %0 (expected %1) - -- id: sil_substitution_mismatch - msg: >- - substitution replacement type %0 does not conform to protocol %1 - -- id: sil_not_class - msg: >- - substitution replacement type %0 is not a class type - -- id: sil_missing_substitutions - msg: >- - missing substitutions - -- id: sil_too_many_substitutions - msg: >- - too many substitutions - -- id: sil_dbg_unknown_key - msg: >- - unknown key '%0' in debug variable declaration - -- id: sil_objc_with_tail_elements - msg: >- - alloc_ref [objc] cannot have tail allocated elements - -- id: sil_expected_access_kind - msg: >- - %0 instruction must have explicit access kind - -- id: sil_expected_access_enforcement - msg: >- - %0 instruction must have explicit access enforcement - -- id: sil_keypath_expected_component_kind - msg: >- - expected keypath component kind - -- id: sil_keypath_unknown_component_kind - msg: >- - unknown keypath component kind %0 - -- id: sil_keypath_computed_property_missing_part - msg: >- - keypath %select{gettable|settable}0_property component needs an - %select{id and getter|id, getter, and setter}0 - -- id: sil_keypath_no_root - msg: >- - keypath must have a root component declared - -- id: sil_keypath_index_not_hashable - msg: >- - key path index type %0 does not conform to Hashable - -- id: sil_keypath_index_operand_type_conflict - msg: >- - conflicting types for key path operand %0: %1 vs. %2 - -- id: sil_keypath_no_use_of_operand_in_pattern - msg: >- - operand %0 is not referenced by any component in the pattern - -- id: expected_sil_block_name - msg: >- - expected basic block name or '}' - -- id: expected_sil_block_colon - msg: >- - expected ':' after basic block name - -- id: sil_undefined_basicblock_use - msg: >- - use of undefined basic block %0 - -- id: sil_basicblock_redefinition - msg: >- - redefinition of basic block %0 - -- id: sil_basicblock_arg_rparen - msg: >- - expected ')' in basic block argument list - -- id: expected_sil_function_name - msg: >- - expected SIL function name - -- id: expected_sil_rbrace - msg: >- - expected '}' at the end of a sil body - -- id: expected_sil_function_type - msg: >- - sil function expected to have SIL function type - -- id: sil_dynamically_replaced_func_not_found - msg: >- - dynamically replaced function not found %0 - -- id: sil_availability_expected_version - msg: >- - expected version number in 'available' attribute - -- id: expected_sil_stage_name - msg: >- - expected 'raw' or 'canonical' after 'sil_stage' - -- id: multiple_sil_stage_decls - msg: >- - sil_stage declared multiple times - -- id: expected_sil_vtable_colon - msg: >- - expected ':' in a vtable entry - -- id: sil_vtable_func_not_found - msg: >- - sil function not found %0 - -- id: sil_vtable_class_not_found - msg: >- - sil class not found %0 - -- id: sil_vtable_bad_entry_kind - msg: >- - expected 'inherited' or 'override' - -- id: sil_vtable_expect_rsquare - msg: >- - expected ']' after vtable entry kind - -- id: sil_global_variable_not_found - msg: >- - sil global not found %0 - -- id: expected_sil_witness_colon - msg: >- - expected ':' in a witness table - -- id: expected_sil_witness_lparen - msg: >- - expected '(' in a witness table - -- id: expected_sil_witness_rparen - msg: >- - expected ')' in a witness table - -- id: sil_witness_func_not_found - msg: >- - sil function not found %0 - -- id: sil_witness_protocol_not_found - msg: >- - sil protocol not found %0 - -- id: sil_witness_assoc_not_found - msg: >- - sil associated type decl not found %0 - -- id: sil_witness_assoc_conf_not_found - msg: >- - sil associated type path for conformance not found %0 - -- id: sil_witness_protocol_conformance_not_found - msg: >- - sil protocol conformance not found - -- id: sil_diff_witness_expected_token - msg: >- - expected '%0' in differentiability witness - -- id: sil_diff_witness_serialized_declaration - msg: >- - differentiability witness declaration should not be serialized - -- id: sil_diff_witness_undefined - msg: >- - reference to undefined differentiability witness - -- id: sil_diff_witness_invalid_generic_signature - msg: >- - expected witness generic signature '%0' does not have same generic - parameters as original function generic signature '%1' - -- id: sil_coverage_invalid_hash - msg: >- - expected coverage hash - -- id: sil_coverage_expected_lbrace - msg: >- - expected '{' in coverage map - -- id: sil_coverage_expected_loc - msg: >- - expected line:column pair - -- id: sil_coverage_expected_arrow - msg: >- - expected '->' after start location - -- id: sil_coverage_expected_colon - msg: >- - expected ':' after source range - -- id: sil_coverage_invalid_counter - msg: >- - expected counter expression, id, or 'zero' - -- id: sil_coverage_expected_rparen - msg: >- - expected ')' to end counter expression - -- id: sil_coverage_expected_quote - msg: >- - expected quotes surrounding PGO function name - -- id: sil_coverage_invalid_operator - msg: >- - expected '+' or '-' - -- id: expected_type - msg: >- - expected type - -- id: expected_init_value - msg: >- - expected initial value after '=' - -- id: expected_identifier_in_dotted_type - msg: >- - expected identifier in dotted type - -- id: expected_identifier_for_type - msg: >- - expected identifier for type name - -- id: expected_rangle_generic_arg_list - msg: >- - expected '>' to complete generic argument list - -- id: expected_type_function_result - msg: >- - expected type for function result - -- id: generic_non_function - msg: >- - only syntactic function types can be generic - -- id: rethrowing_function_type - msg: >- - only function declarations may be marked 'rethrows'; did you mean - 'throws'? - -- id: async_or_throws_in_wrong_position - msg: >- - %select{'throws'|'rethrows'|'async'}0 may only occur before '->' - -- id: throw_in_function_type - msg: >- - expected throwing specifier; did you mean 'throws'? - -- id: expected_type_before_arrow - msg: >- - expected type before '->' - -- id: expected_type_after_arrow - msg: >- - expected type after '->' - -- id: function_type_argument_label - msg: >- - function types cannot have argument labels; use '_' before %0 - -- id: expected_dynamic_func_attr - msg: >- - expected a dynamically_replaceable function - -- id: expected_expr_enum_case_raw_value - msg: >- - expected expression after '=' in 'case' - -- id: nonliteral_enum_case_raw_value - msg: >- - raw value for enum case must be a literal - -- id: new_array_syntax - msg: >- - array types are now written with the brackets around the element type - -- id: expected_rbracket_array_type - msg: >- - expected ']' in array type - -- id: expected_element_type - msg: >- - expected element type - -- id: expected_dictionary_value_type - msg: >- - expected dictionary value type - -- id: expected_rbracket_dictionary_type - msg: >- - expected ']' in dictionary type - -- id: extra_rbracket - msg: >- - unexpected ']' in type; did you mean to write an array type? - -- id: extra_colon - msg: >- - unexpected ':' in type; did you mean to write a dictionary type? - -- id: subscript_array_element - msg: >- - unexpected subscript in array literal; did you mean to write two separate - elements instead? - -- id: subscript_array_element_fix_it_add_comma - msg: >- - add a separator between the elements - -- id: subscript_array_element_fix_it_remove_space - msg: >- - remove the space between the elements to silence this warning - -- id: expected_rparen_tuple_type_list - msg: >- - expected ')' at end of tuple list - -- id: multiple_ellipsis_in_tuple - msg: >- - only a single element can be variadic - -- id: tuple_type_init - msg: >- - default argument not permitted in a tuple type - -- id: protocol_method_argument_init - msg: >- - default argument not permitted in a protocol method - -- id: protocol_init_argument_init - msg: >- - default argument not permitted in a protocol initializer - -- id: tuple_type_multiple_labels - msg: >- - tuple element cannot have two labels - -- id: expected_rangle_protocol - msg: >- - expected '>' to complete protocol-constrained type - -- id: deprecated_protocol_composition - msg: >- - 'protocol<...>' composition syntax has been removed; join the protocols - using '&' - -- id: deprecated_protocol_composition_single - msg: >- - 'protocol<...>' composition syntax has been removed and is not needed - here - -- id: deprecated_any_composition - msg: >- - 'protocol<>' syntax has been removed; use 'Any' instead - -- id: sil_box_expected_var_or_let - msg: >- - expected 'var' or 'let' to introduce SIL box field type - -- id: sil_box_expected_r_brace - msg: >- - expected '}' to complete SIL box field type list - -- id: sil_box_expected_r_angle - msg: >- - expected '>' to complete SIL box generic argument list - -- id: sil_function_subst_expected_l_angle - msg: >- - expected '<' to begin SIL function type substitution list after 'for' - -- id: sil_function_subst_expected_r_angle - msg: >- - expected '>' to end SIL function type substitution list after 'for <...' - -- id: sil_function_subst_expected_generics - msg: >- - expected '<' to begin substituted parameter list after '@substituted' - -- id: sil_function_subst_expected_function - msg: >- - expected function type after '@substituted' - -- id: sil_function_subst_expected_subs - msg: >- - expected 'for' to begin substitutions after '@substituted' function type - -- id: sil_function_subs_without_generics - msg: >- - unexpected 'for' to begin substitutions after non-generic function type - -- id: opaque_mid_composition - msg: >- - 'some' should appear at the beginning of a composition - -- id: layout_size_should_be_positive - msg: >- - expected non-negative size to be specified in layout constraint - -- id: layout_alignment_should_be_positive - msg: >- - expected non-negative alignment to be specified in layout constraint - -- id: expected_rparen_layout_constraint - msg: >- - expected ')' to complete layout constraint - -- id: layout_constraints_only_inside_specialize_attr - msg: >- - layout constraints are only allowed inside '_specialize' attributes - -- id: expected_pattern - msg: >- - expected pattern - -- id: keyword_cant_be_identifier - msg: >- - keyword '%0' cannot be used as an identifier here - -- id: repeated_identifier - msg: >- - found an unexpected second identifier in %0 declaration; is there an - accidental break? - -- id: join_identifiers - msg: >- - join the identifiers together - -- id: join_identifiers_camel_case - msg: >- - join the identifiers together with camel-case - -- id: backticks_to_escape - msg: >- - if this name is unavoidable, use backticks to escape it - -- id: expected_rparen_tuple_pattern_list - msg: >- - expected ')' at end of tuple pattern - -- id: untyped_pattern_ellipsis - msg: >- - '...' cannot be applied to a subpattern which is not explicitly typed - -- id: no_default_arg_closure - msg: >- - default arguments are not allowed in closures - -- id: no_default_arg_curried - msg: >- - default arguments are not allowed in curried parameter lists - -- id: var_pattern_in_var - msg: >- - '%select{var|let}0' cannot appear nested inside another 'var' or 'let' - pattern - -- id: extra_var_in_multiple_pattern_list - msg: >- - %0 must be bound in every pattern - -- id: let_pattern_in_immutable_context - msg: >- - 'let' pattern cannot appear nested in an already immutable context - -- id: specifier_must_have_type - msg: >- - %0 arguments must have a type specified - -- id: expected_rparen_parameter - msg: >- - expected ')' in parameter - -- id: expected_parameter_type - msg: >- - expected parameter type following ':' - -- id: expected_parameter_name - msg: >- - expected parameter name followed by ':' - -- id: expected_parameter_colon - msg: >- - expected ':' following argument label and parameter name - -- id: expected_assignment_instead_of_comparison_operator - msg: >- - expected '=' instead of '==' to assign default value for parameter - -- id: multiple_parameter_ellipsis - msg: >- - only a single variadic parameter '...' is permitted - -- id: parameter_vararg_default - msg: >- - variadic parameter cannot have a default value - -- id: parameter_specifier_as_attr_disallowed - msg: >- - '%0' before a parameter name is not allowed, place it before the - parameter type instead - -- id: parameter_specifier_repeated - msg: >- - parameter must not have multiple '__owned', 'inout', or '__shared' - specifiers - -- id: parameter_let_var_as_attr - msg: >- - '%0' in this position is interpreted as an argument label - -- id: parameter_extraneous_double_up - msg: >- - extraneous duplicate parameter name; %0 already has an argument label - -- id: parameter_operator_keyword_argument - msg: >- - %select{operator|closure|enum case}0 cannot have keyword arguments - -- id: parameter_unnamed - msg: >- - unnamed parameters must be written with the empty name '_' - -- id: parameter_unnamed_warn - msg: >- - unnamed parameters must be written with the empty name '_' - -- id: parameter_curry_syntax_removed - msg: >- - cannot have more than one parameter list - -- id: initializer_as_typed_pattern - msg: >- - unexpected initializer in pattern; did you mean to use '='? - -- id: unlabeled_parameter_following_variadic_parameter - msg: >- - a parameter following a variadic parameter requires a label - -- id: enum_element_empty_arglist - msg: >- - enum element with associated values must have at least one associated - value - -- id: enum_element_empty_arglist_swift4 - msg: >- - enum element with associated values must have at least one associated - value; this will be an error in the future version of Swift - -- id: enum_element_empty_arglist_delete - msg: >- - did you mean to remove the empty associated value list? - -- id: enum_element_empty_arglist_add_void - msg: >- - did you mean to explicitly add a 'Void' associated value? - -- id: expected_stmt - msg: >- - expected statement - -- id: illegal_top_level_stmt - msg: >- - statements are not allowed at the top level - -- id: illegal_top_level_expr - msg: >- - expressions are not allowed at the top level - -- id: illegal_semi_stmt - msg: >- - ';' statements are not allowed - -- id: statement_begins_with_closure - msg: >- - top-level statement cannot begin with a closure expression - -- id: statement_same_line_without_semi - msg: >- - consecutive statements on a line must be separated by ';' - -- id: invalid_label_on_stmt - msg: >- - labels are only valid on loops, if, and switch statements - -- id: labeled_block_needs_do - msg: >- - labeled block needs 'do' - -- id: snake_case_deprecated - msg: >- - %0 has been replaced with %1 in Swift 3 - -- id: expected_expr_assignment - msg: >- - expected expression in assignment - -- id: expected_rbrace_in_brace_stmt - msg: >- - expected '}' at end of brace statement - -- id: typealias_inside_protocol_without_type - msg: >- - type alias is missing an assigned type; use 'associatedtype' to define an - associated type requirement - -- id: associatedtype_outside_protocol - msg: >- - associated types can only be defined in a protocol; define a type or - introduce a 'typealias' to satisfy an associated type requirement - -- id: expected_expr_return - msg: >- - expected expression in 'return' statement - -- id: unindented_code_after_return - msg: >- - expression following 'return' is treated as an argument of the 'return' - -- id: indent_expression_to_silence - msg: >- - indent the expression to silence this warning - -- id: expected_expr_throw - msg: >- - expected expression in 'throw' statement - -- id: expected_expr_yield - msg: >- - expected expression in 'yield' statement - -- id: expected_lbrace_after_defer - msg: >- - expected '{' after 'defer' - -- id: expected_comma_stmtcondition - msg: >- - expected ',' joining parts of a multi-clause condition - -- id: expected_expr_conditional - msg: >- - expected expression in conditional - -- id: expected_binding_keyword - msg: >- - expected '%0' in conditional - -- id: expected_expr_conditional_var - msg: >- - expected expression after '=' in conditional binding - -- id: conditional_var_initializer_required - msg: >- - variable binding in a condition requires an initializer - -- id: wrong_condition_case_location - msg: >- - pattern matching binding is spelled with 'case %0', not '%0 case' - -- id: expected_condition_if - msg: >- - expected expression, var, or let in 'if' condition - -- id: missing_condition_after_if - msg: >- - missing condition in an 'if' statement - -- id: expected_lbrace_after_if - msg: >- - expected '{' after 'if' condition - -- id: expected_lbrace_or_if_after_else - msg: >- - expected '{' or 'if' after 'else' - -- id: expected_lbrace_or_if_after_else_fixit - msg: >- - expected '{' or 'if' after 'else'; did you mean to write 'if'? - -- id: unexpected_else_after_if - msg: >- - unexpected 'else' immediately following 'if' condition - -- id: suggest_removing_else - msg: >- - remove 'else' to execute the braced block of statements when the - condition is true - -- id: expected_condition_guard - msg: >- - expected expression, var, let or case in 'guard' condition - -- id: missing_condition_after_guard - msg: >- - missing condition in an 'guard' statement - -- id: expected_else_after_guard - msg: >- - expected 'else' after 'guard' condition - -- id: expected_lbrace_after_guard - msg: >- - expected '{' after 'guard' else - -- id: bound_var_guard_body - msg: >- - variable declared in 'guard' condition is not usable in its body - -- id: expected_condition_while - msg: >- - expected expression, var, or let in 'while' condition - -- id: missing_condition_after_while - msg: >- - missing condition in a 'while' statement - -- id: expected_lbrace_after_while - msg: >- - expected '{' after 'while' condition - -- id: expected_lbrace_after_repeat - msg: >- - expected '{' after 'repeat' - -- id: expected_while_after_repeat_body - msg: >- - expected 'while' after body of 'repeat' statement - -- id: expected_expr_repeat_while - msg: >- - expected expression in 'repeat-while' condition - -- id: do_while_now_repeat_while - msg: >- - 'do-while' statement is not allowed - -- id: do_while_expected_repeat_while - msg: >- - did you mean 'repeat-while' statement? - -- id: do_while_expected_separate_stmt - msg: >- - did you mean separate 'do' and 'while' statements? - -- id: expected_lbrace_after_do - msg: >- - expected '{' after 'do' - -- id: expected_lbrace_after_catch - msg: >- - expected '{' after 'catch' pattern - -- id: expected_catch_where_expr - msg: >- - expected expression for 'where' guard of 'catch' - -- id: docatch_not_trycatch - msg: >- - the 'do' keyword is used to specify a 'catch' region - -- id: c_style_for_stmt_removed - msg: >- - C-style for statement has been removed in Swift 3 - -- id: expected_foreach_in - msg: >- - expected 'in' after for-each pattern - -- id: expected_foreach_container - msg: >- - expected Sequence expression for for-each loop - -- id: expected_foreach_lbrace - msg: >- - expected '{' to start the body of for-each loop - -- id: expected_foreach_where_expr - msg: >- - expected expression in 'where' guard of 'for/in' - -- id: expected_switch_expr - msg: >- - expected expression in 'switch' statement - -- id: expected_lbrace_after_switch - msg: >- - expected '{' after 'switch' subject expression - -- id: expected_rbrace_switch - msg: >- - expected '}' at end of 'switch' statement - -- id: case_outside_of_switch - msg: >- - '%0' label can only appear inside a 'switch' statement - -- id: stmt_in_switch_not_covered_by_case - msg: >- - all statements inside a switch must be covered by a 'case' or 'default' - -- id: case_after_default - msg: >- - additional 'case' blocks cannot appear after the 'default' block of a - 'switch' - -- id: expected_case_where_expr - msg: >- - expected expression for 'where' guard of 'case' - -- id: expected_case_colon - msg: >- - expected ':' after '%0' - -- id: default_with_where - msg: >- - 'default' cannot be used with a 'where' guard expression - -- id: case_stmt_without_body - msg: >- - %select{'case'|'default'}0 label in a 'switch' should have at least one - executable statement - -- id: try_on_stmt - msg: >- - 'try' cannot be used with '%0' - -- id: try_on_return_throw_yield - msg: >- - 'try' must be placed on the %select{returned|thrown|yielded}0 expression - -- id: try_on_var_let - msg: >- - 'try' must be placed on the initial value expression - -- id: expected_expr - msg: >- - expected expression - -- id: expected_separator - msg: >- - expected '%0' separator - -- id: unexpected_separator - msg: >- - unexpected '%0' separator - -- id: expected_expr_after_operator - msg: >- - expected expression after operator - -- id: expected_expr_after_unary_operator - msg: >- - expected expression after unary operator - -- id: expected_prefix_operator - msg: >- - unary operator cannot be separated from its operand - -- id: expected_operator_ref - msg: >- - expected operator name in operator reference - -- id: invalid_postfix_operator - msg: >- - operator with postfix spacing cannot start a subexpression - -- id: expected_member_name - msg: >- - expected member name following '.' - -- id: dollar_numeric_too_large - msg: >- - numeric value following '$' is too large - -- id: numeric_literal_numeric_member - msg: >- - expected named member of numeric literal - -- id: standalone_dollar_identifier - msg: >- - '$' is not an identifier; use backticks to escape it - -- id: dollar_identifier_decl - msg: >- - cannot declare entity named %0; the '$' prefix is reserved for - implicitly-synthesized declarations -- id: lazy_var_storage_access - msg: >- - access to the underlying storage of a lazy property is not allowed - -- id: anon_closure_arg_not_in_closure - msg: >- - anonymous closure argument not contained in a closure - -- id: anon_closure_arg_in_closure_with_args - msg: >- - anonymous closure arguments cannot be used inside a closure that has - explicit arguments - -- id: anon_closure_arg_in_closure_with_args_typo - msg: >- - anonymous closure arguments cannot be used inside a closure that has - explicit arguments; did you mean '%0'? - -- id: anon_closure_tuple_param_destructuring - msg: >- - closure tuple parameter does not support destructuring - -- id: expected_closure_parameter_name - msg: >- - expected the name of a closure parameter - -- id: expected_capture_specifier - msg: >- - expected 'weak', 'unowned', or no specifier in capture list - -- id: expected_capture_specifier_name - msg: >- - expected name of in closure capture list - -- id: expected_init_capture_specifier - msg: >- - expected initializer for closure capture specifier - -- id: expected_capture_list_end_rsquare - msg: >- - expected ']' at end of capture list - -- id: cannot_capture_fields - msg: >- - fields may only be captured by assigning to a specific name - -- id: expected_closure_result_type - msg: >- - expected closure result type after '->' - -- id: expected_closure_in - msg: >- - expected 'in' after the closure signature - -- id: unexpected_tokens_before_closure_in - msg: >- - unexpected tokens prior to 'in' - -- id: expected_closure_rbrace - msg: >- - expected '}' at end of closure - -- id: trailing_closure_after_newlines - msg: >- - braces here form a trailing closure separated from its callee by multiple - newlines - -- id: trailing_closure_callee_here - msg: >- - callee is here - -- id: string_literal_no_atsign - msg: >- - string literals in Swift are not preceded by an '@' sign - -- id: invalid_float_literal_missing_leading_zero - msg: >- - '.%0' is not a valid floating point literal; it must be written '0.%0' - -- id: availability_query_outside_if_stmt_guard - msg: >- - #available may only be used as condition of an 'if', 'guard' or 'while' - statement - -- id: empty_arg_label_underscore - msg: >- - an empty argument label is spelled with '_' - -- id: expected_identifier_after_dot_expr - msg: >- - expected identifier after '.' expression - -- id: expected_identifier_after_super_dot_expr - msg: >- - expected identifier or 'init' after super '.' expression - -- id: expected_dot_or_subscript_after_super - msg: >- - expected '.' or '[' after 'super' - -- id: super_in_closure_with_capture - msg: >- - using 'super' in a closure where 'self' is explicitly captured is not yet - supported - -- id: super_in_closure_with_capture_here - msg: >- - 'self' explicitly captured here - -- id: expected_expr_in_expr_list - msg: >- - expected expression in list of expressions - -- id: expected_expr_in_collection_literal - msg: >- - expected expression in container literal - -- id: expected_key_in_dictionary_literal - msg: >- - expected key expression in dictionary literal - -- id: expected_value_in_dictionary_literal - msg: >- - expected value in dictionary literal - -- id: expected_colon_in_dictionary_literal - msg: >- - expected ':' in dictionary literal - -- id: expected_rparen_expr_list - msg: >- - expected ')' in expression list - -- id: expected_rsquare_expr_list - msg: >- - expected ']' in expression list - -- id: expected_rsquare_array_expr - msg: >- - expected ']' in container literal expression - -- id: expected_arg_list_in_object_literal - msg: >- - expected argument list in object literal - -- id: legacy_object_literal - msg: >- - '%select{|[}0#%1(...)%select{|#]}0' has been renamed to '#%2(...)' - -- id: unknown_pound_expr - msg: >- - use of unknown directive '#%0' - -- id: expected_expr_after_if_question - msg: >- - expected expression after '?' in ternary expression - -- id: expected_colon_after_if_question - msg: >- - expected ':' after '? ...' in ternary expression - -- id: expected_expr_after_if_colon - msg: >- - expected expression after '? ... :' in ternary expression - -- id: expected_type_after_is - msg: >- - expected type after 'is' - -- id: expected_type_after_as - msg: >- - expected type after 'as' - -- id: string_interpolation_extra - msg: >- - extra tokens after interpolated string expression - -- id: string_interpolation_list_changing - msg: >- - interpolating multiple values will not form a tuple in Swift 5 - -- id: string_interpolation_list_insert_parens - msg: >- - insert parentheses to keep current behavior - -- id: string_interpolation_label_changing - msg: >- - labeled interpolations will not be ignored in Swift 5 - -- id: string_interpolation_remove_label - msg: >- - remove %0 label to keep current behavior - -- id: expr_keypath_expected_lparen - msg: >- - expected '(' following '#keyPath' - -- id: expr_keypath_expected_property_or_type - msg: >- - expected property or type name within '#keyPath(...)' - -- id: expr_keypath_expected_rparen - msg: >- - expected ')' to complete '#keyPath' expression - -- id: expr_keypath_expected_expr - msg: >- - expected expression path in Swift key path - -- id: expr_selector_expected_lparen - msg: >- - expected '(' following '#selector' - -- id: expr_selector_expected_method_expr - msg: >- - expected expression naming a method within '#selector(...)' - -- id: expr_selector_expected_property_expr - msg: >- - expected expression naming a property within '#selector(...)' - -- id: expr_selector_expected_rparen - msg: >- - expected ')' to complete '#selector' expression - -- id: expr_dynamictype_deprecated - msg: >- - '.dynamicType' is deprecated. Use 'type(of: ...)' instead - -- id: pound_assert_disabled - msg: >- - #assert is an experimental feature that is currently disabled - -- id: pound_assert_expected_lparen - msg: >- - expected '(' in #assert directive - -- id: pound_assert_expected_rparen - msg: >- - expected ')' in #assert directive - -- id: pound_assert_expected_expression - msg: >- - expected a condition expression - -- id: pound_assert_expected_string_literal - msg: >- - expected a string literal - -- id: replace_equal_with_colon_for_value - msg: >- - '=' has been replaced with ':' in attribute arguments - -- id: expected_attribute_name - msg: >- - expected an attribute name - -- id: unknown_attribute - msg: >- - unknown attribute '%0' - -- id: unexpected_lparen_in_attribute - msg: >- - unexpected '(' in attribute '%0' - -- id: duplicate_attribute - msg: >- - duplicate %select{attribute|modifier}0 - -- id: previous_attribute - msg: >- - %select{attribute|modifier}0 already specified here - -- id: mutually_exclusive_attrs - msg: >- - '%0' contradicts previous %select{attribute|modifier}2 '%1' - -- id: invalid_infix_on_func - msg: >- - 'infix' modifier is not required or allowed on func declarations - -- id: expected_in_attribute_list - msg: >- - expected ']' or ',' in attribute list - -- id: type_attribute_applied_to_decl - msg: >- - attribute can only be applied to types, not declarations - -- id: decl_attribute_applied_to_type - msg: >- - attribute can only be applied to declarations, not types - -- id: attr_expected_lparen - msg: >- - expected '(' in '%0' %select{attribute|modifier}1 - -- id: attr_expected_rparen - msg: >- - expected ')' in '%0' %select{attribute|modifier}1 - -- id: attr_expected_comma - msg: >- - expected ',' in '%0' %select{attribute|modifier}1 - -- id: attr_expected_string_literal - msg: >- - expected string literal in '%0' attribute - -- id: attr_missing_label - msg: >- - missing label '%0:' in '@%1' attribute - -- id: attr_expected_label - msg: >- - expected label '%0:' in '@%1' attribute - -- id: alignment_must_be_positive_integer - msg: >- - alignment value must be a positive integer literal - -- id: swift_native_objc_runtime_base_must_be_identifier - msg: >- - @_swift_native_objc_runtime_base class name must be an identifier - -- id: objc_runtime_name_must_be_identifier - msg: >- - @_objcRuntimeName name must be an identifier - -- id: attr_only_at_non_local_scope - msg: >- - attribute '%0' can only be used in a non-local scope - -- id: projection_value_property_not_identifier - msg: >- - @_projectedValueProperty name must be an identifier - -- id: attr_access_expected_set - msg: >- - expected 'set' as subject of '%0' modifier - -- id: attr_access_expected_spi_name - msg: >- - expected an SPI identifier as subject of the '@_spi' attribute - -- id: attr_renamed - msg: >- - '@%0' has been renamed to '@%1' - -- id: attr_renamed_warning - msg: >- - '@%0' has been renamed to '@%1' - -- id: attr_name_close_match - msg: >- - no attribute named '@%0'; did you mean '@%1'? - -- id: attr_unsupported_on_target - msg: >- - attribute '%0' is unsupported on target '%1' - -- id: attr_availability_platform - msg: >- - expected platform name or '*' for '%0' attribute - -- id: attr_availability_unavailable_deprecated - msg: >- - '%0' attribute cannot be both unconditionally 'unavailable' and - 'deprecated' - -- id: attr_availability_invalid_duplicate - msg: >- - '%0' argument has already been specified - -- id: attr_availability_unknown_platform - msg: >- - unknown platform '%0' for attribute '%1' - -- id: attr_availability_invalid_renamed - msg: >- - 'renamed' argument of '%0' attribute must be an operator, identifier, or - full function name, optionally prefixed by a type name - -- id: attr_availability_expected_option - msg: >- - expected '%0' option such as 'unavailable', 'introduced', 'deprecated', - 'obsoleted', 'message', or 'renamed' - -- id: attr_availability_expected_equal - msg: >- - expected ':' after '%1' in '%0' attribute - -- id: attr_availability_expected_version - msg: >- - expected version number in '%0' attribute - -- id: attr_availability_platform_agnostic_expected_option - msg: >- - expected 'introduced', 'deprecated', or 'obsoleted' in '%0' attribute for - platform '%1' - -- id: attr_availability_platform_agnostic_expected_deprecated_version - msg: >- - expected version number with 'deprecated' in '%0' attribute for platform - '%1' - -- id: attr_availability_platform_agnostic_infeasible_option - msg: >- - '%0' cannot be used in '%1' attribute for platform '%2' - -- id: attr_availability_nonspecific_platform_unexpected_version - msg: >- - unexpected version number in '%0' attribute for non-specific platform '*' - -- id: originally_defined_in_missing_rparen - msg: >- - expected ')' in @_originallyDefinedIn argument list - -- id: originally_defined_in_unrecognized_platform - msg: >- - unrecognized platform name in @_originallyDefinedIn argument list - -- id: originally_defined_in_unrecognized_property - msg: >- - unrecognized property in @_originallyDefinedIn argument list - -- id: originally_defined_in_need_original_module_name - msg: >- - expected 'module: "original"' in the first argument to - @_originallyDefinedIn - -- id: originally_defined_in_need_nonempty_module_name - msg: >- - original module name cannot be empty in @_originallyDefinedIn - -- id: originally_defined_in_need_platform_version - msg: >- - expected at least one platform version in @_originallyDefinedIn - -- id: originally_defined_in_major_minor_only - msg: >- - @_originallyDefinedIn only uses major and minor version number - -- id: originally_defined_in_missing_platform_name - msg: >- - * as platform name has no effect - -- id: convention_attribute_expected_lparen - msg: >- - expected '(' after 'convention' attribute - -- id: convention_attribute_expected_name - msg: >- - expected convention name identifier in 'convention' attribute - -- id: convention_attribute_expected_rparen - msg: >- - expected ')' after convention name for 'convention' attribute - -- id: convention_attribute_ctype_expected_label - msg: >- - expected 'cType' label in 'convention' attribute - -- id: convention_attribute_ctype_expected_colon - msg: >- - expected ':' after 'cType' for 'convention' attribute - -- id: convention_attribute_ctype_expected_string - msg: >- - expected string literal containing clang type for 'cType' in 'convention' - attribute - -- id: convention_attribute_witness_method_expected_colon - msg: >- - expected ':' after 'witness_method' for 'convention' attribute - -- id: convention_attribute_witness_method_expected_protocol - msg: >- - expected protocol name in 'witness_method' 'convention' attribute - -- id: attr_objc_missing_colon - msg: >- - missing ':' after selector piece in @objc attribute - -- id: attr_objc_expected_rparen - msg: >- - expected ')' after name for @objc - -- id: attr_objc_empty_name - msg: >- - expected name within parentheses of @objc attribute - -- id: attr_dynamic_replacement_expected_rparen - msg: >- - expected ')' after function name for @_dynamicReplacement - -- id: attr_dynamic_replacement_expected_function - msg: >- - expected a function name in @_dynamicReplacement(for:) - -- id: attr_dynamic_replacement_expected_for - msg: >- - expected 'for' in '_dynamicReplacement' attribute - -- id: attr_dynamic_replacement_expected_colon - msg: >- - expected ':' after @_dynamicReplacement(for - -- id: attr_type_eraser_expected_type_name - msg: >- - expected a type name in @_typeEraser() - -- id: attr_type_eraser_expected_rparen - msg: >- - expected ')' after type name for @_typeEraser - -- id: attr_private_import_expected_rparen - msg: >- - expected ')' after function name for @_private - -- id: attr_private_import_expected_sourcefile - msg: >- - expected 'sourceFile' in '_private' attribute - -- id: attr_private_import_expected_sourcefile_name - msg: >- - expected a source file name in @_private(sourceFile:) - -- id: attr_private_import_expected_colon - msg: >- - expected ':' after @_private(sourceFile - -- id: opened_attribute_expected_lparen - msg: >- - expected '(' after 'opened' attribute - -- id: opened_attribute_id_value - msg: >- - known id for 'opened' attribute must be a UUID string - -- id: opened_attribute_expected_rparen - msg: >- - expected ')' after id value for 'opened' attribute - -- id: optimization_attribute_expect_option - msg: >- - expected '%0' option such as '%1' - -- id: optimization_attribute_unknown_option - msg: >- - unknown option '%0' for attribute '%1' - -- id: effects_attribute_expect_option - msg: >- - expected '%0' option (readnone, readonly, readwrite) - -- id: effects_attribute_unknown_option - msg: >- - unknown option '%0' for attribute '%1' - -- id: attr_unowned_invalid_specifier - msg: >- - expected 'safe' or 'unsafe' - -- id: attr_unowned_expected_rparen - msg: >- - expected ')' after specifier for 'unowned' - -- id: attr_warn_unused_result_removed - msg: >- - 'warn_unused_result' attribute behavior is now the default - -- id: attr_warn_unused_result_expected_rparen - msg: >- - expected ')' after 'warn_unused_result' attribute - -- id: attr_specialize_missing_colon - msg: >- - missing ':' after %0 in '_specialize' attribute - -- id: attr_specialize_missing_comma - msg: >- - missing ',' in '_specialize' attribute - -- id: attr_specialize_unknown_parameter_name - msg: >- - unknown parameter %0 in '_specialize attribute' - -- id: attr_specialize_expected_bool_value - msg: >- - expected a boolean true or false value in '_specialize' attribute - -- id: attr_specialize_export_true_no_op - msg: >- - 'exported: true' has no effect in '_specialize' attribute - -- id: attr_specialize_missing_parameter_label_or_where_clause - msg: >- - expected a parameter label or a where clause in '_specialize' attribute - -- id: attr_specialize_parameter_already_defined - msg: >- - parameter '%0' was already defined in '_specialize' attribute - -- id: attr_specialize_expected_partial_or_full - msg: >- - expected 'partial' or 'full' as values of the 'kind' parameter in - '_specialize' attribute - -- id: attr_implements_expected_member_name - msg: >- - expected a member name as second parameter in '_implements' attribute - -- id: attr_differentiable_expected_parameter_list - msg: >- - expected a list of parameters to differentiate with respect to - -- id: attr_differentiable_use_wrt_not_withrespectto - msg: >- - use 'wrt:' to specify parameters to differentiate with respect to - -- id: attr_differentiable_expected_label - msg: >- - expected 'wrt:' or 'where' in '@differentiable' attribute - -- id: attr_differentiable_unexpected_argument - msg: >- - unexpected argument '%0' in '@differentiable' attribute - -- id: expected_colon_after_label - msg: >- - expected a colon ':' after '%0' - -- id: diff_params_clause_expected_parameter - msg: >- - expected a parameter, which can be a function parameter name, parameter - index, or 'self' - -- id: diff_params_clause_expected_parameter_unnamed - msg: >- - expected a parameter, which can be a function parameter index or 'self' - -- id: autodiff_attr_expected_original_decl_name - msg: >- - expected an original function name - -- id: sil_autodiff_expected_lsquare - msg: >- - expected '[' to start the %0 - -- id: sil_autodiff_expected_rsquare - msg: >- - expected ']' to complete the %0 - -- id: sil_autodiff_expected_index_list - msg: >- - expected a space-separated list of indices, e.g. '0 1' - -- id: sil_autodiff_expected_index_list_label - msg: >- - expected label '%0' in index list - -- id: sil_autodiff_expected_parameter_index - msg: >- - expected the index of a parameter to differentiate with respect to - -- id: sil_autodiff_expected_result_index - msg: >- - expected the index of a result to differentiate from - -- id: sil_inst_autodiff_operand_list_expected_lbrace - msg: >- - expected '{' to start a derivative function list - -- id: sil_inst_autodiff_operand_list_expected_comma - msg: >- - expected ',' between operands in a derivative function list - -- id: sil_inst_autodiff_operand_list_expected_rbrace - msg: >- - expected '}' to start a derivative function list - -- id: sil_inst_autodiff_expected_differentiable_extractee_kind - msg: >- - expected an extractee kind attribute, which can be one of '[original]', - '[jvp]', and '[vjp]' - -- id: sil_inst_autodiff_expected_linear_extractee_kind - msg: >- - expected an extractee kind attribute, which can be one of '[original]' - and '[transpose]' - -- id: sil_inst_autodiff_expected_function_type_operand - msg: >- - expected an operand of a function type - -- id: sil_inst_autodiff_expected_differentiability_witness_kind - msg: >- - expected a differentiability witness kind, which can be one of '[jvp]', - '[vjp]', or '[transpose]' - -- id: sil_inst_autodiff_invalid_witness_generic_signature - msg: >- - expected witness_generic signature '%0' does not have same generic - parameters as original function generic signature '%1' - -- id: expected_rangle_generics_param - msg: >- - expected '>' to complete generic parameter list - -- id: expected_generics_parameter_name - msg: >- - expected an identifier to name generic parameter - -- id: unexpected_class_constraint - msg: >- - 'class' constraint can only appear on protocol declarations - -- id: suggest_anyobject - msg: >- - did you mean to write an 'AnyObject' constraint? - -- id: expected_generics_type_restriction - msg: >- - expected a class type or protocol-constrained type restricting %0 - -- id: requires_single_equal - msg: >- - use '==' for same-type requirements rather than '=' - -- id: requires_comma - msg: >- - expected ',' to separate the requirements of this 'where' clause - -- id: expected_requirement_delim - msg: >- - expected ':' or '==' to indicate a conformance or same-type requirement - -- id: redundant_class_requirement - msg: >- - redundant 'class' requirement - -- id: late_class_requirement - msg: >- - 'class' must come first in the requirement list - -- id: where_inside_brackets - msg: >- - 'where' clause next to generic parameters is obsolete, must be written - following the declaration's type - -- id: unsupported_conditional_compilation_binary_expression - msg: >- - expected '&&' or '||' expression - -- id: unsupported_conditional_compilation_unary_expression - msg: >- - expected unary '!' expression - -- id: unsupported_platform_condition_expression - msg: >- - unexpected platform condition (expected 'os', 'arch', or 'swift') - -- id: platform_condition_expected_one_argument - msg: >- - expected only one argument to platform condition - -- id: unsupported_platform_runtime_condition_argument - msg: >- - unexpected argument for the '_runtime' condition; expected '_Native' or - '_ObjC' - -- id: unsupported_platform_condition_argument - msg: >- - unexpected platform condition argument: expected %0 - -- id: unsupported_conditional_compilation_expression_type - msg: >- - invalid conditional compilation expression - -- id: unsupported_conditional_compilation_integer - msg: >- - '%0' is not a valid conditional compilation expression, use '%1' - -- id: version_component_not_number - msg: >- - version component contains non-numeric characters - -- id: compiler_version_too_many_components - msg: >- - compiler version must not have more than five components - -- id: unused_compiler_version_component - msg: >- - the second version component is not used for comparison - -- id: empty_version_component - msg: >- - found empty version component - -- id: compiler_version_component_out_of_range - msg: >- - compiler version component out of range: must be in [0, %0] - -- id: empty_version_string - msg: >- - version requirement is empty - -- id: unknown_platform_condition_argument - msg: >- - unknown %0 for build configuration '%1' - -- id: renamed_platform_condition_argument - msg: >- - '%0' has been renamed to '%1' - -- id: likely_simulator_platform_condition - msg: >- - platform condition appears to be testing for simulator environment; use - 'targetEnvironment(simulator)' instead - -- id: avail_query_expected_condition - msg: >- - expected availability condition - -- id: avail_query_expected_platform_name - msg: >- - expected platform name - -- id: avail_query_expected_version_number - msg: >- - expected version number - -- id: avail_query_expected_rparen - msg: >- - expected ')' in availability query - -- id: avail_query_unrecognized_platform_name - msg: >- - unrecognized platform name %0 - -- id: avail_query_disallowed_operator - msg: >- - '%0' cannot be used in an availability condition - -- id: avail_query_argument_and_shorthand_mix_not_allowed - msg: >- - '%0' can't be combined with shorthand specification '%1' - -- id: avail_query_meant_introduced - msg: >- - did you mean to specify an introduction version? - -- id: avail_query_version_comparison_not_needed - msg: >- - version comparison not needed - -- id: availability_query_wildcard_required - msg: >- - must handle potential future platforms with '*' - -- id: availability_must_occur_alone - msg: >- - '%0' version-availability must be specified alone - -- id: pound_available_swift_not_allowed - msg: >- - Swift language version checks not allowed in #available(...) - -- id: pound_available_package_description_not_allowed - msg: >- - PackageDescription version checks not allowed in #available(...) - -- id: availability_query_repeated_platform - msg: >- - version for '%0' already specified - -- id: unknown_syntax_entity - msg: >- - unknown %0 syntax exists in the source - -- id: expected_argument_label_followed_by_closure_literal - msg: >- - expected an argument label followed by a closure literal - -- id: expected_closure_literal - msg: >- - expected a closure literal - -- id: expected_multiple_closures_block_rbrace - msg: >- - expected '}' at the end of a trailing closures block - -- id: decl_declared_here - msg: >- - %0 declared here - -- id: kind_declared_here - msg: >- - %0 declared here - -- id: implicit_member_declared_here - msg: >- - %1 '%0' is implicitly declared - -- id: extended_type_declared_here - msg: >- - extended type declared here - -- id: opaque_return_type_declared_here - msg: >- - opaque return type declared here - -- id: ambiguous_member_overload_set - msg: >- - ambiguous reference to member %0 - -- id: ambiguous_reference_to_decl - msg: >- - ambiguous reference to %0 %1 - -- id: no_overloads_match_exactly_in_call - msg: >- - no exact matches in %select{reference|call}0 to %1 %select{%3|}2 - -- id: candidate_partial_match - msg: >- - candidate has partially matching parameter list %0 - -- id: could_not_find_value_subscript - msg: >- - value of type %0 has no subscripts - -- id: could_not_find_tuple_member - msg: >- - value of tuple type %0 has no member %1 - -- id: could_not_find_value_member - msg: >- - value of type %0 has no member %1 - -- id: could_not_find_value_member_corrected - msg: >- - value of type %0 has no member %1; did you mean %2? - -- id: could_not_find_value_dynamic_member_corrected - msg: >- - value of type %0 has no dynamic member %2 using key path from root type - %1; did you mean %3? - -- id: could_not_find_value_dynamic_member - msg: >- - value of type %0 has no dynamic member %2 using key path from root type - %1 - -- id: cannot_infer_contextual_keypath_type_specify_root - msg: >- - cannot infer key path type from context; consider explicitly specifying a - root type - -- id: cannot_infer_keypath_root_anykeypath_context - msg: >- - 'AnyKeyPath' does not provide enough context for root type to be - inferred; consider explicitly specifying a root type - -- id: could_not_find_type_member - msg: >- - type %0 has no member %1 - -- id: could_not_find_type_member_corrected - msg: >- - type %0 has no member %1; did you mean %2? - -- id: could_not_find_subscript_member_did_you_mean - msg: >- - value of type %0 has no property or method named 'subscript'; did you - mean to use the subscript operator? - -- id: could_not_find_subscript_member_tuple - msg: >- - cannot access element using subscript for tuple type %0; use '.' notation instead - -- id: could_not_find_subscript_member_tuple_did_you_mean_use_dot - msg: >- - cannot access element using subscript for tuple type %0; did you mean to use '.%1'? - -- id: could_not_find_enum_case - msg: >- - enum type %0 has no case %1; did you mean %2? - -- id: did_you_mean_raw_type - msg: >- - did you mean to specify a raw type on the enum declaration? - -- id: did_you_mean_generic_param_as_conformance - msg: >- - did you mean to declare %0 as a protocol conformance for %1? - -- id: any_as_anyobject_fixit - msg: >- - cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more - specific type to access members - -- id: expected_argument_in_contextual_member - msg: >- - member %0 expects argument of type %1 - -- id: expected_parens_in_contextual_member - msg: >- - member %0 is a function; did you mean to call it? - -- id: expected_result_in_contextual_member - msg: >- - member %0 in %2 produces result of type %1, but context expects %2 - -- id: unexpected_arguments_in_enum_case - msg: >- - enum case %0 has no associated values - -- id: could_not_use_type_member_on_instance - msg: >- - static member %1 cannot be used on instance of type %0 - -- id: could_not_use_enum_element_on_instance - msg: >- - enum case %0 cannot be used as an instance member - -- id: could_not_use_type_member_on_protocol_metatype - msg: >- - static member %1 cannot be used on protocol metatype %0 - -- id: could_not_use_instance_member_on_type - msg: >- - instance member %1%select{| of type %2}3 - cannot be used on%select{| instance of nested}3 type %0 - -- id: could_not_use_member_on_existential - msg: >- - member %1 cannot be used on value of protocol type %0; use a generic - constraint instead - -- id: candidate_inaccessible - msg: >- - %0 is inaccessible due to - '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level - -- id: note_candidate_inaccessible - msg: >- - %0 is inaccessible due to - '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level - -- id: init_candidate_inaccessible - msg: >- - %0 initializer is inaccessible due to - '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level - -- id: cannot_pass_rvalue_mutating_subelement - msg: >- - cannot use mutating member on immutable value: %0 - -- id: cannot_pass_rvalue_mutating - msg: >- - cannot use mutating member on immutable value of type %0 - -- id: cannot_pass_rvalue_mutating_getter_subelement - msg: >- - cannot use mutating getter on immutable value: %0 - -- id: cannot_pass_rvalue_mutating_getter - msg: >- - cannot use mutating getter on immutable value of type %0 - -- id: expression_too_complex - msg: >- - the compiler is unable to type-check this expression in reasonable time; - try breaking up the expression into distinct sub-expressions - -- id: value_type_comparison_with_nil_illegal_did_you_mean - msg: >- - value of type %0 cannot be compared by reference; did you mean to compare - by value? - -- id: value_type_comparison_with_nil_illegal - msg: >- - type %0 is not optional, value can never be nil - -- id: cannot_match_expr_pattern_with_value - msg: >- - expression pattern of type %0 cannot match values of type %1 - -- id: cannot_match_expr_tuple_pattern_with_nontuple_value - msg: >- - tuple pattern cannot match values of non-tuple type %0 - -- id: cannot_match_unresolved_expr_pattern_with_value - msg: >- - pattern cannot match values of type %0 - -- id: cannot_reference_compare_types - msg: >- - cannot check reference equality of functions; operands here have types %1 - and %2 - -- id: cannot_apply_binop_to_args - msg: >- - binary operator '%0' cannot be applied to operands of type %1 and %2 - -- id: cannot_apply_binop_to_same_args - msg: >- - binary operator '%0' cannot be applied to two %1 operands - -- id: cannot_apply_unop_to_arg - msg: >- - unary operator '%0' cannot be applied to an operand of type %1 - -- id: cannot_apply_lvalue_unop_to_subelement - msg: >- - cannot pass immutable value to mutating operator: %0 - -- id: cannot_apply_lvalue_unop_to_rvalue - msg: >- - cannot pass immutable value of type %0 to mutating operator - -- id: cannot_apply_lvalue_binop_to_subelement - msg: >- - left side of mutating operator isn't mutable: %0 - -- id: cannot_apply_lvalue_binop_to_rvalue - msg: >- - left side of mutating operator has immutable type %0 - -- id: cannot_subscript_base - msg: >- - cannot subscript a value of type %0 - -- id: cannot_subscript_ambiguous_base - msg: >- - cannot subscript a value of incorrect or ambiguous type - -- id: cannot_subscript_nil_literal - msg: >- - cannot subscript a nil literal value - -- id: conditional_cast_from_nil - msg: >- - nil literal cannot be the source of a conditional cast - -- id: cannot_pass_rvalue_inout_subelement - msg: >- - cannot pass immutable value as inout argument: %0 - -- id: cannot_pass_rvalue_inout_converted - msg: >- - inout argument could be set to a value with a type other than %0; use a - value declared as type %1 instead - -- id: inout_change_var_type_if_possible - msg: >- - change variable type to %1 if it doesn't need to be declared as %0 - -- id: cannot_pass_rvalue_inout - msg: >- - cannot pass immutable value of type %0 as inout argument - -- id: cannot_provide_default_value_inout - msg: >- - cannot provide default value to inout parameter %0 - -- id: cannot_call_with_params - msg: >- - cannot invoke %select{|initializer for type }2'%0' with an argument list - of type '%1' - -- id: cannot_call_non_function_value - msg: >- - cannot call value of non-function type %0 - -- id: no_candidates_match_result_type - msg: >- - no '%0' candidates produce the expected contextual result type %1 - -- id: no_candidates_match_argument_type - msg: >- - no '%0' candidates produce the expected type %1 for parameter #%2 - -- id: cannot_infer_closure_parameter_type - msg: >- - unable to infer type of a closure parameter %0 in the current context - -- id: cannot_infer_closure_type - msg: >- - unable to infer closure type in the current context - -- id: cannot_infer_closure_result_type - msg: >- - unable to infer%select{ complex|}0 closure return type; add explicit type - to disambiguate - -- id: incorrect_explicit_closure_result - msg: >- - declared closure result %0 is incompatible with contextual type %1 - -- id: suggest_expected_match - msg: >- - %select{expected an argument list|produces result}0 of type '%1' - -- id: suggest_partial_overloads - msg: >- - overloads for '%1' exist with these %select{partially matching parameter - lists|result types}0: %2 - -- id: no_binary_op_overload_for_enum_with_payload - msg: >- - binary operator '%0' cannot be synthesized for enums with associated - values - -- id: cannot_convert_initializer_value - msg: >- - cannot convert value of type %0 to specified type %1 - -- id: cannot_convert_initializer_value_protocol - msg: >- - value of type %0 does not conform to specified type %1 - -- id: cannot_convert_initializer_value_anyobject - msg: >- - value of type %0 expected to be instance of class or class-constrained - type - -- id: cannot_convert_initializer_value_nil - msg: >- - 'nil' cannot initialize specified type %0 - -- id: cannot_convert_to_return_type - msg: >- - cannot convert return expression of type %0 to return type %1 - -- id: cannot_convert_to_return_type_protocol - msg: >- - return expression of type %0 does not conform to %1 - -- id: cannot_convert_return_type_to_anyobject - msg: >- - return expression of type %0 expected to be an instance of a class or - class-constrained type - -- id: cannot_convert_to_return_type_nil - msg: >- - 'nil' is incompatible with return type %0 - -- id: cannot_convert_thrown_type - msg: >- - thrown expression type %0 does not conform to 'Error' - -- id: cannot_throw_error_code - msg: >- - thrown error code type %0 does not conform to 'Error'; construct an %1 - instance - -- id: bad_yield_count - msg: >- - expected %0 yield value(s) - -- id: cannot_throw_nil - msg: >- - cannot infer concrete Error for thrown 'nil' value - -- id: cannot_convert_raw_initializer_value - msg: >- - cannot convert value of type %0 to raw type %1 - -- id: cannot_convert_raw_initializer_value_nil - msg: >- - cannot convert 'nil' to raw type %0 - -- id: cannot_convert_default_arg_value - msg: >- - default argument value of type %0 cannot be converted to type %1 - -- id: cannot_convert_default_arg_value_protocol - msg: >- - default argument value of type %0 does not conform to %1 - -- id: cannot_convert_default_arg_value_nil - msg: >- - nil default argument value cannot be converted to type %0 - -- id: cannot_convert_argument_value - msg: >- - cannot convert value of type %0 to expected argument type %1 - -- id: candidate_has_invalid_argument_at_position - msg: >- - candidate expects %select{|in-out }2value of type %0 for parameter #%1 - -- id: cannot_convert_array_to_variadic - msg: >- - cannot pass array of type %0 as variadic arguments of type %1 - -- id: candidate_would_match_array_to_variadic - msg: >- - candidate would match if array elements were passed as variadic arguments - of type %0 - -- id: suggest_pass_elements_directly - msg: >- - remove brackets to pass array elements directly - -- id: cannot_convert_argument_value_generic - msg: >- - cannot convert value of type %0 (%1) to expected argument type %2 (%3) - -- id: conflicting_arguments_for_generic_parameter - msg: >- - conflicting arguments to generic parameter %0 (%1) - -- id: cannot_pass_type_to_non_ephemeral - msg: >- - cannot pass %0 to parameter; argument %1 must be a pointer that outlives - the call%select{| to %3}2 - -- id: cannot_pass_type_to_non_ephemeral_warning - msg: >- - passing %0 to parameter, but argument %1 should be a pointer that - outlives the call%select{| to %3}2 - -- id: cannot_use_inout_non_ephemeral - msg: >- - cannot use inout expression here; argument %0 must be a pointer that - outlives the call%select{| to %2}1 - -- id: cannot_use_inout_non_ephemeral_warning - msg: >- - inout expression creates a temporary pointer, but argument %0 should be a - pointer that outlives the call%select{| to %2}1 - -- id: cannot_construct_dangling_pointer - msg: >- - initialization of %0 results in a dangling %select{|buffer }1pointer - -- id: cannot_construct_dangling_pointer_warning - msg: >- - initialization of %0 results in a dangling %select{|buffer }1pointer - -- id: ephemeral_pointer_argument_conversion_note - msg: >- - implicit argument conversion from %0 to %1 produces a pointer valid only - for the duration of the call%select{| to %3}2 - -- id: ephemeral_use_with_unsafe_pointer - msg: >- - use 'withUnsafe%select{Bytes|MutableBytes|Pointer|MutablePointer}0' in - order to explicitly convert argument to %select{buffer |buffer ||}0pointer - valid for a defined scope - -- id: ephemeral_use_string_with_c_string - msg: >- - use the 'withCString' method on String in order to explicitly convert - argument to pointer valid for a defined scope - -- id: ephemeral_use_array_with_unsafe_buffer - msg: >- - use the - 'withUnsafe%select{Bytes|MutableBytes|BufferPointer|MutableBufferPointer}0' - method on Array in order to explicitly convert argument to buffer pointer valid - for a defined scope - -- id: candidate_performs_illegal_ephemeral_conv - msg: >- - candidate expects pointer that outlives the call for parameter #%0 - -- id: cannot_convert_argument_value_protocol - msg: >- - argument type %0 does not conform to expected type %1 - -- id: cannot_convert_argument_value_anyobject - msg: >- - argument type %0 expected to be an instance of a class or - class-constrained type - -- id: cannot_convert_argument_value_nil - msg: >- - 'nil' is not compatible with expected argument type %0 - -- id: cannot_convert_condition_value - msg: >- - cannot convert value of type %0 to expected condition type %1 - -- id: cannot_convert_condition_value_nil - msg: >- - 'nil' is not compatible with expected condition type %0 - -- id: cannot_yield_rvalue_by_reference_same_type - msg: >- - cannot yield immutable value of type %0 as an inout yield - -- id: cannot_yield_rvalue_by_reference - msg: >- - cannot yield immutable value of type %0 as an inout yield of type %1 - -- id: cannot_yield_wrong_type_by_reference - msg: >- - cannot yield reference to storage of type %0 as an inout yield of type %1 - -- id: cannot_convert_yield_value - msg: >- - cannot convert value of type %0 to expected yield type %1 - -- id: cannot_convert_yield_value_protocol - msg: >- - yielded type %0 does not conform to expected type %1 - -- id: cannot_convert_yield_value_nil - msg: >- - nil is not compatible with expected yield type %0 - -- id: cannot_convert_closure_result - msg: >- - cannot convert value of type %0 to closure result type %1 - -- id: cannot_convert_closure_result_protocol - msg: >- - result value of type %0 does not conform to closure result type %1 - -- id: cannot_convert_closure_result_nil - msg: >- - 'nil' is not compatible with closure result type %0 - -- id: cannot_convert_parent_type - msg: >- - cannot convert parent type %0 to expected type %1 - -- id: generic_argument_mismatch - msg: >- - arguments to generic parameter %0 (%1 and %2) are expected to be equal - -- id: destructor_not_accessible - msg: >- - deinitializers cannot be accessed - -- id: cannot_convert_array_element - msg: >- - cannot convert value of type %0 to expected element type %1 - -- id: cannot_convert_array_element_protocol - msg: >- - value of type %0 does not conform to expected element type %1 - -- id: cannot_convert_array_element_nil - msg: >- - 'nil' is not compatible with expected element type %0 - -- id: cannot_convert_dict_key - msg: >- - cannot convert value of type %0 to expected dictionary key type %1 - -- id: cannot_convert_dict_key_protocol - msg: >- - value of type %0 does not conform to expected dictionary key type %1 - -- id: cannot_convert_dict_key_nil - msg: >- - 'nil' is not compatible with expected dictionary key type %0 - -- id: cannot_convert_dict_value - msg: >- - cannot convert value of type %0 to expected dictionary value type %1 - -- id: cannot_convert_dict_value_protocol - msg: >- - value of type %0 does not conform to expected dictionary value type %1 - -- id: cannot_convert_dict_value_nil - msg: >- - 'nil' is not compatible with expected dictionary value type %0 - -- id: cannot_convert_coerce - msg: >- - cannot convert value of type %0 to type %1 in coercion - -- id: cannot_convert_coerce_protocol - msg: >- - value of type %0 does not conform to %1 in coercion - -- id: cannot_convert_coerce_nil - msg: >- - 'nil' is not compatible with type %0 in coercion - -- id: cannot_convert_assign - msg: >- - cannot assign value of type %0 to type %1 - -- id: assign_protocol_conformance_fix_it - msg: >- - add missing conformance to %0 to %1 %2 - -- id: cannot_convert_assign_protocol - msg: >- - value of type %0 does not conform to %1 in assignment - -- id: cannot_convert_assign_anyobject - msg: >- - value of type %0 expected to be an instance of a class or - class-constrained type in assignment - -- id: cannot_convert_assign_nil - msg: >- - 'nil' cannot be assigned to type %0 - -- id: cannot_convert_subscript_assign - msg: >- - cannot assign value of type %0 to subscript of type %1 - -- id: cannot_convert_subscript_assign_protocol - msg: >- - value of type %0 does not conform to %1 in subscript assignment - -- id: cannot_convert_subscript_assign_nil - msg: >- - 'nil' cannot be assigned to subscript of type %0 - -- id: cannot_convert_candidate_result_to_contextual_type - msg: >- - %0 produces %1, not the expected contextual result type %2 - -- id: cannot_convert_sequence_element_value - msg: >- - cannot convert sequence element type %0 to expected type %1 - -- id: cannot_convert_sequence_element_protocol - msg: >- - sequence element type %0 does not conform to expected protocol %1 - -- id: throws_functiontype_mismatch - msg: >- - invalid conversion from throwing function of type %0 to non-throwing - function type %1 - -- id: expr_keypath_no_objc_runtime - msg: >- - '#keyPath' can only be used with the Objective-C runtime - -- id: expression_unused_keypath_result - msg: >- - result of key path is unused - -- id: expr_keypath_non_objc_property - msg: >- - argument of '#keyPath' refers to non-'@objc' property %0 - -- id: expr_keypath_swift3_objc_inference - msg: >- - argument of '#keyPath' refers to property %0 in %1 that depends on - '@objc' inference deprecated in Swift 4 - -- id: expr_keypath_type_of_property - msg: >- - cannot refer to type member %0 within instance of type %1 - -- id: expr_keypath_generic_type - msg: >- - key path cannot refer to generic type %0 - -- id: expr_keypath_not_property - msg: >- - %select{key path|dynamic key path member lookup}2 cannot refer to %0 %1 - -- id: expr_keypath_mutating_getter - msg: >- - %select{key path|dynamic key path member lookup}1 cannot refer to %0, - which has a mutating getter - -- id: expr_keypath_static_member - msg: >- - %select{key path|dynamic key path member lookup}1 cannot refer to static - member %0 - -- id: expr_keypath_enum_case - msg: >- - %select{key path|dynamic key path member lookup}1 cannot refer to enum - case %0 - -- id: expr_keypath_empty - msg: >- - empty key path does not refer to a property - -- id: expr_unsupported_objc_key_path_component - msg: >- - an Objective-C key path cannot contain - %select{BAD|subscript|BAD|BAD|optional-forcing|optional-chaining|BAD} - components - -- id: expr_unsupported_objc_key_path_compound_name - msg: >- - an Objective-C key path cannot reference a declaration with a compound name - -- id: expr_keypath_no_keypath_type - msg: >- - broken standard library: no 'KeyPath' type found - -- id: expr_swift_keypath_invalid_component - msg: >- - invalid component of Swift key path - -- id: expr_swift_keypath_not_starting_with_type - msg: >- - a Swift key path must begin with a type - -- id: expr_swift_keypath_not_starting_with_dot - msg: >- - a Swift key path with contextual root must begin with a leading dot - -- id: expr_smart_keypath_value_covert_to_contextual_type - msg: >- - key path value type %0 cannot be converted to contextual type %1 - -- id: expr_swift_keypath_empty - msg: >- - key path must have at least one component - -- id: expr_string_interpolation_outside_string - msg: >- - string interpolation can only appear inside a string literal - -- id: expr_keypath_subscript_index_not_hashable - msg: >- - subscript index of type %0 in a key path must be Hashable - -- id: expr_smart_keypath_application_type_mismatch - msg: >- - key path of type %0 cannot be applied to a base of type %1 - -- id: expr_keypath_root_type_mismatch - msg: >- - key path with root type %0 cannot be applied to a base of type %1 - -- id: expr_swift_keypath_anyobject_root - msg: >- - the root type of a Swift key path cannot be 'AnyObject' - -- id: expr_keypath_multiparam_func_conversion - msg: >- - cannot convert key path into a multi-argument function type %0 - -- id: expr_deprecated_writable_keypath - msg: >- - forming a writable keypath to property %0 that is read-only in this - context is deprecated and will be removed in a future release - -- id: expr_selector_no_objc_runtime - msg: >- - '#selector' can only be used with the Objective-C runtime - -- id: expr_selector_module_missing - msg: >- - import the 'ObjectiveC' module to use '#selector' - -- id: expr_selector_no_declaration - msg: >- - argument of '#selector' does not refer to an '@objc' method, property, or - initializer - -- id: expr_selector_not_method - msg: >- - argument of '#selector' cannot refer to %select{local|global}0 function %1 - -- id: expr_selector_expected_property - msg: >- - cannot reference %1 %2 as a property; remove '%select{getter|setter}0:' - -- id: expr_selector_not_property - msg: >- - argument of '#selector' cannot refer to %select{variable|parameter}0 %1 - -- id: expr_selector_expected_method - msg: >- - use 'getter:'%select{| or 'setter:'}0 to refer to the Objective-C - getter%select{| or setter}0 of property %1%select{|, respectively}0 - -- id: expr_selector_add_modifier - msg: >- - add '%select{getter|setter}0:' to reference the Objective-C - %select{getter|setter}0 for %1 - -- id: expr_selector_property_not_settable - msg: >- - argument of '#selector(setter:)' refers to non-settable %0 %1 - -- id: expr_selector_property_setter_inaccessible - msg: >- - setter of %0 %1 is inaccessible - -- id: expr_selector_cannot_be_used - msg: >- - cannot use %0 as a selector because protocol %1 is not exposed to - Objective-C - -- id: expr_selector_not_objc - msg: >- - argument of '#selector' refers to %0 %1 that is not exposed to Objective-C - -- id: make_decl_objc - msg: >- - add '@objc' to expose this %0 to Objective-C - -- id: expr_selector_swift3_objc_inference - msg: >- - argument of '#selector' refers to %0 %1 in %2 that depends on '@objc' - inference deprecated in Swift 4 - -- id: selector_literal_invalid - msg: >- - string literal is not a valid Objective-C selector - -- id: selector_literal_undeclared - msg: >- - no method declared with Objective-C selector %0 - -- id: selector_literal_deprecated - msg: >- - use of string literal for Objective-C selectors is deprecated; use - '#selector' or explicitly construct a 'Selector' - -- id: selector_literal_deprecated_suggest - msg: >- - use of string literal for Objective-C selectors is deprecated; use - '#selector' instead - -- id: selector_construction_suggest - msg: >- - use '#selector' instead of explicitly constructing a 'Selector' - -- id: selector_construction_suppress_warning - msg: >- - wrap the selector name in parentheses to suppress this warning - -- id: cannot_return_value_from_void_func - msg: >- - unexpected non-void return value in void function - -- id: add_return_type_note - msg: >- - did you mean to add a return type? - -- id: sema_no_import - msg: >- - no such module '%0' - -- id: sema_no_import_target - msg: >- - could not find module '%0' for target '%1'; found: %2 - -- id: sema_no_import_repl - msg: >- - no such module '%0' - -- id: sema_no_import_no_sdk - msg: >- - did you forget to set an SDK using -sdk or SDKROOT? - -- id: sema_no_import_no_sdk_xcrun - msg: >- - use "xcrun swiftc" to select the default macOS SDK installed with Xcode - -- id: sema_import_current_module - msg: >- - this file is part of module %0; ignoring import - -- id: sema_import_current_module_with_file - msg: >- - file '%0' is part of module %1; ignoring import - -- id: sema_opening_import - msg: >- - opening import file for module %0: %1 - -- id: serialization_load_failed - msg: >- - failed to load module '%0' - -- id: module_interface_build_failed - msg: >- - failed to build module '%0' from its module interface; %select{the - compiler that produced it, '%2', may have used features that aren't - supported by this compiler, '%3'|it may have been damaged - or it may have triggered a bug in the Swift compiler when it was produced}1 - -- id: serialization_malformed_module - msg: >- - malformed compiled module: %0 - -- id: serialization_module_too_new - msg: >- - compiled module was created by a newer version of the compiler: %0 - -- id: serialization_module_language_version_mismatch - msg: >- - module compiled with Swift %0 cannot be imported by the Swift %1 - compiler: %2 - -- id: serialization_module_too_old - msg: >- - compiled module was created by an older version of the compiler; rebuild - %0 and try again: %1 - -- id: serialization_missing_single_dependency - msg: >- - missing required module '%0' - -- id: serialization_missing_dependencies - msg: >- - missing required modules: %0 - -- id: serialization_circular_dependency - msg: >- - circular dependency between modules '%0' and %1 - -- id: serialization_missing_underlying_module - msg: >- - cannot load underlying module for %0 - -- id: serialization_name_mismatch - msg: >- - cannot load module '%0' as '%1' - -- id: serialization_name_mismatch_repl - msg: >- - cannot load module '%0' as '%1' - -- id: serialization_target_incompatible - msg: >- - module %0 was created for incompatible target %1: %2 - -- id: serialization_target_incompatible_repl - msg: >- - module %0 was created for incompatible target %1: %2 - -- id: serialization_target_too_new - msg: >- - compiling for %0 %1, but module %2 has a minimum deployment target of %0 - %3: %4 - -- id: serialization_target_too_new_repl - msg: >- - compiling for %0 %1, but module %2 has a minimum deployment target of %0 - %3: %4 - -- id: serialization_fatal - msg: >- - fatal error encountered while reading from module '%0'; please file a bug - report with your project and the crash log - -- id: serialization_misc_version - msg: >- - module '%0' full misc version is '%1' - -- id: serialization_compatibility_version_mismatch - msg: >- - compiling as Swift %0, with '%1' built as Swift %2 (this is supported but - may expose additional compiler issues) - -- id: reserved_member_name - msg: >- - type member must not be named %0, since it would conflict with the - 'foo.%1' expression - -- id: invalid_redecl - msg: >- - invalid redeclaration of %0 - -- id: invalid_redecl_init - msg: >- - invalid redeclaration of synthesized %select{|memberwise }1%0 - -- id: invalid_redecl_implicit - msg: >- - invalid redeclaration of synthesized %select{%0|implementation for - protocol requirement}1 %2 - -- id: invalid_redecl_swift5_warning - msg: >- - redeclaration of %0 is deprecated and will be an error in Swift 5 - -- id: invalid_redecl_prev - msg: >- - %0 previously declared here - -- id: invalid_redecl_implicit_wrapper - msg: >- - %0 synthesized for property wrapper %select{projected value|backing - storage}1 - -- id: ambiguous_type_base - msg: >- - %0 is ambiguous for type lookup in this context - -- id: invalid_member_type - msg: >- - %0 is not a member type of %1 - -- id: invalid_member_type_suggest - msg: >- - %0 does not have a member type named %1; did you mean %2? - -- id: invalid_member_reference - msg: >- - %0 %1 is not a member type of %2 - -- id: ambiguous_member_type - msg: >- - ambiguous type name %0 in %1 - -- id: no_module_type - msg: >- - no type named %0 in module %1 - -- id: ambiguous_module_type - msg: >- - ambiguous type name %0 in module %1 - -- id: use_nonmatching_operator - msg: >- - %0 is not a %select{binary|prefix unary|postfix unary}1 operator - -- id: unsupported_recursion_in_associated_type_reference - msg: >- - unsupported recursion for reference to %select{associated type|type - alias}0 %1 of type %2 - -- id: broken_associated_type_witness - msg: >- - reference to invalid %select{associated type|type alias}0 %1 of type %2 - -- id: unspaced_binary_operator_fixit - msg: >- - missing whitespace between %0 and %1 operators - -- id: unspaced_binary_operator - msg: >- - ambiguous missing whitespace between unary and binary operators - -- id: unspaced_binary_operators_candidate - msg: >- - could be %select{binary|postfix}2 %0 and %select{prefix|binary}2 %1 - -- id: unspaced_unary_operator - msg: >- - unary operators must not be juxtaposed; parenthesize inner expression - -- id: cannot_find_in_scope - msg: >- - cannot %select{find|find operator}1 %0 in scope - -- id: cannot_find_in_scope_corrected - msg: >- - cannot %select{find|find operator}1 %0 in scope; did you mean '%2'? - -- id: confusable_character - msg: >- - %select{identifier|operator}0 '%1' contains possibly confused characters; - did you mean to use '%2'? -- id: single_confusable_character - msg: >- - %select{identifier|operator}0 '%1' (%2) looks similar to '%3' (%4); did you mean '%3' (%4)?" - -- id: cannot_find_type_in_scope - msg: >- - cannot find type %0 in scope - -- id: cannot_find_type_in_scope_did_you_mean - msg: >- - cannot find type %0 in scope; did you mean to use '%1'? - -- id: note_typo_candidate_implicit_member - msg: >- - did you mean the implicitly-synthesized %1 '%0'? - -- id: note_remapped_type - msg: >- - did you mean to use '%0'? - -- id: note_module_as_type - msg: >- - cannot use module %0 as a type - -- id: use_unknown_object_literal_protocol - msg: >- - cannot deduce protocol for %0 literal - -- id: object_literal_default_type_missing - msg: >- - could not infer type of %0 literal - -- id: object_literal_resolve_import - msg: >- - import %0 to use '%1' as the default %2 literal type - -- id: use_local_before_declaration - msg: >- - use of local variable %0 before its declaration - -- id: unsupported_existential_type - msg: >- - protocol %0 can only be used as a generic constraint because it has Self - or associated type requirements - -- id: decl_does_not_exist_in_module - msg: >- - %select{%error|type|struct|class|enum|protocol|variable|function}0 %1 - does not exist in module %2 - -- id: imported_decl_is_wrong_kind - msg: >- - %0 was imported as '%1', but is %select{%error|a type|a struct|a class|an - enum|a protocol|a variable|a function}2 - -- id: imported_decl_is_wrong_kind_typealias - msg: >- - %0 %1 cannot be imported as '%2' - -- id: ambiguous_decl_in_module - msg: >- - ambiguous name %0 in module %1 - -- id: module_not_testable - msg: >- - module %0 was not compiled for testing - -- id: module_not_compiled_for_private_import - msg: >- - module %0 was not compiled for private import - -- id: import_implementation_cannot_be_exported - msg: >- - module %0 cannot be both exported and implementation-only - -- id: module_not_compiled_with_library_evolution - msg: >- - module %0 was not compiled with library evolution support; using it means - binary compatibility for %1 can't be guaranteed - -- id: cross_import_added - msg: >- - import of %0 and %1 triggered a cross-import of %2 - -- id: ambiguous_operator_decls - msg: >- - ambiguous operator declarations found for operator - -- id: found_this_operator_decl - msg: >- - found this matching operator declaration - -- id: operator_redeclared - msg: >- - operator redeclared - -- id: previous_operator_decl - msg: >- - previous operator declaration here - -- id: declared_operator_without_operator_decl - msg: >- - operator implementation without matching operator declaration - -- id: declared_unary_op_without_attribute - msg: >- - unary operator implementation must have a 'prefix' or 'postfix' modifier - -- id: unary_op_missing_prepos_attribute - msg: >- - %select{prefix|postfix}0 unary operator missing - '%select{prefix|postfix}0' modifier - -- id: unary_operator_declaration_here - msg: >- - %select{prefix|postfix}0 operator found here - -- id: invalid_arg_count_for_operator - msg: >- - operators must have one or two arguments - -- id: operator_in_local_scope - msg: >- - operator functions can only be declared at global or in type scope - -- id: nonstatic_operator_in_nominal - msg: >- - operator %0 declared in type %1 must be 'static' - -- id: nonstatic_operator_in_extension - msg: >- - operator %0 declared in extension%select{| of %2}1 must be 'static' - -- id: nonfinal_operator_in_class - msg: >- - operator %0 declared in non-final class %1 must be 'final' - -- id: operator_in_unrelated_type - msg: >- - member operator %2%select{| of protocol %0}1 must have at least one - argument of type %select{%0|'Self'}1 - -- id: ambiguous_precedence_groups - msg: >- - multiple precedence groups found - -- id: found_this_precedence_group - msg: >- - found this matching precedence group - -- id: unknown_precedence_group - msg: >- - unknown precedence group %0 - -- id: precedence_group_cycle - msg: >- - cycle in '%select{lowerThan|higherThan}0' relation - -- id: higher_than_precedence_group_cycle - msg: >- - cycle in higherThan relation: %0 - -- id: precedence_group_lower_within_module - msg: >- - precedence group cannot be given lower precedence than group in same - module; make the other precedence group higher than this one instead - -- id: precedence_group_redeclared - msg: >- - precedence group redeclared - -- id: previous_precedence_group_decl - msg: >- - previous precedence group declaration here - -- id: circular_reference_through_precedence_group - msg: >- - through reference to precedence group %0 here - -- id: tuple_types_not_convertible_nelts - msg: >- - %0 is not convertible to %1, tuples have a different number of elements - -- id: tuple_types_not_convertible - msg: >- - tuple type %0 is not convertible to tuple type %1 - -- id: invalid_force_unwrap - msg: >- - cannot force unwrap value of non-optional type %0 - -- id: invalid_optional_chain - msg: >- - cannot use optional chaining on non-optional value of type %0 - -- id: if_expr_cases_mismatch - msg: >- - result values in '? :' expression have mismatching types %0 and %1 - -- id: did_not_call_function_value - msg: >- - function value was used as a property; add () to call it - -- id: did_not_call_function - msg: >- - function %0 was used as a property; add () to call it - -- id: did_not_call_method - msg: >- - method %0 was used as a property; add () to call it - -- id: init_not_instance_member_use_assignment - msg: >- - 'init' is a member of the type; use assignment to initalize the value - instead - -- id: init_not_instance_member - msg: >- - 'init' is a member of the type; use 'type(of: ...)' to initialize a new - object of the same dynamic type - -- id: super_initializer_not_in_initializer - msg: >- - 'super.init' cannot be called outside of an initializer - -- id: isa_is_always_true - msg: >- - '%0' test is always true - -- id: isa_is_foreign_check - msg: >- - 'is' test is always true because %0 is a Core Foundation type - -- id: conditional_downcast_coercion - msg: >- - conditional cast from %0 to %1 always succeeds - -- id: literal_conditional_downcast_to_coercion - msg: >- - conditional downcast from literal to %0 always fails; consider using 'as' - coercion - -- id: forced_downcast_noop - msg: >- - forced cast of %0 to same type has no effect - -- id: forced_downcast_coercion - msg: >- - forced cast from %0 to %1 always succeeds; did you mean to use 'as'? - -- id: downcast_same_type - msg: >- - forced cast from %0 to %1 %select{only unwraps optionals|only unwraps and - bridges}3; did you mean to use '%2'%select{| with 'as'}3? - -- id: conditional_downcast_same_type - msg: >- - conditional downcast from %0 to %1 %select{does nothing|is equivalent to - an implicit conversion to an optional %1|is a bridging conversion; - did you mean to use 'as'?}2 - -- id: is_expr_same_type - msg: >- - checking a value with optional type %0 against dynamic type %1 succeeds - whenever the value is non-nil; did you mean to use '!= nil'? - -- id: downcast_to_unrelated - msg: >- - cast from %0 to unrelated type %1 always fails - -- id: downcast_to_unrelated_fixit - msg: >- - did you mean to call %0 with '()'? - -- id: downcast_to_more_optional - msg: >- - cannot downcast from %0 to a more optional type %1 - -- id: optional_chain_noop - msg: >- - optional chain has no effect, expression already produces %0 - -- id: optional_chain_isnt_chaining - msg: >- - '?' must be followed by a call, member lookup, or subscript - -- id: pattern_in_expr - msg: >- - %0 cannot appear in an expression - -- id: note_call_to_operator - msg: >- - in call to operator %0 - -- id: note_call_to_func - msg: >- - in call to function %0 - -- id: note_call_to_subscript - msg: >- - in call to %0 - -- id: note_call_to_initializer - msg: >- - in call to initializer - -- id: note_init_parameter - msg: >- - in initialization of parameter %0 - -- id: missing_nullary_call - msg: >- - function produces expected type %0; did you mean to call it with '()'? - -- id: optional_not_unwrapped - msg: >- - value of optional type %0 must be unwrapped to a value of type %1 - -- id: unwrap_with_default_value - msg: >- - coalesce using '??' to provide a default when the optional value contains - 'nil' - -- id: unwrap_with_force_value - msg: >- - force-unwrap using '!' to abort execution if the optional value contains - 'nil' - -- id: unwrap_iuo_initializer - msg: >- - value inferred to be type %0 when initialized with an implicitly - unwrapped value - -- id: unwrap_with_guard - msg: >- - short-circuit using 'guard' to exit this function early if the optional - value contains 'nil' - -- id: optional_base_not_unwrapped - msg: >- - value of optional type %0 must be unwrapped to refer to member %1 of - wrapped base type %2 - -- id: optional_base_chain - msg: >- - chain the optional using '?' to access member %0 only for non-'nil' base - values - -- id: optional_base_remove_optional_for_keypath_root - msg: >- - use unwrapped type %0 as key path root - -- id: optional_keypath_application_base - msg: >- - use '?' to access key path subscript only for non-'nil' base values - -- id: missing_unwrap_optional_try - msg: >- - value of optional type %0 not unwrapped; did you mean to use 'try!' or - chain with '?'? - -- id: missing_forced_downcast - msg: >- - %0 is not convertible to %1; did you mean to use 'as!' to force downcast? - -- id: coercion_may_fail_warning - msg: >- - coercion from %0 to %1 may fail; use 'as?' or 'as!' instead - -- id: missing_explicit_conversion - msg: >- - %0 is not implicitly convertible to %1; did you mean to use 'as' to - explicitly convert? - -- id: missing_address_of - msg: >- - passing value of type %0 to an inout parameter requires explicit '&' - -- id: missing_address_of_yield - msg: >- - yielding mutable value of type %0 requires explicit '&' - -- id: extraneous_address_of - msg: >- - use of extraneous '&' - -- id: extra_address_of - msg: >- - '&' used with non-inout argument of type %0 - -- id: extra_address_of_unsafepointer - msg: >- - '&' is not allowed passing array value as %0 argument - -- id: cannot_pass_inout_arg_to_subscript - msg: >- - cannot pass an inout argument to a subscript; use - 'withUnsafeMutablePointer' to explicitly convert argument to a pointer - -- id: incorrect_property_wrapper_reference - msg: >- - cannot convert value %0 of type %1 to expected type %2, use - %select{wrapper|wrapped value}3 instead - -- id: incorrect_property_wrapper_reference_member - msg: >- - referencing %0 %1 requires %select{wrapper|wrapped value of type}2 %3 - -- id: missing_init_on_metatype_initialization - msg: >- - initializing from a metatype value must reference 'init' explicitly - -- id: extra_argument_labels - msg: >- - extraneous argument label%select{|s}0 '%1' in %select{call|subscript}2 - -- id: missing_argument_labels - msg: >- - missing argument label%select{|s}0 '%1' in %select{call|subscript}2 - -- id: wrong_argument_labels - msg: >- - incorrect argument label%select{|s}0 in %select{call|subscript}3 (have - '%1', expected '%2') - -- id: argument_out_of_order_named_named - msg: >- - argument %0 must precede argument %1 - -- id: argument_out_of_order_named_unnamed - msg: >- - argument %0 must precede unnamed argument #%1 - -- id: argument_out_of_order_unnamed_named - msg: >- - unnamed argument #%0 must precede argument %1 - -- id: argument_out_of_order_unnamed_unnamed - msg: >- - unnamed argument #%0 must precede unnamed argument #%1 - -- id: argument_out_of_order_binary_op - msg: >- - operator argument #%0 must precede operator argument #%1 - -- id: candidate_expected_different_labels - msg: >- - incorrect labels for candidate (have: '%0', expected: '%1') - -- id: member_shadows_function - msg: >- - use of %0 refers to %1 rather than %2 %3 - -- id: member_shadows_global_function - msg: >- - use of %0 refers to %1 rather than %2 %3 in module %4 - -- id: instance_member_use_on_type - msg: >- - instance member %1 cannot be used on type %0; did you mean to use a value - of this type instead? - -- id: instance_member_in_initializer - msg: >- - cannot use instance member %0 within property initializer; property - initializers run before 'self' is available - -- id: instance_member_in_default_parameter - msg: >- - cannot use instance member %0 as a default parameter - -- id: missing_argument_named - msg: >- - missing argument for parameter %0 in call - -- id: missing_argument_positional - msg: >- - missing argument for parameter #%0 in call - -- id: missing_arguments_in_call - msg: >- - missing arguments for parameters %0 in call - -- id: extra_argument_named - msg: >- - extra argument %0 in call - -- id: extra_argument_positional - msg: >- - extra argument in call - -- id: extra_arguments_in_call - msg: >- - extra arguments at positions %0 in call - -- id: extra_argument_to_nullary_call - msg: >- - argument passed to call that takes no arguments - -- id: extra_trailing_closure_in_call - msg: >- - extra trailing closure passed in call - -- id: trailing_closure_bad_param - msg: >- - trailing closure passed to parameter of type %0 that does not accept a - closure - -- id: candidate_with_extraneous_args - msg: >- - candidate %0 requires %1 argument%s1, but %2 %select{were|was}3 - %select{provided|used in closure body}4 - -- id: no_accessible_initializers - msg: >- - %0 cannot be constructed because it has no accessible initializers - -- id: non_nominal_no_initializers - msg: >- - non-nominal type %0 does not support explicit initialization - -- id: unbound_generic_parameter - msg: >- - generic parameter %0 could not be inferred - -- id: unbound_generic_parameter_cast - msg: >- - generic parameter %0 could not be inferred in cast to %1 - -- id: archetype_declared_in_type - msg: >- - %0 declared as parameter to type %1 - -- id: unbound_generic_parameter_explicit_fix - msg: >- - explicitly specify the generic arguments to fix this issue - -- id: invalid_dynamic_callable_type - msg: >- - @dynamicCallable attribute requires %0 to have either a valid - 'dynamicallyCall(withArguments:)' method or - 'dynamicallyCall(withKeywordArguments:)' method - -- id: missing_dynamic_callable_kwargs_method - msg: >- - @dynamicCallable type %0 cannot be applied with keyword arguments; - missing 'dynamicCall(withKeywordArguments:)' method - -- id: invalid_dynamic_member_lookup_type - msg: >- - @dynamicMemberLookup attribute requires %0 to have a - 'subscript(dynamicMember:)' method that accepts either - 'ExpressibleByStringLiteral' or a key path - -- id: invalid_dynamic_member_subscript - msg: >- - add an explicit argument label to this subscript to satisfy the - @dynamicMemberLookup requirement - -- id: string_index_not_integer - msg: >- - String must not be indexed with %0, it has variable size elements - -- id: string_index_not_integer_note - msg: >- - consider using an existing high level algorithm, - str.startIndex.advanced(by: n), or a projection like str.utf8 - -- id: invalid_c_function_pointer_conversion_expr - msg: >- - a C function pointer can only be formed from a reference to a 'func' or a - literal closure - -- id: c_function_pointer_from_method - msg: >- - a C function pointer cannot be formed from a method - -- id: c_function_pointer_from_generic_function - msg: >- - a C function pointer cannot be formed from a reference to a generic - function - -- id: unsupported_linear_to_differentiable_conversion - msg: >- - conversion from '@differentiable(linear)' to '@differentiable' is not yet - supported - -- id: invalid_autoclosure_forwarding - msg: >- - add () to forward @autoclosure parameter - -- id: invalid_differentiable_function_conversion_expr - msg: >- - a '@differentiable%select{|(linear)}0' function can only be formed from a - reference to a 'func' or 'init' or a literal closure - -- id: invalid_differentiable_function_conversion_parameter - msg: >- - did you mean to take a '%0' closure? - -- id: invalid_autoclosure_pointer_conversion - msg: >- - cannot perform pointer conversion of value of type %0 to autoclosure - result type %1 - -- id: missing_initializer_def - msg: >- - initializer requires a body - -- id: pound_warning - msg: >- - %0 - -- id: pound_error - msg: >- - %0 - -- id: operator_not_func - msg: >- - operators must be declared with 'func' - -- id: redefining_builtin_operator - msg: >- - cannot declare a custom %0 '%1' operator - -- id: attribute_requires_operator_identifier - msg: >- - '%0' requires a function with an operator identifier - -- id: attribute_requires_single_argument - msg: >- - '%0' requires a function with one argument - -- id: nominal_type_not_attribute - msg: >- - %0 %1 cannot be used as an attribute - -- id: mutating_invalid_global_scope - msg: >- - %0 is only valid on methods - -- id: mutating_invalid_classes - msg: >- - %0 isn't valid on methods in classes or class-bound protocols - -- id: functions_mutating_and_not - msg: >- - method must not be declared both %0 and %1 - -- id: static_functions_not_mutating - msg: >- - static functions must not be declared mutating - -- id: modify_mutatingness_differs_from_setter - msg: >- - 'modify' accessor cannot be %0 when the setter is %1 - -- id: transparent_in_protocols_not_supported - msg: >- - '@_transparent' attribute is not supported on declarations within - protocols - -- id: transparent_in_classes_not_supported - msg: >- - '@_transparent' attribute is not supported on declarations within classes - -- id: invalid_iboutlet - msg: >- - only instance properties can be declared @IBOutlet - -- id: iboutlet_nonobjc_class - msg: >- - @IBOutlet property cannot %select{have|be an array of}0 non-'@objc' class - type %1 - -- id: iboutlet_nonobjc_protocol - msg: >- - @IBOutlet property cannot %select{have|be an array of}0 non-'@objc' - protocol type %1 - -- id: iboutlet_nonobject_type - msg: >- - @IBOutlet property cannot %select{have|be an array of}0 non-object type %1 - -- id: iboutlet_only_mutable - msg: >- - @IBOutlet attribute requires property to be mutable - -- id: iboutlet_non_optional - msg: >- - @IBOutlet property has non-optional type %0 - -- id: note_make_optional - msg: >- - add '?' to form the optional type %0 - -- id: note_make_implicitly_unwrapped_optional - msg: >- - add '!' to form an implicitly unwrapped optional - -- id: invalid_ibdesignable_extension - msg: >- - @IBDesignable can only be applied to classes and extensions of classes - -- id: invalid_ibinspectable - msg: >- - only instance properties can be declared @%0 - -- id: invalid_ibaction_decl - msg: >- - only instance methods can be declared @%0 - -- id: invalid_ibaction_result - msg: >- - methods declared @%0 must %select{|not }1return a value - -- id: invalid_ibaction_argument_count - msg: >- - @%0 methods must have %1 to %2 arguments - -- id: invalid_ibaction_argument_count_exact - msg: >- - @%0 methods must have %2 argument%s2 - -- id: invalid_ibaction_argument_count_max - msg: >- - @%0 methods must have at most %2 argument%s2 - -- id: ibsegueaction_objc_method_family - msg: >- - @%0 method cannot have selector %1 because it has special memory - management behavior - -- id: fixit_rename_in_swift - msg: >- - change Swift name to %0 - -- id: fixit_rename_in_objc - msg: >- - change Objective-C selector to %0 - -- id: no_objc_tagged_pointer_not_class_protocol - msg: >- - @unsafe_no_objc_tagged_pointer can only be applied to class protocols - -- id: swift_native_objc_runtime_base_not_on_root_class - msg: >- - @_swift_native_objc_runtime_base_not_on_root_class can only be applied to - root classes - -- id: cdecl_not_at_top_level - msg: >- - @_cdecl can only be applied to global functions - -- id: cdecl_empty_name - msg: >- - @_cdecl symbol name cannot be empty - -- id: cdecl_throws - msg: >- - raising errors from @_cdecl functions is not supported - -- id: attr_methods_only - msg: >- - only methods can be declared %0 - -- id: access_control_in_protocol - msg: >- - %0 modifier cannot be used in protocols - -- id: access_control_in_protocol_detail - msg: >- - protocol requirements implicitly have the same access as the protocol - itself - -- id: access_control_setter - msg: >- - '%select{private|fileprivate|internal|public|open}0(set)' modifier can - only be applied to variables and subscripts - -- id: access_control_setter_read_only - msg: >- - '%select{private|fileprivate|internal|public|%error}0(set)' modifier - cannot be applied to %select{constants|read-only variables|read-only - properties|read-only subscripts}1 - -- id: access_control_setter_more - msg: >- - %select{private|fileprivate|internal|public|%error}0 - %select{variable|property|subscript}1 cannot have %select{%error|a - fileprivate|an internal|a public|an open}2 setter - -- id: access_control_setter_redundant - msg: >- - '%select{private|fileprivate|internal|public|open}0(set)' modifier is - redundant for - %select{a private|a fileprivate|an internal|a public|an open}2 %1 - -- id: access_control_ext_member_more - msg: >- - '%select{%error|fileprivate|internal|public|open}0' modifier conflicts - with extension's default access of - '%select{private|fileprivate|internal|public|%error}1' - -- id: access_control_ext_member_redundant - msg: >- - '%select{%error|fileprivate|internal|public|%error}0' modifier is - redundant for %1 declared in %select{a private (equivalent to fileprivate)|a - fileprivate|an internal|a public|%error}2 extension - -- id: access_control_ext_requirement_member_more - msg: >- - cannot declare %select{%error|a fileprivate|an internal|a public|an - open}0 %1 in an extension with - %select{private|fileprivate|internal|public|%error}2 requirements - -- id: access_control_extension_more - msg: >- - extension of %select{private|fileprivate|internal|%error|%error}0 %1 - cannot be declared %select{%error|fileprivate|internal|public|%error}2 - -- id: access_control_extension_open - msg: >- - extensions cannot use 'open' as their default access; use 'public' - -- id: access_control_open_bad_decl - msg: >- - only classes and overridable class members can be declared 'open'; use - 'public' - -- id: invalid_decl_attribute - msg: >- - '%0' attribute cannot be applied to this declaration - -- id: invalid_decl_modifier - msg: >- - %0 modifier cannot be applied to this declaration - -- id: attribute_does_not_apply_to_type - msg: >- - attribute does not apply to type - -- id: optional_attribute_non_protocol - msg: >- - 'optional' can only be applied to protocol members - -- id: optional_attribute_non_objc_protocol - msg: >- - 'optional' can only be applied to members of an @objc protocol - -- id: optional_attribute_missing_explicit_objc - msg: >- - 'optional' requirements are an Objective-C compatibility feature; add - '@objc' - -- id: objcmembers_attribute_nonclass - msg: >- - '@objcMembers' attribute can only be applied to a class - -- id: optional_attribute_initializer - msg: >- - 'optional' cannot be applied to an initializer - -- id: unavailable_method_non_objc_protocol - msg: >- - protocol members can only be marked unavailable in an @objc protocol - -- id: missing_in_class_init_1 - msg: >- - stored property %0 requires an initial value%select{| or should be - @NSManaged}1 - -- id: missing_in_class_init_2 - msg: >- - stored properties %0 and %1 require initial values%select{| or should be - @NSManaged}2 - -- id: missing_in_class_init_3plus - msg: >- - stored properties %0, %1, %select{and %2|%2, and others}3 require initial - values%select{| or should be @NSManaged}4 - -- id: requires_stored_property_inits_here - msg: >- - %select{superclass|class}1 %0 requires all stored properties to have - initial values%select{| or use @NSManaged}2 - -- id: class_without_init - msg: >- - class %0 has no initializers - -- id: note_no_in_class_init_1 - msg: >- - stored property %0 without initial value prevents synthesized - initializers - -- id: note_no_in_class_init_2 - msg: >- - stored properties %0 and %1 without initial values prevent synthesized - initializers - -- id: note_no_in_class_init_3plus - msg: >- - stored properties %0, %1, %select{and %2|%2, and others}3 without initial - values prevent synthesized initializers - -- id: missing_unimplemented_init_runtime - msg: >- - standard library error: missing _unimplementedInitializer - -- id: missing_undefined_runtime - msg: >- - standard library error: missing _undefined - -- id: expr_dynamic_lookup_swift3_objc_inference - msg: >- - reference to %0 %1 of %2 depends on '@objc' inference deprecated in Swift 4 - -- id: inherited_default_value_not_in_designated_constructor - msg: >- - default value inheritance via 'super' is only valid on the parameters of - designated initializers - -- id: inherited_default_value_used_in_non_overriding_constructor - msg: >- - default value inheritance via 'super' can only be used when overriding a - designated initializer - -- id: corresponding_param_not_defaulted - msg: >- - default value inheritance via 'super' requires that the corresponding - parameter of the overridden designated initializer has a default value - -- id: inherited_default_param_here - msg: >- - corresponding parameter declared here - -- id: option_set_zero_constant - msg: >- - static property %0 produces an empty option set - -- id: option_set_empty_set_init - msg: >- - use [] to silence this warning - -- id: originally_defined_in_dupe_platform - msg: >- - duplicate version number for platform %0 - -- id: originally_definedin_topleve_decl - msg: >- - @%0 is only applicable to top-level decl - -- id: originally_definedin_need_available - msg: >- - need @available attribute for @%0 - -- id: originally_definedin_must_after_available_version - msg: >- - moved version from @%0 must after introduced OS version - -- id: alignment_not_power_of_two - msg: >- - alignment value must be a power of two - -- id: indirect_case_without_payload - msg: >- - enum case %0 without associated value cannot be 'indirect' - -- id: indirect_case_in_indirect_enum - msg: >- - enum case in 'indirect' enum cannot also be 'indirect' - -- id: enum_frozen_nonpublic - msg: >- - %0 has no effect on non-public enums - -- id: getset_init - msg: >- - variable with getter/setter cannot have an initial value - -- id: unimplemented_static_var - msg: >- - %select{ERROR|static|class}1 stored properties not supported%select{ in - this context| in generic types| in classes| - in protocol extensions}0%select{|; did you mean 'static'?}2 - -- id: observingprop_requires_initializer - msg: >- - non-member observing properties require an initializer - -- id: global_requires_initializer - msg: >- - global '%select{var|let}0' declaration requires an initializer - expression%select{ or getter/setter specifier|}0 - -- id: static_requires_initializer - msg: >- - %select{ERROR|'static var'|'class var'|}0 declaration requires an - initializer expression or getter/setter specifier - -- id: pattern_type_access - msg: >- - %select{%select{variable|constant}0|property}1 %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}3|private or - fileprivate}4|cannot be declared %select{in this - context|fileprivate|internal|public|open}3}2 because its type uses %select{a - private|a fileprivate|an internal|%error|%error}5 type - -- id: pattern_type_access_warn - msg: >- - %select{%select{variable|constant}0|property}1 %select{should be declared - %select{private|fileprivate|internal|%error|%error}5|should not be declared - %select{in this context|fileprivate|internal|public|open}3}2 because its - type uses %select{a private|a fileprivate|an internal|%error|%error}5 type - -- id: pattern_type_access_inferred - msg: >- - %select{%select{variable|constant}0|property}1 %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}3|private or - fileprivate}4|cannot be declared %select{in this - context|fileprivate|internal|public|open}3}2 because its type %6 - uses %select{a private|a fileprivate|an internal|%error|%error}5 type - -- id: pattern_type_access_inferred_warn - msg: >- - %select{%select{variable|constant}0|property}1 %select{should be declared - %select{private|fileprivate|internal|%error|%error}5|should not be declared - %select{in this context|fileprivate|internal|public|open}3}2 because its - type %6 uses - %select{a private|a fileprivate|an internal|%error|%error}5 type - -- id: pattern_type_not_usable_from_inline - msg: >- - type referenced from a '@usableFromInline' - %select{%select{variable|constant}0|property}1 must be '@usableFromInline' - or public - -- id: pattern_type_not_usable_from_inline_warn - msg: >- - type referenced from a '@usableFromInline' - %select{%select{variable|constant}0|property}1 should be '@usableFromInline' - or public - -- id: pattern_type_not_usable_from_inline_frozen - msg: >- - type referenced from a stored property in a '@frozen' struct must be - '@usableFromInline' or public - -- id: pattern_type_not_usable_from_inline_inferred - msg: >- - type referenced from a '@usableFromInline' - %select{%select{variable|constant}0|property}1 with inferred type %2 must be - '@usableFromInline' or public - -- id: pattern_type_not_usable_from_inline_inferred_warn - msg: >- - type referenced from a '@usableFromInline' - %select{%select{variable|constant}0|property}1 with inferred type %2 should - be '@usableFromInline' or public - -- id: pattern_type_not_usable_from_inline_inferred_frozen - msg: >- - type referenced from a stored property with inferred type %2 in a - '@frozen' struct must be '@usableFromInline' or public - -- id: pattern_binds_no_variables - msg: >- - %select{property|global variable}0 declaration does not bind any - variables - -- id: variable_bound_by_no_pattern - msg: >- - variable %0 is not bound by any pattern - -- id: optional_ambiguous_case_ref - msg: >- - assuming you mean '%0.%2'; did you mean '%1.%2' instead? - -- id: optional_fixit_ambiguous_case_ref - msg: >- - explicitly specify 'Optional' to silence this warning - -- id: optional_fixit_ambiguous_case_ref_switch - msg: >- - use 'nil' to silence this warning - -- id: type_fixit_optional_ambiguous_case_ref - msg: >- - use '%0.%1' instead - -- id: type_fixit_optional_ambiguous_case_ref_switch - msg: >- - use '%0' instead - -- id: nscoding_unstable_mangled_name - msg: >- - %select{private|fileprivate|nested|local}0 class %1 has an unstable name - when archiving via 'NSCoding' - -- id: unstable_mangled_name_add_objc_new - msg: >- - for new classes, use '@objc' to specify a unique, prefixed Objective-C - runtime name - -- id: unstable_mangled_name_add_objc - msg: >- - for compatibility with existing archives, use '@objc' to record the Swift - 3 runtime name - -- id: unsupported_type_nested_in_generic_function - msg: >- - type %0 cannot be nested in generic function %1 - -- id: unsupported_type_nested_in_generic_closure - msg: >- - type %0 cannot be nested in closure in generic context - -- id: unsupported_type_nested_in_protocol - msg: >- - type %0 cannot be nested in protocol %1 - -- id: unsupported_type_nested_in_protocol_extension - msg: >- - type %0 cannot be nested in protocol extension of %1 - -- id: unsupported_nested_protocol - msg: >- - protocol %0 cannot be nested inside another declaration - -- id: where_nongeneric_ctx - msg: >- - 'where' clause on non-generic member declaration requires a generic - context - -- id: where_nongeneric_toplevel - msg: >- - 'where' clause cannot be applied to a non-generic top-level declaration - -- id: type_alias_underlying_type_access - msg: >- - type alias %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}1|private or - fileprivate}3|cannot be declared %select{in this - context|fileprivate|internal|public|open}1}0 because its underlying type - uses %select{a private|a fileprivate|an internal|%error|%error}2 type - -- id: type_alias_underlying_type_access_warn - msg: >- - type alias %select{should be declared - %select{private|fileprivate|internal|%error|%error}1|should not be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its - underlying type uses - %select{a private|a fileprivate|an internal|%error|%error}2 type - -- id: type_alias_underlying_type_not_usable_from_inline - msg: >- - type referenced from the underlying type of a '@usableFromInline' type - alias must be '@usableFromInline' or public - -- id: type_alias_underlying_type_not_usable_from_inline_warn - msg: >- - type referenced from the underlying type of a '@usableFromInline' type - alias should be '@usableFromInline' or public - -- id: subscript_type_access - msg: >- - subscript %select{must be declared - %select{private|fileprivate|internal|%error|%error}1|cannot be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its - %select{index|element type}3 uses %select{a private|a fileprivate|an - internal|%error|%error}2 type - -- id: subscript_type_access_warn - msg: >- - subscript %select{should be declared - %select{private|fileprivate|internal|%error|%error}1|should not be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its - %select{index|element type}3 uses %select{a private|a fileprivate|an - internal|%error|%error}2 type - -- id: subscript_type_usable_from_inline - msg: >- - %select{index type|element type}0 of a '@usableFromInline' subscript must - be '@usableFromInline' or public - -- id: subscript_type_usable_from_inline_warn - msg: >- - %select{index type|element type}0 of a '@usableFromInline' subscript - should be '@usableFromInline' or public - -- id: function_type_access - msg: >- - %select{function|method|initializer}4 %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}1|private or - fileprivate}2|cannot be declared %select{in this - context|fileprivate|internal|public|open}1}0 because its - %select{parameter|result}5 uses %select{a private|a fileprivate|an internal|an - '@_spi'|an '@_spi'}3 type - -- id: function_type_spi - msg: >- - %select{function|method|initializer}0 cannot be declared '@_spi' because - its %select{parameter|result}1 uses %select{a private|a fileprivate|an - internal|a public|an open}2 type%select{| that is not '@_spi'}3 - -- id: function_type_access_warn - msg: >- - %select{function|method|initializer}4 %select{should be declared - %select{private|fileprivate|internal|%error|%error}1|should not be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its - %select{parameter|result}5 uses %select{a private|a fileprivate|an - internal|%error|%error}3 type - -- id: function_type_usable_from_inline - msg: >- - the %select{parameter|result}1 of a '@usableFromInline' - %select{function|method|initializer}0 must be '@usableFromInline' or public - -- id: function_type_usable_from_inline_warn - msg: >- - the %select{parameter|result}1 of a '@usableFromInline' - %select{function|method|initializer}0 should be '@usableFromInline' - or public - -- id: spi_attribute_on_non_public - msg: >- - %select{private|fileprivate|internal|%error|%error}0 %1 cannot be - declared '@_spi' because only public and open declarations can be '@_spi' - -- id: spi_attribute_on_protocol_requirement - msg: >- - protocol requirement %0 cannot be declared '@_spi' without a default - implementation in a protocol extension - -- id: spi_attribute_on_frozen_stored_properties - msg: >- - stored property %0 cannot be declared '@_spi' in a '@frozen' struct - -- id: opaque_type_invalid_constraint - msg: >- - an 'opaque' type must specify only 'Any', 'AnyObject', protocols, and/or - a base class - -- id: inferred_opaque_type - msg: >- - property definition has inferred type %0, involving the 'some' return - type of another declaration - -- id: non_nominal_extension - msg: >- - non-nominal type %0 cannot be extended - -- id: composition_in_extended_type - msg: >- - extending a protocol composition is not supported; extending %0 instead - -- id: composition_in_extended_type_alternative - msg: >- - did you mean to extend the most specific type %0 instead? - -- id: extension_access_with_conformances - msg: >- - %0 modifier cannot be used with extensions that declare protocol - conformances - -- id: extension_metatype - msg: >- - cannot extend a metatype %0 - -- id: extension_specialization - msg: >- - constrained extension must be declared on the unspecialized generic type - %0 with constraints specified by a 'where' clause - -- id: extension_stored_property - msg: >- - extensions must not contain stored properties - -- id: extension_stored_property_fixit - msg: >- - Remove '=' to make %0 a computed property - -- id: extension_nongeneric_trailing_where - msg: >- - trailing 'where' clause for extension of non-generic type %0 - -- id: extension_protocol_inheritance - msg: >- - extension of protocol %0 cannot have an inheritance clause - -- id: objc_generic_extension_using_type_parameter - msg: >- - extension of a generic Objective-C class cannot access the class's - generic parameters at runtime - -- id: objc_generic_extension_using_type_parameter_here - msg: >- - generic parameter used here - -- id: objc_generic_extension_using_type_parameter_try_objc - msg: >- - add '@objc' to allow uses of 'self' within the function body - -- id: invalid_nominal_extension - msg: >- - extension of type %0 must be declared as an extension of %1 - -- id: invalid_nominal_extension_rewrite - msg: >- - did you mean to extend %0 instead? - -- id: type_does_not_conform - msg: >- - type %0 does not conform to protocol %1 - -- id: cannot_use_nil_with_this_type - msg: >- - 'nil' cannot be used in context expecting type %0 - -- id: type_cannot_conform_to_nsobject - msg: >- - cannot declare conformance to 'NSObjectProtocol' in Swift; %0 should - inherit 'NSObject' instead - -- id: use_of_equal_instead_of_equality - msg: >- - use of '=' in a boolean context, did you mean '=='? - -- id: type_cannot_conform - msg: >- - %select{type %1|protocol %1 as a type}0 cannot conform to - %select{%3|the protocol itself}2; - only concrete types such as structs, enums and classes - can conform to protocols - -- id: required_by_opaque_return - msg: >- - required by opaque return type of %0 %1 - -- id: required_by_decl - msg: >- - required by %0 %1 where %2 = %3 - -- id: required_by_decl_ref - msg: >- - required by referencing %0 %1 on %2 where %3 = %4 - -- id: protocol_does_not_conform_static - msg: >- - %0 cannot be used as a type conforming to protocol %1 because %1 has - static requirements - -- id: protocol_derivation_is_broken - msg: >- - protocol %0 is broken; cannot derive conformance for type %1 - -- id: type_does_not_inherit - msg: >- - %0 requires that %1 inherit from %2 - -- id: type_does_not_inherit_or_conform_requirement - msg: >- - requirement specified as %0 : %1%2 - -- id: types_not_equal - msg: >- - %0 requires the types %1 and %2 be equivalent - -- id: type_does_not_conform_owner - msg: >- - %0 requires that %1 conform to %2 - -- id: type_does_not_conform_in_decl_ref - msg: >- - referencing %0 %1 on %2 requires that %3 conform to %4 - -- id: type_does_not_conform_anyobject_in_decl_ref - msg: >- - referencing %0 %1 on %2 requires that %3 be a class type - -- id: type_does_not_conform_decl_owner - msg: >- - %0 %1 requires that %2 conform to %3 - -- id: type_does_not_conform_anyobject_decl_owner - msg: >- - %0 %1 requires that %2 be a class type - -- id: type_does_not_conform_in_opaque_return - msg: >- - return type of %0 %1 requires that %2 - %select{conform to %3|be a class type}4 - -- id: types_not_equal_decl - msg: >- - %0 %1 requires the types %2 and %3 be equivalent - -- id: types_not_equal_in_decl_ref - msg: >- - referencing %0 %1 on %2 requires the types %3 and %4 be equivalent - -- id: types_not_inherited_decl - msg: >- - %0 %1 requires that %2 inherit from %3 - -- id: types_not_inherited_in_decl_ref - msg: >- - referencing %0 %1 on %2 requires that %3 inherit from %4 - -- id: where_requirement_failure_one_subst - msg: >- - where %0 = %1 - -- id: where_requirement_failure_both_subst - msg: >- - where %0 = %1, %2 = %3 - -- id: requirement_implied_by_conditional_conformance - msg: >- - requirement from conditional conformance of %0 to %1 - -- id: wrapped_type_satisfies_requirement - msg: >- - wrapped type %0 satisfies this requirement; did you mean to unwrap? - -- id: candidate_types_conformance_requirement - msg: >- - candidate requires that %0 conform to %1 - (requirement specified as %2 == %3%4) - -- id: candidate_types_equal_requirement - msg: >- - candidate requires that the types %0 and %1 be equivalent (requirement - specified as %2 == %3%4) - -- id: candidate_types_inheritance_requirement - msg: >- - candidate requires that %1 inherit from %2 - (requirement specified as %2 : %3%4) - -- id: types_not_equal_requirement - msg: >- - requirement specified as %0 == %1%2 - -- id: type_is_not_a_class - msg: >- - %0 requires that %1 be a class type - -- id: anyobject_requirement - msg: >- - requirement specified as %0 : 'AnyObject'%2 - -- id: non_class_cannot_conform_to_class_protocol - msg: >- - non-class type %0 cannot conform to class protocol %1 - -- id: cf_class_cannot_conform_to_objc_protocol - msg: >- - Core Foundation class %0 cannot conform to @objc protocol %1 because Core - Foundation types are not classes in Objective-C - -- id: objc_runtime_visible_cannot_conform_to_objc_protocol - msg: >- - class %0 cannot conform to @objc protocol %1 because the class is only - visible via the Objective-C runtime - -- id: objc_generics_cannot_conditionally_conform - msg: >- - type %0 cannot conditionally conform to protocol %1 because the type uses - the Objective-C generics model - -- id: objc_protocol_cannot_have_conditional_conformance - msg: >- - type %0 cannot conditionally conform to @objc protocol %1 because - Objective-C does not support conditional conformances - -- id: objc_protocol_in_generic_extension - msg: >- - conformance of %select{class from generic context|generic class}0 %1 to - @objc protocol %2 cannot be in an extension - -- id: conditional_conformances_cannot_imply_conformances - msg: >- - conditional conformance of type %0 to protocol %1 does not imply - conformance to inherited protocol %2 - -- id: note_explicitly_state_conditional_conformance_different - msg: >- - did you mean to explicitly state the conformance with different bounds? - -- id: note_explicitly_state_conditional_conformance_relaxed - msg: >- - did you mean to explicitly state the conformance with relaxed bounds? - -- id: note_explicitly_state_conditional_conformance_same - msg: >- - did you mean to explicitly state the conformance with the same bounds? - -- id: note_explicitly_state_conditional_conformance_noneditor - msg: >- - did you mean to explicitly state the conformance like '%0where ...'? - -- id: protocol_has_missing_requirements - msg: >- - type %0 cannot conform to protocol %1 because it has requirements that - cannot be satisfied - -- id: protocol_has_missing_requirements_versioned - msg: >- - type %0 cannot conform to protocol %1 (compiled with Swift %2) because it - has requirements that could not be loaded in Swift %3 - -- id: requirement_restricts_self - msg: >- - %0 requirement %1 cannot add constraint '%2%select{:|:| ==|:}3 %4' on 'Self' - -- id: witness_argument_name_mismatch - msg: >- - %0 %1 has different argument labels from those required by protocol %2 (%3) - -- id: witness_initializer_not_required - msg: >- - initializer requirement %0 can only be satisfied by a 'required' - initializer in%select{| the definition of}1 non-final class %2 - -- id: witness_initializer_failability - msg: >- - non-failable initializer requirement %0%select{| in Objective-C - protocol}1 cannot be satisfied by a - failable initializer ('init%select{?|!}1') - -- id: witness_self_non_subtype - msg: >- - 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 - -- id: witness_self_same_type - msg: >- - %0 %1 in non-final class %2 cannot be used to satisfy requirement %3 %4 - (in protocol %5) due to same-type requirement involving 'Self' - -- id: witness_self_weaken_same_type - msg: >- - consider weakening the same-type requirement %0 == %1 to a superclass - requirement - -- id: witness_requires_dynamic_self - msg: >- - method %0 in non-final class %1 must return 'Self' to conform to protocol %2 - -- id: witness_requires_class_implementation - msg: >- - method %0 in non-final class %1 cannot be implemented in a protocol - extension because it returns 'Self' and has associated type requirements - -- id: witness_not_accessible_proto - msg: >- - %select{initializer %1|method %1|%select{|setter for }2property - %1|subscript%select{| setter}2}0 must be declared - %select{%error|fileprivate|internal|public|%error}3 because it matches a - requirement in %select{private|fileprivate|internal|public|%error}4 - protocol %5 - -- id: witness_not_accessible_type - msg: >- - %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 %5 - -- id: type_witness_not_accessible_proto - msg: >- - %0 %1 must be declared - %select{%error|fileprivate|internal|public|%error}2 because it matches a - requirement in %select{%error|fileprivate|internal|public|%error}2 - protocol %3 - -- id: type_witness_not_accessible_type - msg: >- - %0 %1 must be as accessible as its enclosing type because it matches a - requirement in protocol %3 - -- id: witness_not_usable_from_inline - msg: >- - %0 %1 must be declared '@usableFromInline' because it matches a - requirement in protocol %2 - -- id: witness_not_usable_from_inline_warn - msg: >- - %0 %1 should be declared '@usableFromInline' because it matches a - requirement in protocol %2 - -- id: type_witness_objc_generic_parameter - msg: >- - type %0 involving Objective-C type parameter%select{| %1}2 cannot be used - for associated type %3 of protocol %4 - -- id: witness_fix_access - msg: >- - mark the %0 as '%select{%error|fileprivate|internal|public|%error}1' to - satisfy the requirement - -- id: witness_move_to_another_extension - msg: >- - move the %0 to another extension where it can be declared - '%select{%error|%error|internal|public|%error}1' to satisfy the requirement - -- id: assoc_type_default_conformance_failed - msg: >- - default type %0 for associated type %1 does not satisfy constraint %2: %3 - -- id: assoc_type_default_here - msg: >- - associated type %0 has default type %1 written here - -- id: protocol_access - msg: >- - %select{protocol must be declared - %select{%select{private|fileprivate|internal|%error|%error}1|private or - fileprivate}4 because - %select{it refines|its 'where' clause uses}2|%select{in - this context|fileprivate|internal|public|%error}1 %select{protocol cannot - refine|protocol's 'where' clause cannot use}2}0 %select{a private|a - fileprivate|an internal|%error|%error}3 %5 - -- id: protocol_access_warn - msg: >- - %select{protocol should be declared - %select{private|fileprivate|internal|%error|%error}1 because %select{it - refines|its 'where' clause uses}2|%select{in this - context|fileprivate|internal|public|%error}1 %select{protocol should not - refine|protocol's 'where' clause should not use}2}0 %select{a private|a - fileprivate|an internal|%error|%error}3 %5 - -- id: protocol_usable_from_inline - msg: >- - protocol %select{refined|used}0 by '@usableFromInline' protocol must be - '@usableForInline' or public - -- id: protocol_usable_from_inline_warn - msg: >- - protocol %select{refined|used}0 by '@usableFromInline' protocol should be - '@usableForInline' or public - -- id: protocol_property_must_be_computed_var - msg: >- - protocols cannot require properties to be immutable; declare read-only - properties by using 'var' with a '{ get }' specifier - -- id: protocol_property_must_be_computed - msg: >- - property in protocol must have explicit { get } or { get set } specifier - -- id: inherited_protocol_does_not_conform - msg: >- - type %0 does not conform to inherited protocol %1 - -- id: no_witnesses - msg: >- - protocol requires %select{initializer %1|function %1|property - %1|subscript}0 with type %2%select{|; do you want to add a stub?}3 - -- id: missing_witnesses_general - msg: >- - do you want to add protocol stubs? - -- id: ambiguous_witnesses - msg: >- - multiple matching %select{initializers named %1|functions named - %1|properties named %1|subscript operators}0 with type %2 - -- id: ambiguous_witnesses_wrong_name - msg: >- - multiple matching %select{initializers named %1|functions named - %1|properties named %1|subscript operators}0 with type %2 - -- id: no_witnesses_type - msg: >- - protocol requires nested type %0; do you want to add it? - -- id: default_associated_type_req_fail - msg: >- - default type %0 for associated type %1 (from protocol %2) does not - %select{inherit from|conform to}4 %3 - -- id: associated_type_access - msg: >- - associated type in %select{a private|a fileprivate|an internal|a - public|%error}0 protocol uses %select{a private|a fileprivate|an - internal|%error|%error}1 type in its - %select{default definition|requirement}2 - -- id: associated_type_access_warn - msg: >- - associated type in %select{a private|a fileprivate|an internal|a - public|%error}0 protocol uses %select{a private|a fileprivate|an - internal|%error|%error}1 type in its - %select{default definition|requirement}2 - -- id: associated_type_not_usable_from_inline - msg: >- - type referenced from a %select{default definition|requirement}0 of an - associated type in a '@usableFromInline' - protocol must be '@usableFromInline' or public - -- id: associated_type_not_usable_from_inline_warn - msg: >- - type referenced from a %select{default definition|requirement}0 of an - associated type in a '@usableFromInline' - protocol should be '@usableFromInline' or public - -- id: bad_associated_type_deduction - msg: >- - unable to infer associated type %0 for protocol %1 - -- id: associated_type_deduction_witness_failed - msg: >- - candidate would match and infer %0 = %1 if %1 %select{inherited - from|conformed to}3 %2 - -- id: associated_type_witness_conform_impossible - msg: >- - candidate can not infer %0 = %1 because %1 is not a nominal type and so - can't conform to %2 - -- id: associated_type_witness_inherit_impossible - msg: >- - candidate can not infer %0 = %1 because %1 is not a class type and so - can't inherit from %2 - -- id: ambiguous_associated_type_deduction - msg: >- - ambiguous inference of associated type %0: %1 vs. %2 - -- id: associated_type_deduction_witness - msg: >- - matching requirement %0 to this declaration inferred associated type to %1 - -- id: associated_type_deduction_default - msg: >- - using associated type default %0 - -- id: ambiguous_witnesses_type - msg: >- - multiple matching types named %0 - -- id: protocol_witness_exact_match - msg: >- - candidate exactly matches%0 - -- id: protocol_witness_renamed - msg: >- - rename to %0 to satisfy this requirement%1 - -- id: protocol_witness_kind_conflict - msg: >- - candidate is not %select{an initializer|a function|a variable|a subscript}0 - -- id: protocol_witness_type_conflict - msg: >- - candidate has non-matching type %0%1 - -- id: protocol_witness_missing_requirement - msg: >- - candidate would match if %0 %select{conformed to|subclassed|was the same - type as}2 %1 - -- id: protocol_witness_optionality_conflict - msg: >- - candidate %select{type has|result type has|parameter type has|parameter - types have|result and parameter types have}0 incorrect optionality%1 - -- id: err_protocol_witness_optionality - msg: >- - %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 - -- id: warn_protocol_witness_optionality - msg: >- - %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 - -- id: protocol_witness_static_conflict - msg: >- - candidate operates on %select{a type|an instance}0, not %select{an - instance|a type}0 as required - -- id: protocol_witness_prefix_postfix_conflict - msg: >- - candidate is %select{|prefix, |postfix, }1not %select{prefix|postfix}0 as - required - -- id: protocol_witness_mutation_modifier_conflict - msg: >- - candidate is marked %0 but protocol does not allow it - -- id: protocol_witness_settable_conflict - msg: >- - candidate is not settable, but protocol requires it - -- id: protocol_witness_rethrows_conflict - msg: >- - candidate is not 'rethrows', but protocol requires it - -- id: protocol_witness_throws_conflict - msg: >- - candidate throws, but protocol does not allow it - -- id: protocol_witness_not_objc - msg: >- - candidate is explicitly '@nonobjc' - -- id: protocol_witness_enum_case_payload - msg: >- - candidate is an enum case with associated values, but protocol does not - allow it - -- id: protocol_witness_type - msg: >- - possibly intended match - -- id: protocol_witness_nonconform_type - msg: >- - possibly intended match %0 does not %select{inherit from|conform to}2 %1 - -- id: protocol_witness_circularity - msg: >- - candidate references itself - -- id: protocol_conformance_here - msg: >- - %select{|class }0%1 declares conformance to protocol %2 here - -- id: declared_protocol_conformance_here - msg: >- - %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 - -- id: witness_unavailable - msg: >- - unavailable %0 %1 was used to satisfy a requirement of protocol %2 - -- id: redundant_conformance - msg: >- - redundant conformance of %0 to protocol %1 - -- id: redundant_conformance_conditional - msg: >- - conflicting conformance of %0 to protocol %1; there cannot be more than - one conformance, even with different conditional bounds - -- id: redundant_conformance_adhoc - msg: >- - conformance of %0 to protocol %1 was already stated in - %select{the protocol's|the type's}2 module %3 - -- id: redundant_conformance_adhoc_conditional - msg: >- - conformance of %0 to protocol %1 conflicts with that stated in - %select{the protocol's|the type's}2 module %3 and will be ignored; - there cannot be more than one conformance, - even with different conditional bounds - -- id: redundant_conformance_witness_ignored - msg: >- - %0 %1 will not be used to satisfy the conformance to %2 - -- id: req_near_match - msg: >- - %0 %1 nearly matches %select{defaulted|optional}2 requirement %3 of - protocol %4 - -- id: optional_req_nonobjc_near_match_add_objc - msg: >- - add '@objc' to provide an Objective-C entrypoint - -- id: req_near_match_move - msg: >- - move %0 to %select{an|another}1 extension to silence this warning - -- id: req_near_match_nonobjc - msg: >- - add '@nonobjc' to silence this %select{warning|error}0 - -- id: req_near_match_access - msg: >- - make %0 %select{ERROR|private|private|non-public|non-public}1 to silence - this warning - -- id: missing_append_interpolation - msg: >- - type conforming to 'StringInterpolationProtocol' does not implement a - valid 'appendInterpolation' method - -- id: append_interpolation_static - msg: >- - 'appendInterpolation' method will never be used because it is static - -- id: append_interpolation_void_or_discardable - msg: >- - 'appendInterpolation' method does not return 'Void' or have a discardable - result - -- id: append_interpolation_access_control - msg: >- - 'appendInterpolation' method is - %select{private|fileprivate|internal|public|open}0, but %1 is - %select{private|fileprivate|internal|public|open}2 - -- id: assoc_type_outside_of_protocol - msg: >- - associated type %0 can only be used with a concrete type or generic - parameter base - -- id: typealias_outside_of_protocol - msg: >- - type alias %0 can only be used with a concrete type or generic parameter - base - -- id: objc_protocol_inherits_non_objc_protocol - msg: >- - @objc protocol %0 cannot refine non-@objc protocol %1 - -- id: protocol_where_clause_self_requirement - msg: >- - constraint with subject type of 'Self' is not supported; consider adding - requirement to protocol inheritance clause instead - -- id: invalid_protocol_composition_member - msg: >- - non-protocol, non-class type %0 cannot be used within a - protocol-constrained type - -- id: protocol_composition_one_class - msg: >- - protocol-constrained type cannot contain class %0 because it already - contains class %1 - -- id: requires_conformance_nonprotocol - msg: >- - type %0 constrained to non-protocol, non-class type %1 - -- id: requires_conformance_nonprotocol_fixit - msg: >- - use '%0 == %1' to require '%0' to be '%1' - -- id: requires_not_suitable_archetype - msg: >- - type %0 in conformance requirement does not refer to a generic parameter - or associated type - -- id: requires_no_same_type_archetype - msg: >- - neither type in same-type constraint (%0 or %1) refers to a generic - parameter or associated type - -- id: requires_generic_params_made_equal - msg: >- - same-type requirement makes generic parameters %0 and %1 equivalent - -- id: requires_generic_param_made_equal_to_concrete - msg: >- - same-type requirement makes generic parameter %0 non-generic - -- id: recursive_decl_reference - msg: >- - %0 %1 references itself - -- id: recursive_same_type_constraint - msg: >- - same-type constraint %0 == %1 is recursive - -- id: recursive_superclass_constraint - msg: >- - superclass constraint %0 : %1 is recursive - -- id: requires_generic_param_same_type_does_not_conform - msg: >- - same-type constraint type %0 does not conform to required protocol %1 - -- id: requires_same_concrete_type - msg: >- - generic signature requires types %0 and %1 to be the same - -- id: redundant_conformance_constraint - msg: >- - redundant conformance constraint %0: %1 - -- id: redundant_conformance_here - msg: >- - conformance constraint %1: %2 %select{written here|implied here|inferred - from type here}0 - -- id: unsupported_recursive_requirements - msg: >- - requirement involves recursion that is not currently supported - -- id: same_type_conflict - msg: >- - %select{generic parameter |protocol |}0%1 cannot be equal to both %2 and %3 - -- id: redundant_same_type_to_concrete - msg: >- - redundant same-type constraint %0 == %1 - -- id: same_type_redundancy_here - msg: >- - same-type constraint %1 == %2 %select{written here|implied here|inferred - from type here}0 - -- id: requires_superclass_conflict - msg: >- - %select{generic parameter %1 cannot|protocol %1 cannot require 'Self' - to|%1 cannot}0 be a subclass of both %2 and %3 - -- id: redundant_superclass_constraint - msg: >- - redundant superclass constraint %0 : %1 - -- id: superclass_redundancy_here - msg: >- - superclass constraint %1 : %2 %select{written here|implied here|inferred - from type here}0 - -- id: conflicting_layout_constraints - msg: >- - %select{generic parameter |protocol |}0%1 has conflicting constraints %2 - and %3 - -- id: redundant_layout_constraint - msg: >- - redundant constraint %0 : %1 - -- id: previous_layout_constraint - msg: >- - constraint %1 : %2 %select{written here|implied here|inferred from type - here}0 - -- id: redundant_same_type_constraint - msg: >- - redundant same-type constraint %0 == %1 - -- id: previous_same_type_constraint - msg: >- - previous same-type constraint %1 == %2 %select{written here|implied - here|inferred from type here}0 - -- id: inherited_associated_type_redecl - msg: >- - redeclaration of associated type %0 from protocol %1 is better expressed - as a 'where' clause on the protocol - -- id: typealias_override_associated_type - msg: >- - typealias overriding associated type %0 from protocol %1 is better - expressed as same-type constraint on the protocol - -- id: associated_type_override_typealias - msg: >- - associated type %0 is redundant with type %0 declared in inherited %1 %2 - -- id: associated_type_objc - msg: >- - associated type %0 cannot be declared inside '@objc' protocol %1 - -- id: generic_param_access - msg: >- - %0 %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}3|private or - fileprivate}4|cannot be declared %select{in this - context|fileprivate|internal|public|open}2}1 because its generic - %select{parameter|requirement}5 uses %select{a private|a fileprivate|an - internal|an '@_spi'|an '@_spi'}3 type - -- id: generic_param_access_warn - msg: >- - %0 %select{should be declared - %select{private|fileprivate|internal|%error|%error}3|should not be declared - %select{in this context|fileprivate|internal|public|open}2}1 because its generic - %select{parameter|requirement}5 uses %select{a private|a fileprivate|an - internal|an '@_spi'|an '@_spi'}3 type - -- id: generic_param_usable_from_inline - msg: >- - type referenced from a generic %select{parameter|requirement}1 of a - '@usableFromInline' %0 must be '@usableFromInline' or public - -- id: generic_param_usable_from_inline_warn - msg: >- - type referenced from a generic %select{parameter|requirement}1 of a - '@usableFromInline' %0 should be '@usableFromInline' or public - -- id: override_multiple_decls_base - msg: >- - declaration %0 cannot override more than one superclass declaration - -- id: override_multiple_decls_arg_mismatch - msg: >- - declaration %0 has different argument labels from any potential overrides - -- id: overridden_near_match_here - msg: >- - potential overridden %0 %1 here - -- id: override_decl_extension - msg: >- - overriding %select{|non-@objc }0declarations %select{in extensions|from - extensions}0 is not supported - -- id: overridden_here - msg: >- - overridden declaration is here - -- id: overridden_here_can_be_objc - msg: >- - add '@objc' to make this declaration overridable - -- id: missing_override - msg: >- - overriding declaration requires an 'override' keyword - -- id: missing_override_warn - msg: >- - implicit override should be marked with 'override' or suppressed with - '@_nonoverride' - -- id: multiple_override - msg: >- - %0 has already been overridden - -- id: multiple_override_prev - msg: >- - %0 previously overridden here - -- id: override_unavailable - msg: >- - cannot override %0 which has been marked unavailable%select{|: %1}1 - -- id: suggest_removing_override - msg: >- - remove 'override' modifier to declare a new %0 - -- id: override_less_available - msg: >- - overriding %0 must be as available as declaration it overrides - -- id: override_accessor_less_available - msg: >- - overriding %0 for %1 must be as available as declaration it overrides - -- id: override_let_property - msg: >- - cannot override immutable 'let' property %0 with the getter of a 'var' - -- id: override_not_accessible - msg: >- - %select{|setter of }0overriding %1 must be as accessible as %select{its - enclosing type|the declaration it overrides}2 - -- id: override_of_non_open - msg: >- - overriding non-open %0 outside of its defining module - -- id: method_does_not_override - msg: >- - method does not override any method from its %select{parent protocol|superclass}0 - -- id: property_does_not_override - msg: >- - property does not override any property from its %select{parent protocol|superclass}0 - -- id: subscript_does_not_override - msg: >- - subscript does not override any subscript from its %select{parent protocol|superclass}0 - -- id: initializer_does_not_override - msg: >- - initializer does not override a designated initializer from its - %select{parent protocol|superclass}0 - -- id: failable_initializer_override - msg: >- - failable initializer %0 cannot override a non-failable initializer - -- id: nonfailable_initializer_override_here - msg: >- - non-failable initializer %0 overridden here - -- id: property_override_here - msg: >- - attempt to override property here - -- id: subscript_override_here - msg: >- - attempt to override subscript here - -- id: convenience_init_override_here - msg: >- - attempt to override convenience initializer here - -- id: override_type_mismatch_with_fixits - msg: >- - type does not match superclass %0 with type %1 - -- id: override_type_mismatch_with_fixits_init - msg: >- - type does not match superclass initializer with %select{no - arguments|argument %1|arguments %1}0 - -- id: override_nonclass_decl - msg: >- - 'override' can only be specified on class members - -- id: nonoverride_wrong_decl_context - msg: >- - '@_nonoverride' can only be specified on class or protocol members - -- id: nonoverride_and_override_attr - msg: >- - 'override' cannot be combined with '@_nonoverride' - -- id: override_property_type_mismatch - msg: >- - property %0 with type %1 cannot override a property with type %2 - -- id: override_with_stored_property - msg: >- - cannot override with a stored property %0 - -- id: override_with_stored_property_warn - msg: >- - cannot override with a stored property %0 - -- id: observing_readonly_property - msg: >- - cannot observe read-only property %0; it can't change - -- id: override_mutable_with_readonly_property - msg: >- - cannot override mutable property with read-only property %0 - -- id: override_argument_name_mismatch - msg: >- - argument labels for %select{method|initializer}0 %1 do not match those of - overridden %select{method|initializer}0 %2 - -- id: override_ownership_mismatch - msg: >- - cannot override %0 property with %1 property - -- id: override_dynamic_self_mismatch - msg: >- - cannot override a Self return type with a non-Self return type - -- id: override_class_declaration_in_extension - msg: >- - cannot override a non-dynamic class declaration from an extension - -- id: override_throws - msg: >- - cannot override non-throwing %select{method|initializer}0 with throwing - %select{method|initializer}0 - -- id: override_throws_objc - msg: >- - overriding a throwing @objc %select{method|initializer}0 with a - non-throwing %select{method|initializer}0 is not supported - -- id: satisfy_throws_objc - msg: >- - satisfying a throwing @objc %select{method|initializer}0 with a - non-throwing %select{method|initializer}0 is not supported - -- id: override_optional_mismatch - msg: >- - cannot override %0 %select{parameter|index}1 of type %2 with non-optional - type %3 - -- id: override_optional_result_mismatch - msg: >- - cannot override %0 %select{result|element}1 type %2 with optional type %3 - -- id: override_unnecessary_IUO - msg: >- - overriding %0 parameter of type %1 with implicitly unwrapped optional - type %2 - -- id: override_unnecessary_result_IUO - msg: >- - overriding %0 optional result type %1 with implicitly unwrapped optional - type %2 - -- id: override_unnecessary_IUO_remove - msg: >- - remove '!' to make the parameter required - -- id: override_unnecessary_IUO_use_strict - msg: >- - use '?' to make the result optional - -- id: override_unnecessary_IUO_silence - msg: >- - add parentheses to silence this warning - -- id: override_mutable_covariant_property - msg: >- - cannot override mutable property %0 of type %1 with covariant type %2 - -- id: override_mutable_covariant_subscript - msg: >- - cannot override mutable subscript of type %0 with covariant type %1 - -- id: static_decl_already_final - msg: >- - static declarations are already final - -- id: open_decl_cannot_be_final - msg: >- - %0 cannot be declared both 'final' and 'open' - -- id: implicitly_final_cannot_be_open - msg: >- - %select{'let' properties|members of 'final' classes|static declarations}0 - are implicitly 'final'; use 'public' instead of 'open' - -- id: implicitly_final_cannot_be_open_swift4 - msg: >- - %select{'let' properties|members of 'final' classes|static declarations}0 - are implicitly 'final'; use 'public' instead of 'open' - -- id: override_swift3_objc_inference - msg: >- - override of %0 %1 from extension of %2 depends on deprecated inference of - '@objc' - -- id: override_method_different_generic_sig - msg: >- - overridden method %0 has generic signature %1 which is incompatible with - base method's generic signature %2; expected generic signature to be %3 - -- id: duplicate_inheritance - msg: >- - duplicate inheritance from %0 - -- id: duplicate_anyobject_class_inheritance - msg: >- - redundant inheritance from 'AnyObject' and Swift 3 'class' keyword - -- id: inheritance_from_protocol_with_superclass - msg: >- - inheritance from class-constrained protocol composition type %0 - -- id: multiple_inheritance - msg: >- - multiple inheritance from classes %0 and %1 - -- id: inheritance_from_non_protocol_or_class - msg: >- - inheritance from non-protocol, non-class type %0 - -- id: inheritance_from_non_protocol - msg: >- - inheritance from non-protocol type %0 - -- id: superclass_not_first - msg: >- - superclass %0 must appear first in the inheritance clause - -- id: superclass_not_open - msg: >- - cannot inherit from non-open class %0 outside of its defining module - -- id: superclass_here - msg: >- - superclass is declared here - -- id: superclass_of_open_not_open - msg: >- - superclass %0 of open class must be open - -- id: inheritance_from_final_class - msg: >- - inheritance from a final class %0 - -- id: inheritance_from_unspecialized_objc_generic_class - msg: >- - inheritance from a generic Objective-C class %0 must bind type parameters - of %0 to specific concrete types - -- id: inheritance_from_class_with_missing_vtable_entries - msg: >- - cannot inherit from class %0 because it has overridable members that - could not be loaded - -- id: inheritance_from_class_with_missing_vtable_entries_versioned - msg: >- - cannot inherit from class %0 (compiled with Swift %1) because it has - overridable members that could not be loaded in Swift %2 - -- id: inheritance_from_cf_class - msg: >- - cannot inherit from Core Foundation type %0 - -- id: inheritance_from_objc_runtime_visible_class - msg: >- - cannot inherit from class %0 because it is only visible via the - Objective-C runtime - -- id: enum_case_access - msg: >- - enum case in %select{a private|a fileprivate|an internal|a - public|%error}0 enum uses %select{a private|a fileprivate|an - internal|%error|%error}1 type - -- id: enum_case_access_warn - msg: >- - enum case in %select{a private|a fileprivate|an internal|a - public|%error}0 enum uses %select{a private|a fileprivate|an - internal|%error|%error}1 type - -- id: enum_case_usable_from_inline - msg: >- - type of enum case in '@usableFromInline' enum must be '@usableFromInline' - or public - -- id: enum_case_usable_from_inline_warn - msg: >- - type of enum case in '@usableFromInline' enum should be - '@usableFromInline' or public - -- id: enum_stored_property - msg: >- - enums must not contain stored properties - -- id: multiple_enum_raw_types - msg: >- - multiple enum raw types %0 and %1 - -- id: raw_type_not_first - msg: >- - raw type %0 must appear first in the enum inheritance clause - -- id: raw_type_not_literal_convertible - msg: >- - raw type %0 is not expressible by a string, integer, or floating-point - literal - -- id: enum_raw_type_not_equatable - msg: >- - RawRepresentable conformance cannot be synthesized because raw type %0 is - not Equatable - -- id: enum_raw_type_nonconforming_and_nonsynthable - msg: >- - %0 declares raw type %1, but does not conform to RawRepresentable and - conformance could not be synthesized - -- id: enum_declares_rawrep_with_raw_type - msg: >- - %0 declares raw type %1, which implies RawRepresentable - -- id: enum_raw_type_access - msg: >- - enum %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}1|private or - fileprivate}3|cannot be declared %select{in this - context|fileprivate|internal|public|open}1}0 because its raw type uses - %select{a private|a fileprivate|an internal|%error|%error}2 type - -- id: enum_raw_type_access_warn - msg: >- - enum %select{should be declared - %select{private|fileprivate|internal|%error|%error}1|should not be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its raw - type uses %select{a private|a fileprivate|an internal|%error|%error}2 type - -- id: enum_raw_type_not_usable_from_inline - msg: >- - type referenced from the raw type of a '@usableFromInline' enum must be - '@usableFromInline' or public - -- id: enum_raw_type_not_usable_from_inline_warn - msg: >- - type referenced from the raw type of a '@usableFromInline' enum should be - '@usableFromInline' or public - -- id: empty_enum_raw_type - msg: >- - an enum with no cases cannot declare a raw type - -- id: enum_raw_value_without_raw_type - msg: >- - enum case cannot have a raw value if the enum does not have a raw type - -- id: enum_with_raw_type_case_with_argument - msg: >- - enum with raw type cannot have cases with arguments - -- id: enum_raw_type_here - msg: >- - declared raw type %0 here - -- id: objc_enum_no_raw_type - msg: >- - '@objc' enum must declare an integer raw type - -- id: objc_enum_raw_type_not_integer - msg: >- - '@objc' enum raw type %0 is not an integer type - -- id: enum_non_integer_raw_value_auto_increment - msg: >- - enum case must declare a raw value when the preceding raw value is not an - integer - -- id: enum_non_integer_convertible_raw_type_no_value - msg: >- - enum cases require explicit raw values when the raw type is not - expressible by integer or string literal - -- id: enum_raw_value_not_unique - msg: >- - raw value for enum case is not unique - -- id: enum_raw_value_magic_literal - msg: >- - use of '%0' literal as raw value for enum case is not supported - -- id: enum_raw_value_used_here - msg: >- - raw value previously used here - -- id: enum_raw_value_incrementing_from_here - msg: >- - raw value auto-incremented from here - -- id: enum_raw_value_incrementing_from_zero - msg: >- - raw value implicitly auto-incremented from zero - -- id: construct_raw_representable_from_unwrapped_value - msg: >- - construct %0 from unwrapped %1 value - -- id: decl_from_hidden_module - msg: >- - cannot use %0 %1 %select{here|as property wrapper here|in an extension - with public or '@usableFromInline' members|in an extension with conditional - conformances}2; %select{%3 has been imported as implementation-only|it - is an SPI imported from %3|it is SPI}4 - -- id: conformance_from_implementation_only_module - msg: >- - cannot use conformance of %0 to %1 %select{here|as property wrapper - here|in an extension with public or '@usableFromInline' members|in - an extension with conditional conformances}2; - %3 has been imported as implementation-only - -- id: assoc_conformance_from_implementation_only_module - msg: >- - cannot use conformance of %0 to %1 in associated type %3 (inferred as - %4); %2 has been imported as implementation-only - -- id: unexportable_clang_function_type - msg: >- - cannot export the underlying C type of the function type %0; it may use - anonymous types or types defined outside of a module - -- id: warn_implementation_only_conflict - msg: >- - %0 inconsistently imported as implementation-only - -- id: implementation_only_conflict_here - msg: >- - imported as implementation-only here - -- id: implementation_only_decl_non_override - msg: >- - '@_implementationOnly' can only be used on overrides - -- id: implementation_only_override_changed_type - msg: >- - '@_implementationOnly' override must have the same type as the - declaration it overrides (%0) - -- id: implementation_only_override_without_attr - msg: >- - override of '@_implementationOnly' %0 should also be declared - '@_implementationOnly' - -- id: implementation_only_override_import_without_attr - msg: >- - override of %0 imported as implementation-only must be declared - '@_implementationOnly' - -- id: cannot_synthesize_init_in_extension_of_nonfinal - msg: >- - implementation of %0 for non-final class cannot be automatically - synthesized in extension because initializer requirement %1 can only be - satisfied by a 'required' initializer in the class definition - -- id: cannot_synthesize_in_crossfile_extension - msg: >- - implementation of %0 cannot be automatically synthesized in an extension - in a different file to the type - -- id: broken_additive_arithmetic_requirement - msg: >- - AdditiveArithmetic protocol is broken: unexpected requirement - -- id: broken_case_iterable_requirement - msg: >- - CaseIterable protocol is broken: unexpected requirement - -- id: broken_raw_representable_requirement - msg: >- - RawRepresentable protocol is broken: unexpected requirement - -- id: broken_comparable_requirement - msg: >- - Comparable protocol is broken: unexpected requirement - -- id: broken_equatable_requirement - msg: >- - Equatable protocol is broken: unexpected requirement - -- id: broken_hashable_requirement - msg: >- - Hashable protocol is broken: unexpected requirement - -- id: broken_hashable_no_hasher - msg: >- - Hashable protocol is broken: Hasher type not found - -- id: broken_errortype_requirement - msg: >- - Error protocol is broken: unexpected requirement - -- id: broken_int_hashable_conformance - msg: >- - Int type is broken: does not conform to Hashable - -- id: broken_int_integer_literal_convertible_conformance - msg: >- - Int type is broken: does not conform to ExpressibleByIntegerLiteral - -- id: no_less_than_overload_for_int - msg: >- - no overload of '<' for Int - -- id: no_equal_overload_for_int - msg: >- - no overload of '==' for Int - -- id: broken_coding_key_requirement - msg: >- - CodingKey protocol is broken: unexpected requirement - -- id: broken_encodable_requirement - msg: >- - Encodable protocol is broken: unexpected requirement - -- id: broken_decodable_requirement - msg: >- - Decodable protocol is broken: unexpected requirement - -- id: broken_differentiable_requirement - msg: >- - Differentiable protocol is broken: unexpected requirement - -- id: differentiable_nondiff_type_implicit_noderivative_fixit - msg: >- - stored property %0 has no derivative because %1 does not conform to - 'Differentiable'; add an explicit '@noDerivative' attribute%select{|, - or conform %2 to 'AdditiveArithmetic'}3 - -- id: differentiable_immutable_wrapper_implicit_noderivative_fixit - msg: >- - synthesis of the 'Differentiable.move(along:)' requirement for %1 - requires 'wrappedValue' in property wrapper %0 to be mutable; - add an explicit '@noDerivative' attribute%select{|, - or conform %1 to 'AdditiveArithmetic'}2 - -- id: differentiable_let_property_implicit_noderivative_fixit - msg: >- - synthesis of the 'Differentiable.move(along:)' requirement for %0 - requires all stored properties not marked with `@noDerivative` - to be mutable; use 'var' instead, or add an explicit - '@noDerivative' attribute%select{|, or conform %0 to 'AdditiveArithmetic'}1 - -- id: codable_extraneous_codingkey_case_here - msg: >- - CodingKey case %0 does not match any stored properties - -- id: codable_non_conforming_property_here - msg: >- - cannot automatically synthesize %0 because %1 does not conform to %0 - -- id: codable_non_decoded_property_here - msg: >- - cannot automatically synthesize %0 because %1 does not have a matching - CodingKey and does not have a default value - -- id: codable_codingkeys_type_is_not_an_enum_here - msg: >- - cannot automatically synthesize %0 because 'CodingKeys' is not an enum - -- id: codable_codingkeys_type_does_not_conform_here - msg: >- - cannot automatically synthesize %0 because 'CodingKeys' does not conform - to CodingKey - -- id: decodable_no_super_init_here - msg: >- - cannot automatically synthesize %0 because superclass does not have a - callable %1 - -- id: decodable_super_init_not_designated_here - msg: >- - cannot automatically synthesize %0 because implementation would need to - call %1, which is not designated - -- id: decodable_inaccessible_super_init_here - msg: >- - cannot automatically synthesize %0 because implementation would need to - call %1, which is inaccessible due to - '%select{private|fileprivate|internal|%error|%error}2' protection level - -- id: decodable_super_init_is_failable_here - msg: >- - cannot automatically synthesize %0 because implementation would need to - call %1, which is failable - -- id: decodable_suggest_overriding_init_here - msg: >- - did you mean to override 'init(from:)'? - -- id: codable_suggest_overriding_init_here - msg: >- - did you mean to override 'init(from:)' and 'encode(to:)'? - -- id: decodable_property_will_not_be_decoded - msg: >- - immutable property will not be decoded because it is declared with an - initial value which cannot be overwritten - -- id: decodable_property_init_or_codingkeys_implicit - msg: >- - set the initial value via the initializer or explicitly define a - CodingKeys enum %select{including|without}0 a %1 - case to silence this warning - -- id: decodable_property_init_or_codingkeys_explicit - msg: >- - set the initial value via the initializer or remove the %0 case from the - CodingKeys enum to silence this warning - -- id: decodable_make_property_mutable - msg: >- - make the property mutable instead - -- id: missing_member_type_conformance_prevents_synthesis - msg: >- - %select{associated value|stored property}0 type %1 does not conform to - protocol %2, preventing synthesized conformance of %3 to %2 - -- id: automatic_protocol_synthesis_unsupported - msg: >- - automatic synthesis of '%0' is not supported for %select{classes|structs}1 - -- id: comparable_synthesis_raw_value_not_allowed - msg: >- - enum declares raw type %0, preventing synthesized conformance of %1 to %2 - -- id: dynamic_self_non_method - msg: >- - %select{global|local}0 function cannot return 'Self' - -- id: dynamic_self_invalid - msg: >- - covariant 'Self' can only appear as the type of a property, subscript or - method result; did you mean '%0'? - -- id: dynamic_self_in_mutable_property - msg: >- - mutable property cannot have covariant 'Self' type - -- id: dynamic_self_in_stored_property - msg: >- - stored property cannot have covariant 'Self' type - -- id: dynamic_self_in_mutable_subscript - msg: >- - mutable subscript cannot have covariant 'Self' type - -- id: dynamic_self_invalid_property - msg: >- - covariant 'Self' can only appear at the top level of property type - -- id: dynamic_self_invalid_subscript - msg: >- - covariant 'Self' can only appear at the top level of subscript element - type - -- id: dynamic_self_invalid_method - msg: >- - covariant 'Self' can only appear at the top level of method result type - -- id: dynamic_self_stored_property_init - msg: >- - covariant 'Self' type cannot be referenced from a stored property - initializer - -- id: dynamic_self_default_arg - msg: >- - covariant 'Self' type cannot be referenced from a default argument - expression - -- id: attr_only_one_decl_kind - msg: >- - %0 may only be used on '%1' declarations - -- id: attr_not_on_variadic_parameters - msg: >- - '%0' must not be used on variadic parameters - -- id: attr_not_on_subscript_parameters - msg: >- - '%0' must not be used on subscript parameters - -- id: attr_ambiguous_reference_to_decl - msg: >- - ambiguous reference to %0 in '@%1' attribute - -- id: override_final - msg: >- - %0 overrides a 'final' %1 - -- id: override_static - msg: >- - cannot override %0 - -- id: member_cannot_be_final - msg: >- - only classes and class members may be marked with 'final' - -- id: final_not_allowed_here - msg: >- - 'final' may only be applied to classes, properties, methods, and subscripts - -- id: final_not_on_accessors - msg: >- - 'final' cannot be applied to accessors, it must be put on the - %select{var|let|subscript}0 - -- id: override_rethrows_with_non_rethrows - msg: >- - override of 'rethrows' %select{method|initializer}0 should also be - 'rethrows' - -- id: rethrows_without_throwing_parameter - msg: >- - 'rethrows' function must take a throwing function argument - -- id: autoclosure_function_type - msg: >- - @autoclosure attribute only applies to function types - -- id: invalid_autoclosure_and_convention_attributes - msg: >- - '@convention(%0)' attribute is not allowed on '@autoclosure' types - -- id: autoclosure_function_input_nonunit - msg: >- - argument type of @autoclosure parameter must be '()' - -- id: escaping_non_function_parameter - msg: >- - @escaping attribute may only be used in function parameter position - -- id: escaping_optional_type_argument - msg: >- - closure is already escaping in optional type argument - -- id: non_ephemeral_non_pointer_type - msg: >- - @_nonEphemeral attribute only applies to pointer types - -- id: attr_NSManaged_not_instance_member - msg: >- - @NSManaged only allowed on an instance property or method - -- id: attr_NSManaged_not_stored - msg: >- - @NSManaged not allowed on %select{computed|observing|addressed}0 properties - -- id: attr_NSManaged_let_property - msg: >- - @NSManaged not allowed on a 'let' property - -- id: attr_NSManaged_initial_value - msg: >- - @NSManaged property cannot have an initial value - -- id: attr_NSManaged_NSCopying - msg: >- - @NSManaged property cannot also be marked @NSCopying - -- id: attr_NSManaged_method_body - msg: >- - @NSManaged method cannot have a body; it must be provided at runtime - -- id: nscopying_only_on_class_properties - msg: >- - @NSCopying may only be used on properties in classes - -- id: nscopying_only_mutable - msg: >- - @NSCopying requires property to be mutable - -- id: nscopying_only_stored_property - msg: >- - @NSCopying is only valid on stored properties - -- id: nscopying_doesnt_conform - msg: >- - @NSCopying is only valid with types that conform to the NSCopying protocol - -- id: attr_ApplicationMain_not_ApplicationDelegate - msg: >- - %select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 class must - conform to the %select{'UIApplicationDelegate'|'NSApplicationDelegate'}0 - protocol - -- id: attr_generic_ApplicationMain_not_supported - msg: >- - generic %select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 - %select{classes|classes|types}0 are not supported - -- id: attr_ApplicationMain_multiple - msg: >- - %select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 attribute can - only apply to one %select{class|class|type}0 in a module - -- id: attr_ApplicationMain_with_script - msg: >- - %select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 attribute cannot - be used in a module that contains top-level code - -- id: attr_ApplicationMain_script_here - msg: >- - top-level code defined in this source file - -- id: attr_MainType_without_main - msg: >- - %0 is annotated with @main and must provide a main static function of - type () -> Void or () throws -> Void. - -- id: lazy_not_on_let - msg: >- - 'lazy' cannot be used on a let - -- id: lazy_not_on_computed - msg: >- - 'lazy' must not be used on a computed property - -- id: lazy_on_already_lazy_global - msg: >- - 'lazy' must not be used on an already-lazy global - -- id: lazy_not_in_protocol - msg: >- - 'lazy' isn't allowed on a protocol requirement - -- id: lazy_requires_initializer - msg: >- - lazy properties must have an initializer - -- id: lazy_requires_single_var - msg: >- - 'lazy' cannot destructure an initializer - -- id: lazy_must_be_property - msg: >- - lazy is only valid for members of a struct or class - -- id: lazy_not_strong - msg: >- - lazy properties cannot be %0 - -- id: attr_for_debugger_support_only - msg: >- - @LLDBDebuggerSupport may only be used when debugger support is on - -- id: implements_attr_protocol_lacks_member - msg: >- - protocol %0 has no member %1 - -- id: implements_attr_non_protocol_type - msg: >- - non-protocol type in @_implements attribute - -- id: implements_attr_protocol_not_conformed_to - msg: >- - containing type %0 does not conform to protocol %1 - -- id: differentiable_attr_no_vjp_or_jvp_when_linear - msg: >- - cannot specify 'vjp:' or 'jvp:' for linear functions; use '@transpose' - attribute for transpose registration instead - -- id: differentiable_attr_overload_not_found - msg: >- - %0 does not have expected type %1 - -- id: differentiable_attr_duplicate - msg: >- - duplicate '@differentiable' attribute with same parameters - -- id: differentiable_attr_duplicate_note - msg: >- - other attribute declared here - -- id: differentiable_attr_function_not_same_type_context - msg: >- - %0 is not defined in the current type context - -- id: differentiable_attr_derivative_not_function - msg: >- - registered derivative %0 must be a 'func' declaration - -- id: differentiable_attr_class_derivative_not_final - msg: >- - class member derivative must be final - -- id: differentiable_attr_invalid_access - msg: >- - derivative function %0 is required to either be public or - '@usableFromInline' because the original function %1 is public or - '@usableFromInline' - -- id: differentiable_attr_protocol_req_where_clause - msg: >- - '@differentiable' attribute on protocol requirement cannot specify - 'where' clause - -- id: differentiable_attr_class_member_dynamic_self_result_unsupported - msg: >- - '@differentiable' attribute cannot be declared on class members returning - 'Self' - -- id: differentiable_attr_nonfinal_class_init_unsupported - msg: >- - '@differentiable' attribute cannot be declared on 'init' in a non-final - class; consider making %0 final - -- id: differentiable_attr_empty_where_clause - msg: >- - empty 'where' clause in '@differentiable' attribute - -- id: differentiable_attr_where_clause_for_nongeneric_original - msg: >- - 'where' clause is valid only when original function is generic %0 - -- id: differentiable_attr_layout_req_unsupported - msg: >- - '@differentiable' attribute does not yet support layout requirements - -- id: overriding_decl_missing_differentiable_attr - msg: >- - overriding declaration is missing attribute '%0' - -- id: protocol_witness_missing_differentiable_attr - msg: >- - candidate is missing attribute '%0' - -- id: protocol_witness_missing_differentiable_attr_nonpublic_other_file - msg: >- - non-public %1 %2 must have explicit '%0' attribute to satisfy requirement - %3 %4 (in protocol %6) because it is declared in a different file than the - conformance of %5 to %6 - -- id: derivative_attr_expected_result_tuple - msg: >- - '@derivative(of:)' attribute requires function to return a two-element - tuple; first element must have label 'value:' and second element - must have label 'pullback:' or 'differential:' - -- id: derivative_attr_invalid_result_tuple_value_label - msg: >- - '@derivative(of:)' attribute requires function to return a two-element - tuple; first element must have label 'value:' - -- id: derivative_attr_invalid_result_tuple_func_label - msg: >- - '@derivative(of:)' attribute requires function to return a two-element - tuple; second element must have label 'pullback:' or 'differential:' - -- id: derivative_attr_result_value_not_differentiable - msg: >- - '@derivative(of:)' attribute requires function to return a two-element - tuple; first element type %0 must conform to 'Differentiable' - -- id: derivative_attr_result_func_type_mismatch - msg: >- - function result's %0 type does not match %1 - -- id: derivative_attr_result_func_type_mismatch_note - msg: >- - %0 does not have expected type %1 - -- id: derivative_attr_result_func_original_note - msg: >- - %0 defined here - -- id: derivative_attr_not_in_same_file_as_original - msg: >- - derivative not in the same file as the original function - -- id: derivative_attr_original_stored_property_unsupported - msg: >- - cannot register derivative for stored property %0 - -- id: derivative_attr_class_member_dynamic_self_result_unsupported - msg: >- - cannot register derivative for class member %0 returning 'Self' - -- id: derivative_attr_nonfinal_class_init_unsupported - msg: >- - cannot register derivative for 'init' in a non-final class; consider - making %0 final - -- id: derivative_attr_class_setter_unsupported - msg: >- - cannot yet register derivative for class property or subscript setters - -- id: derivative_attr_original_already_has_derivative - msg: >- - a derivative already exists for %0 - -- id: derivative_attr_duplicate_note - msg: >- - other attribute declared here - -- id: derivative_attr_access_level_mismatch - msg: >- - derivative function must have same access level as original function; - derivative function %2 is %select{private|fileprivate|internal|public|open}3, - but original function %0 is %select{private|fileprivate|internal|public|open}1 - -- id: derivative_attr_fix_access - msg: >- - mark the derivative function as - '%select{private|fileprivate|internal|@usableFromInline|@usableFromInline}0' - to match the original function - -- id: transpose_attr_invalid_linearity_parameter_or_result - msg: >- - cannot transpose with respect to original %select{result|parameter}1 '%0' - that does not conform to 'Differentiable' and satisfy '%0 == %0.TangentVector' - -- id: transpose_attr_overload_not_found - msg: >- - could not find function %0 with expected type %1 - -- id: transpose_attr_cannot_use_named_wrt_params - msg: >- - cannot use named 'wrt' parameters in '@transpose(of:)' attribute, found %0 - -- id: transpose_attr_wrt_self_must_be_static - msg: >- - the transpose of an instance method must be a 'static' method in the same - type when 'self' is a linearity parameter - -- id: transpose_attr_wrt_self_self_type_mismatch_note - msg: >- - the transpose is declared in %0 but the original function is declared in %1 - -- id: autodiff_attr_original_decl_invalid_kind - msg: >- - %0 is not a 'func', 'init', 'subscript', or 'var' computed property - declaration - -- id: autodiff_attr_original_decl_not_same_type_context - msg: >- - %0 is not defined in the current type context - -- id: autodiff_attr_original_void_result - msg: >- - cannot differentiate void function %0 - -- id: autodiff_attr_original_multiple_semantic_results - msg: >- - cannot differentiate functions with both an 'inout' parameter and a result - -- id: autodiff_attr_result_not_differentiable - msg: >- - can only differentiate functions with results that conform to - 'Differentiable', but %0 does not conform to 'Differentiable' - -- id: diff_function_no_parameters - msg: >- - %0 has no parameters to differentiate with respect to - -- id: diff_params_clause_param_name_unknown - msg: >- - unknown parameter name %0 - -- id: diff_params_clause_self_instance_method_only - msg: >- - 'self' parameter is only applicable to instance methods - -- id: diff_params_clause_self_must_be_first - msg: >- - 'self' parameter must come first in the parameter list - -- id: diff_params_clause_params_not_original_order - msg: >- - parameters must be specified in original order - -- id: diff_params_clause_param_index_out_of_range - msg: >- - parameter index is larger than total number of parameters - -- id: diff_params_clause_no_inferred_parameters - msg: >- - no differentiation parameters could be inferred; must differentiate with - respect to at least one parameter conforming to 'Differentiable' - -- id: diff_params_clause_cannot_diff_wrt_inout_parameter - msg: >- - cannot differentiate with respect to 'inout' parameter (%0) - -- id: diff_params_clause_param_not_differentiable - msg: >- - can only differentiate with respect to parameters that conform to - 'Differentiable', but %0 does not conform to 'Differentiable' - -- id: found_candidate - msg: >- - found this candidate - -- id: found_candidate_type - msg: >- - found candidate with type %0 - -- id: no_MaxBuiltinFloatType_found - msg: >- - standard library error: _MaxBuiltinFloatType is not properly defined - -- id: no_member_of_module - msg: >- - module %0 has no member named %1 - -- id: super_with_no_base_class - msg: >- - 'super' members cannot be referenced in a root class - -- id: bad_init_ref_base - msg: >- - 'init' can only refer to the initializers of 'self'%select{| or 'super'}0 - -- id: init_delegation_outside_initializer - msg: >- - initializer delegation can only occur within an initializer - -- id: init_delegates_and_chains - msg: >- - initializer cannot both delegate ('self.init') and chain to a superclass - initializer ('super.init') - -- id: init_delegation_or_chain - msg: >- - previous %select{delegation|chaining}0 call is here - -- id: delegating_convenience_super_init - msg: >- - convenience initializer for %0 must delegate (with 'self.init') rather - than chaining to a superclass initializer (with 'super.init') - -- id: delegating_designated_init - msg: >- - designated initializer for %0 cannot delegate (with 'self.init'); did you - mean this to be a convenience initializer? - -- id: delegating_designated_init_in_extension - msg: >- - designated initializer for %0 cannot delegate (with 'self.init') - -- id: delegation_here - msg: >- - delegation occurs here - -- id: chain_convenience_init - msg: >- - must call a designated initializer of the superclass %0 - -- id: delegate_chain_nonoptional_to_optional - msg: >- - a non-failable initializer cannot %select{delegate|chain}0 to failable - initializer %1 written with 'init?' - -- id: init_force_unwrap - msg: >- - force potentially-failing result with '!' - -- id: init_propagate_failure - msg: >- - propagate the failure with 'init?' - -- id: delegate_chain_nonoptional_to_optional_try - msg: >- - a non-failable initializer cannot use 'try?' to %select{delegate|chain}0 - to another initializer - -- id: init_delegate_force_try - msg: >- - force potentially-failing result with 'try!' - -- id: init_delegation_nested - msg: >- - %select{initializer delegation ('self.init')|initializer chaining - ('super.init')}0 cannot be nested in another %select{expression|statement}1 - -- id: convenience_init_here - msg: >- - convenience initializer is declared here - -- id: designated_init_in_extension - msg: >- - designated initializer cannot be declared in an extension of %0; did you - mean this to be a convenience initializer? - -- id: cfclass_designated_init_in_extension - msg: >- - designated initializer cannot be declared in an extension of %0 - -- id: enumstruct_convenience_init - msg: >- - delegating initializers in %0 are not marked with 'convenience' - -- id: nonclass_convenience_init - msg: >- - convenience initializer not allowed in non-class type %0 - -- id: cfclass_convenience_init - msg: >- - convenience initializers are not supported in extensions of CF types - -- id: dynamic_construct_class - msg: >- - constructing an object of class type %0 with a metatype value must use a - 'required' initializer - -- id: note_nonrequired_initializer - msg: >- - selected %select{non-required|implicit}0 initializer %1 - -- id: construct_protocol_value - msg: >- - value of type %0 is a protocol; it cannot be instantiated - -- id: construct_protocol_by_name - msg: >- - protocol type %0 cannot be instantiated - -- id: unknown_binop - msg: >- - operator is not a known binary operator - -- id: non_associative_adjacent_operators - msg: >- - adjacent operators are in non-associative precedence group %0 - -- id: unordered_adjacent_operators - msg: >- - adjacent operators are in unordered precedence groups %0 and %1 - -- id: missing_builtin_precedence_group - msg: >- - broken standard library: missing builtin precedence group %0 - -- id: try_rhs - msg: >- - '%select{try|try!|try?}0' cannot appear to the right of a non-assignment - operator - -- id: try_if_rhs_noncovering - msg: >- - '%select{try|try!|try?}0' following conditional operator does not cover - everything to its right - -- id: try_assign_rhs_noncovering - msg: >- - '%select{try|try!|try?}0' following assignment operator does not cover - everything to its right - -- id: broken_bool - msg: >- - type 'Bool' is broken - -- id: inject_forced_downcast - msg: >- - treating a forced downcast to %0 as optional will never produce 'nil' - -- id: forced_to_conditional_downcast - msg: >- - use 'as?' to perform a conditional downcast to %0 - -- id: silence_inject_forced_downcast - msg: >- - add parentheses around the cast to silence this warning - -- id: conditional_downcast_foreign - msg: >- - conditional downcast to CoreFoundation type %0 will always succeed - -- id: note_explicitly_compare_cftypeid - msg: >- - did you mean to explicitly compare the CFTypeIDs of %0 and %1? - -- id: optional_used_as_boolean - msg: >- - optional type %0 cannot be used as a boolean; test for '%select{!|=}1= - nil' instead - -- id: integer_used_as_boolean - msg: >- - type %0 cannot be used as a boolean; test for '%select{!|=}1= 0' instead - -- id: interpolation_missing_proto - msg: >- - string interpolation requires the protocol - 'ExpressibleByStringInterpolation' to be defined - -- id: interpolation_broken_proto - msg: >- - protocol 'ExpressibleByStringInterpolation' is broken - -- id: object_literal_broken_proto - msg: >- - object literal protocol is broken - -- id: discard_expr_outside_of_assignment - msg: >- - '_' can only appear in a pattern or on the left side of an assignment - -- id: discard_expr_void_result_redundant - msg: >- - using '_' to ignore the result of a Void-returning function is redundant - -- id: collection_literal_heterogeneous - msg: >- - heterogeneous collection literal could only be inferred to %0; add - explicit type annotation if this is intentional - -- id: collection_literal_empty - msg: >- - empty collection literal requires an explicit type - -- id: unresolved_member_no_inference - msg: >- - reference to member %0 cannot be resolved without a contextual type - -- id: cannot_infer_base_of_unresolved_member - msg: >- - cannot infer contextual base in reference to member %0 - -- id: unresolved_nil_literal - msg: >- - 'nil' requires a contextual type - -- id: cannot_force_unwrap_nil_literal - msg: >- - 'nil' literal cannot be force unwrapped - -- id: type_of_expression_is_ambiguous - msg: >- - type of expression is ambiguous without more context - -- id: failed_to_produce_diagnostic - msg: >- - failed to produce diagnostic for expression; please file a bug report - -- id: missing_protocol - msg: >- - missing protocol %0 - -- id: nil_literal_broken_proto - msg: >- - protocol 'ExpressibleByNilLiteral' is broken - -- id: builtin_integer_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinIntegerLiteral' is broken - -- id: integer_literal_broken_proto - msg: >- - protocol 'ExpressibleByIntegerLiteral' is broken - -- id: builtin_float_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinFloatLiteral' is broken - -- id: float_literal_broken_proto - msg: >- - protocol 'ExpressibleByFloatLiteral' is broken - -- id: builtin_boolean_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinBooleanLiteral' is broken - -- id: boolean_literal_broken_proto - msg: >- - protocol 'ExpressibleByBooleanLiteral' is broken - -- id: builtin_unicode_scalar_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinUnicodeScalarLiteral' is broken - -- id: unicode_scalar_literal_broken_proto - msg: >- - protocol 'ExpressibleByUnicodeScalarLiteral' is broken - -- id: builtin_extended_grapheme_cluster_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinExtendedGraphemeClusterLiteral' is broken - -- id: extended_grapheme_cluster_literal_broken_proto - msg: >- - protocol 'ExpressibleByExtendedGraphemeClusterLiteral' is broken - -- id: builtin_string_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinStringLiteral' is broken - -- id: string_literal_broken_proto - msg: >- - protocol 'ExpressibleByStringLiteral' is broken - -- id: should_use_dictionary_literal - msg: >- - dictionary of type %0 cannot be %select{used|initialized}1 with array - literal - -- id: meant_dictionary_lit - msg: >- - did you mean to use a dictionary literal instead? - -- id: should_use_empty_dictionary_literal - msg: >- - use [:] to get an empty dictionary literal - -- id: type_is_not_dictionary - msg: >- - contextual type %0 cannot be used with dictionary literal - -- id: cannot_explicitly_specialize_generic_function - msg: >- - cannot explicitly specialize a generic function - -- id: not_a_generic_definition - msg: >- - cannot specialize a non-generic definition - -- id: not_a_generic_type - msg: >- - cannot specialize non-generic type %0 - -- id: type_parameter_count_mismatch - msg: >- - generic type %0 specialized with %select{too many|too few}3 type - parameters (got %2, but expected %1) - -- id: generic_type_requires_arguments - msg: >- - reference to generic type %0 requires arguments in <...> - -- id: descriptive_generic_type_declared_here - msg: >- - %0 declared here - -- id: use_of_void_pointer - msg: >- - Unsafe%0Pointer has been replaced by Unsafe%0RawPointer - -- id: ambiguous_decl_ref - msg: >- - ambiguous use of %0 - -- id: ambiguous_operator_ref - msg: >- - ambiguous use of operator %0 - -- id: ambiguous_because_of_trailing_closure - msg: >- - %select{use an explicit argument label instead of a trailing - closure|avoid using a trailing closure}0 to call %1 - -- id: partial_application_of_function_invalid - msg: >- - partial application of %select{'mutating' method|'super.init' initializer - chain|'self.init' initializer delegation|'super' instance method with - metatype base}0 is not allowed - -- id: partial_application_of_function_invalid_swift4 - msg: >- - partial application of %select{'mutating' method|'super.init' initializer - chain|'self.init' initializer delegation|'super' instance method with - metatype base}0 is not allowed; calling the function has undefined - behavior and will be an error in future Swift versions - -- id: self_assignment_var - msg: >- - assigning a variable to itself - -- id: self_assignment_prop - msg: >- - assigning a property to itself - -- id: property_use_in_closure_without_explicit_self - msg: >- - reference to property %0 in closure requires explicit use of 'self' to - make capture semantics explicit - -- id: method_call_in_closure_without_explicit_self - msg: >- - call to method %0 in closure requires explicit use of 'self' to make - capture semantics explicit - -- id: note_capture_self_explicitly - msg: >- - capture 'self' explicitly to enable implicit 'self' in this closure - -- id: note_reference_self_explicitly - msg: >- - reference 'self.' explicitly - -- id: note_other_self_capture - msg: >- - variable other than 'self' captured here under the name 'self' does not - enable implicit 'self' - -- id: note_self_captured_weakly - msg: >- - weak capture of 'self' here does not enable implicit 'self' - -- id: implicit_use_of_self_in_closure - msg: >- - implicit use of 'self' in closure; use 'self.' to make capture semantics - explicit - -- id: recursive_accessor_reference - msg: >- - attempting to %select{access|modify}1 %0 within its own - %select{getter|setter}1 - -- id: recursive_accessor_reference_silence - msg: >- - access 'self' explicitly to silence this warning - -- id: store_in_willset - msg: >- - attempting to store to property %0 within its own willSet, which is about - to be overwritten by the new value - -- id: value_of_module_type - msg: >- - expected module member name after module name - -- id: value_of_metatype_type - msg: >- - expected member name or constructor call after type name - -- id: add_parens_to_type - msg: >- - add arguments after the type to construct a value of the type - -- id: add_self_to_type - msg: >- - use '.self' to reference the type object - -- id: warn_unqualified_access - msg: >- - use of %0 treated as a reference to %1 in %2 %3 - -- id: fix_unqualified_access_member - msg: >- - use 'self.' to silence this warning - -- id: fix_unqualified_access_top_level - msg: >- - use '%0' to reference the %1 - -- id: fix_unqualified_access_top_level_multi - msg: >- - use '%0' to reference the %1 in module %2 - -- id: warn_deprecated_conditional_conformance_outer_access - msg: >- - use of %0 as reference to %1 in %2 %3 will change in future versions of - Swift to reference %4 in %5 %6 which comes via a conditional conformance - -- id: fix_deprecated_conditional_conformance_outer_access - msg: >- - use '%0' to continue to reference the %1 - -- id: unsupported_special_decl_ref - msg: >- - referencing %0 as a function value is not implemented - -- id: bitcasting_away_noescape - msg: >- - 'unsafeBitCast' from non-escaping function type %0 to escaping function - type %1 is undefined; use 'withoutActuallyEscaping' to temporarily escape a - function - -- id: bitcasting_to_change_function_rep - msg: >- - 'unsafeBitCast' from function type %0 to %1 changes @convention and is - undefined; use an implicit conversion to change conventions - -- id: bitcasting_to_downcast - msg: >- - 'unsafeBitCast' from %0 to %1 can be replaced with 'unsafeDowncast' - -- id: bitcasting_is_no_op - msg: >- - 'unsafeBitCast' from %0 to %1 is unnecessary and can be removed - -- id: bitcasting_to_change_pointer_kind - msg: >- - 'unsafeBitCast' from %0 to %1 can be replaced with %2 initializer - -- id: bitcasting_to_change_pointee_type - msg: >- - 'unsafeBitCast' from %0 to %1 changes pointee type and may lead to - undefined behavior; use the 'withMemoryRebound' method on %0 - to rebind the type of memory - -- id: bitcasting_to_give_type_to_raw_pointer - msg: >- - 'unsafeBitCast' from %0 to %1 gives a type to a raw pointer and may lead - to undefined behavior - -- id: bitcast_assume_memory_rebound - msg: >- - use the 'assumingMemoryBound' method if the pointer is known to point to - an existing value or array of type %0 in memory - -- id: bitcast_bind_memory - msg: >- - use the 'bindMemory' method to assign type %0 to uninitialized raw memory - -- id: bitcasting_for_number_bit_pattern_init - msg: >- - 'unsafeBitCast' from %0 to %1 can be replaced with 'bitPattern:' - initializer on %1 - -- id: bitcasting_for_number_bit_pattern_property - msg: >- - 'unsafeBitCast' from %0 to %1 can be replaced with 'bitPattern' property - on %0 - -- id: bitcasting_to_change_from_unsized_to_sized_int - msg: >- - 'unsafeBitCast' from %0 to %1 can be replaced with %1 initializer - -- id: use_of_qq_on_non_optional_value - msg: >- - left side of nil coalescing operator '??' has non-optional type %0, so - the right side is never used - -- id: nonoptional_compare_to_nil - msg: >- - comparing non-optional value of type %0 to 'nil' always returns - %select{false|true}1 - -- id: optional_check_nonoptional - msg: >- - non-optional expression of type %0 used in a check for optionals - -- id: optional_check_promotion - msg: >- - explicitly specified type %0 adds an additional level of optional to the - initializer, making the optional check always succeed - -- id: optional_pattern_match_promotion - msg: >- - pattern match introduces an implicit promotion from %0 to %1 - -- id: optional_to_any_coercion - msg: >- - expression implicitly coerced from %0 to %1 - -- id: iuo_to_any_coercion - msg: >- - coercion of implicitly unwrappable value of type %0 to %1 does not unwrap - optional - -- id: iuo_to_any_coercion_note - msg: >- - implicitly unwrapped %0 %1 declared here - -- id: iuo_to_any_coercion_note_func_result - msg: >- - %0 %1 with implicitly unwrapped result type is declared here - -- id: default_optional_to_any - msg: >- - provide a default value to avoid this warning - -- id: force_optional_to_any - msg: >- - force-unwrap the value to avoid this warning - -- id: silence_optional_to_any - msg: >- - explicitly cast to %0 with '%1' to silence this warning - -- id: debug_description_in_string_interpolation_segment - msg: >- - string interpolation produces a debug description for %select{an - optional|a function}0 value; did you mean to make this explicit? - -- id: silence_debug_description_in_interpolation_segment_call - msg: >- - use 'String(describing:)' to silence this warning - -- id: noescape_parameter - msg: >- - parameter %0 is implicitly non-escaping - -- id: generic_parameters_always_escaping - msg: >- - generic parameters are always considered '@escaping' - -- id: passing_noescape_to_escaping - msg: >- - passing non-escaping parameter %0 to function expecting an @escaping closure - -- id: converting_noespace_param_to_generic_type - msg: >- - converting non-escaping parameter %0 to generic parameter %1 may allow it - to escape - -- id: assigning_noescape_to_escaping - msg: >- - assigning non-escaping parameter %0 to an @escaping closure - -- id: general_noescape_to_escaping - msg: >- - using non-escaping parameter %0 in a context expecting an @escaping closure - -- id: converting_noescape_to_type - msg: >- - converting non-escaping value to %0 may allow it to escape - -- id: capture_across_type_decl - msg: >- - %0 declaration cannot close over value %1 defined in outer scope - -- id: jump_out_of_defer - msg: >- - '%0' cannot transfer control out of a defer statement - -- id: defer_stmt_at_block_end - msg: >- - 'defer' statement at end of scope always executes immediately; replace - with 'do' statement to silence this warning - -- id: return_invalid_outside_func - msg: >- - return invalid outside of a func - -- id: return_expr_missing - msg: >- - non-void function should return a value - -- id: return_non_failable_init - msg: >- - only a failable initializer can return 'nil' - -- id: make_init_failable - msg: >- - use 'init?' to make the initializer %0 failable - -- id: return_init_non_nil - msg: >- - 'nil' is the only return value permitted in an initializer - -- id: if_always_true - msg: >- - 'if' condition is always true - -- id: while_always_true - msg: >- - 'while' condition is always true - -- id: guard_always_succeeds - msg: >- - 'guard' condition is always true, body is unreachable - -- id: expression_unused_closure - msg: >- - closure expression is unused - -- id: expression_unused_function - msg: >- - expression resolves to an unused function - -- id: expression_unused_lvalue - msg: >- - expression resolves to an unused %select{variable|property|subscript}0 - -- id: expression_unused_result_call - msg: >- - result of call to %0 is unused - -- id: expression_unused_result_operator - msg: >- - result of operator %0 is unused - -- id: expression_unused_result_unknown - msg: >- - result of call to %select{function|closure}0 returning %1 is unused - -- id: expression_unused_result - msg: >- - expression of type %0 is unused - -- id: expression_unused_init_result - msg: >- - result of %0 initializer is unused - -- id: expression_unused_optional_try - msg: >- - result of 'try?' is unused - -- id: expression_unused_selector_result - msg: >- - result of '#selector' is unused - -- id: expression_unused_literal - msg: >- - %0 literal is unused - -- id: assignment_lhs_not_lvalue - msg: >- - cannot assign to immutable expression of type %0 - -- id: assignment_lhs_is_apply_expression - msg: >- - expression is not assignable: %0 - -- id: assignment_lhs_is_immutable_variable - msg: >- - cannot assign to value: %0 - -- id: assignment_lhs_is_immutable_property - msg: >- - cannot assign to property: %0 - -- id: assignment_subscript_has_immutable_base - msg: >- - cannot assign through subscript: %0 - -- id: assignment_dynamic_property_has_immutable_base - msg: >- - cannot assign through dynamic lookup property: %0 - -- id: assignment_bang_has_immutable_subcomponent - msg: >- - cannot assign through '!': %0 - -- id: candidate_is_not_assignable - msg: >- - candidate is not assignable: %0 %1 - -- id: change_to_mutating - msg: >- - mark %select{method|accessor}0 'mutating' to make 'self' mutable - -- id: masked_mutable_property - msg: >- - add explicit '%0' to refer to mutable %1 of %2 - -- id: assignment_let_property_delegating_init - msg: >- - 'let' property %0 may not be initialized directly; use "self.init(...)" - or "self = ..." instead - -- id: label_shadowed - msg: >- - label %0 cannot be reused on an inner statement - -- id: break_outside_loop - msg: >- - 'break' is only allowed inside a loop, if, do, or switch - -- id: unlabeled_break_outside_loop - msg: >- - unlabeled 'break' is only allowed inside a loop or switch, a labeled - break is required to exit an if or do - -- id: continue_outside_loop - msg: >- - 'continue' is only allowed inside a loop - -- id: continue_not_in_this_stmt - msg: >- - 'continue' cannot be used with %0 statements - -- id: unresolved_label - msg: >- - cannot find label %0 in scope - -- id: unresolved_label_corrected - msg: >- - cannot find label %0 in scope; did you mean %1? - -- id: foreach_sequence_does_not_conform_to_expected_protocol - msg: >- - for-in loop requires %0 to conform to %1%select{|; did you mean to unwrap - optional?}2 - -- id: no_match_operator - msg: >- - no binary '~=' operator available for 'switch' statement - -- id: fallthrough_outside_switch - msg: >- - 'fallthrough' is only allowed inside a switch - -- id: fallthrough_from_last_case - msg: >- - 'fallthrough' without a following 'case' or 'default' block - -- id: fallthrough_into_case_with_var_binding - msg: >- - 'fallthrough' from a case which doesn't bind variable %0 - -- id: unnecessary_cast_over_optionset - msg: >- - unnecessary cast over raw value of %0 - -- id: mutability_mismatch_multiple_pattern_list - msg: >- - '%select{var|let}0' pattern binding must match previous - '%select{var|let}1' pattern binding - -- id: type_mismatch_multiple_pattern_list - msg: >- - pattern variable bound to type %0, expected type %1 - -- id: type_mismatch_fallthrough_pattern_list - msg: >- - pattern variable bound to type %0, fallthrough case bound to type %1 - -- id: unknown_case_must_be_catchall - msg: >- - '@unknown' is only supported for catch-all cases ("case _") - -- id: unknown_case_where_clause - msg: >- - 'where' cannot be used with '@unknown' - -- id: unknown_case_multiple_patterns - msg: >- - '@unknown' cannot be applied to multiple patterns - -- id: unknown_case_must_be_last - msg: >- - '@unknown' can only be applied to the last case in a switch - -- id: where_on_one_item - msg: >- - 'where' only applies to the second pattern match in this case - -- id: add_where_newline - msg: >- - disambiguate by adding a line break between them if this is desired - -- id: duplicate_where - msg: >- - duplicate the 'where' on both patterns to check both patterns - -- id: trailing_closure_requires_parens - msg: >- - trailing closure in this context is confusable with the body of the - statement; pass as a parenthesized argument to silence this warning - -- id: opaque_type_var_no_init - msg: >- - property declares an opaque return type, but has no initializer - expression from which to infer an underlying type - -- id: opaque_type_no_underlying_type_candidates - msg: >- - function declares an opaque return type, but has no return statements in - its body from which to infer an underlying type - -- id: opaque_type_mismatched_underlying_type_candidates - msg: >- - function declares an opaque return type, but the return statements in its - body do not have matching underlying types - -- id: opaque_type_underlying_type_candidate_here - msg: >- - return statement has underlying type %0 - -- id: opaque_type_self_referential_underlying_type - msg: >- - function opaque return type was inferred as %0, which defines the opaque - type in terms of itself - -- id: opaque_type_var_no_underlying_type - msg: >- - property declares an opaque return type, but cannot infer the underlying - type from its initializer expression - -- id: cannot_infer_type_for_pattern - msg: >- - type annotation missing in pattern - -- id: refutable_pattern_requires_initializer - msg: >- - pattern matching requires an initializer value to match against - -- id: var_pattern_didnt_bind_variables - msg: >- - '%0' pattern has no effect; sub-pattern didn't bind any variables - -- id: iflet_pattern_matching - msg: >- - pattern matching in a condition requires the 'case' keyword - -- id: iflet_implicitly_unwraps - msg: >- - pattern matching in a condition implicitly unwraps optionals - -- id: type_pattern_missing_is - msg: >- - 'is' keyword required to pattern match against type name - -- id: pattern_type_mismatch_context - msg: >- - type annotation does not match contextual type %0 - -- id: tuple_pattern_in_non_tuple_context - msg: >- - tuple pattern cannot match values of the non-tuple type %0 - -- id: found_one_pattern_for_several_associated_values - msg: >- - enum case '%0' has %1 associated values; matching them as a tuple is - deprecated - -- id: converting_tuple_into_several_associated_values - msg: >- - enum case '%0' has %1 associated values - -- id: converting_several_associated_values_into_tuple - msg: >- - enum case '%0' has one associated value that is a tuple of %1 elements - -- id: closure_argument_list_tuple - msg: >- - contextual closure type %0 expects %1 argument%s1, but %2 - %select{were|was}3 used in closure body - -- id: closure_argument_list_missing - msg: >- - contextual type for closure argument list expects %0 argument%s0, which - cannot be implicitly ignored - -- id: closure_tuple_parameter_destructuring - msg: >- - closure tuple parameter %0 does not support destructuring - -- id: closure_tuple_parameter_destructuring_implicit - msg: >- - closure tuple parameter %0 does not support destructuring with implicit - parameters - -- id: single_tuple_parameter_mismatch_special - msg: >- - %0 expects a single parameter of type %1%2 - -- id: single_tuple_parameter_mismatch_normal - msg: >- - %0 %1 expects a single parameter of type %2%3 - -- id: cannot_convert_single_tuple_into_multiple_arguments - msg: >- - %0 %select{%1 |}2expects %3 separate arguments%select{|; remove extra - parentheses to change tuple into separate arguments}4 - -- id: enum_element_pattern_assoc_values_mismatch - msg: >- - pattern with associated values does not match enum case %0 - -- id: enum_element_pattern_assoc_values_remove - msg: >- - remove associated values to make the pattern match - -- id: tuple_pattern_length_mismatch - msg: >- - tuple pattern has the wrong length for tuple type %0 - -- id: tuple_pattern_label_mismatch - msg: >- - tuple pattern element label %0 must be %1 - -- id: enum_element_pattern_member_not_found - msg: >- - enum case %0 not found in type %1 - -- id: optional_element_pattern_not_valid_type - msg: >- - '?' pattern cannot match values of type %0 - -- id: condition_optional_element_pattern_not_valid_type - msg: >- - initializer for conditional binding must have Optional type, not %0 - -- id: enum_element_pattern_not_member_of_enum - msg: >- - enum case %0 is not a member of type %1 - -- id: ambiguous_enum_pattern_type - msg: >- - generic enum type %0 is ambiguous without explicit generic parameters - when matching value of type %1 - -- id: type_inferred_to_undesirable_type - msg: >- - %select{variable|constant}2 %0 inferred to have type %1, which may be - unexpected - -- id: type_inferred_to_uninhabited_type - msg: >- - %select{variable|constant}2 %0 inferred to have type %1, which is an enum - with no cases - -- id: type_inferred_to_uninhabited_tuple_type - msg: >- - %select{variable|constant}2 %0 inferred to have type %1, which contains - an enum with no cases - -- id: add_explicit_type_annotation_to_silence - msg: >- - add an explicit type annotation to silence this warning - -- id: unowned_assignment_immediate_deallocation - msg: >- - instance will be immediately deallocated because - %select{variable|property}2 %0 is %1 - -- id: unowned_assignment_requires_strong - msg: >- - a strong reference is required to prevent the instance from being - deallocated - -- id: isa_collection_downcast_pattern_value_unimplemented - msg: >- - collection downcast in cast pattern is not implemented; use an explicit - downcast to %0 instead - -- id: try_unhandled - msg: >- - errors thrown from here are not handled - -- id: throwing_call_unhandled - msg: >- - call can throw, but the error is not handled - -- id: tryless_throwing_call_unhandled - msg: >- - call can throw, but it is not marked with 'try' and the error is not handled - -- id: throw_in_nonthrowing_function - msg: >- - error is not handled because the enclosing function is not declared 'throws' - -- id: throwing_call_in_rethrows_function - msg: >- - call can throw, but the error is not handled; a function declared - 'rethrows' may only throw if its parameter does - -- id: tryless_throwing_call_in_rethrows_function - msg: >- - 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 - -- id: throw_in_rethrows_function - msg: >- - a function declared 'rethrows' may only throw if its parameter does - -- id: because_rethrows_argument_throws - msg: >- - call is to 'rethrows' function, but argument function can throw - -- id: because_rethrows_default_argument_throws - msg: >- - call is to 'rethrows' function, but a defaulted argument function can throw - -- id: throwing_call_in_nonthrowing_autoclosure - msg: >- - call can throw, but it is executed in a non-throwing autoclosure - -- id: tryless_throwing_call_in_nonthrowing_autoclosure - msg: >- - call can throw, but it is not marked with 'try' and it is executed in a - non-throwing autoclosure - -- id: throw_in_nonthrowing_autoclosure - msg: >- - error is not handled because it is thrown in a non-throwing autoclosure - -- id: try_unhandled_in_nonexhaustive_catch - msg: >- - errors thrown from here are not handled because the enclosing catch is - not exhaustive - -- id: throwing_call_in_nonexhaustive_catch - msg: >- - call can throw, but the enclosing catch is not exhaustive - -- id: tryless_throwing_call_in_nonexhaustive_catch - msg: >- - call can throw, but it is not marked with 'try' and the enclosing catch - is not exhaustive - -- id: throw_in_nonexhaustive_catch - msg: >- - error is not handled because the enclosing catch is not exhaustive - -- id: throwing_call_in_illegal_context - msg: >- - call can throw, but errors cannot be thrown out of %0 - -- id: throw_in_illegal_context - msg: >- - errors cannot be thrown out of %0 - -- id: throwing_operator_without_try - msg: >- - operator can throw but expression is not marked with 'try' - -- id: throwing_interpolation_without_try - msg: >- - interpolation can throw but is not marked with 'try' - -- id: throwing_call_without_try - msg: >- - call can throw but is not marked with 'try' - -- id: note_forgot_try - msg: >- - did you mean to use 'try'? - -- id: note_error_to_optional - msg: >- - did you mean to handle error as optional value? - -- id: note_disable_error_propagation - msg: >- - did you mean to disable error propagation? - -- id: no_throw_in_try - msg: >- - no calls to throwing functions occur within 'try' expression - -- id: no_throw_in_do_with_catch - msg: >- - 'catch' block is unreachable because no errors are thrown in 'do' block - -- id: unsupported_recursive_struct - msg: >- - value type %0 cannot have a stored property that recursively contains it - -- id: enum_non_well_founded - msg: >- - enum containing only recursive cases is impossible to instantiate - -- id: recursive_enum_not_indirect - msg: >- - recursive enum %0 is not marked 'indirect' - -- id: unsupported_infinitely_sized_type - msg: >- - value type %0 has infinite size - -- id: note_type_cycle_starts_here - msg: >- - cycle beginning here: %0 - -- id: note_recursive_enum_case_here - msg: >- - recursive case here - -- id: sugar_type_not_found - msg: >- - broken standard library: cannot find - %select{Array|Optional|ImplicitlyUnwrappedOptional|Dictionary|Error}0 type - -- id: optional_intrinsics_not_found - msg: >- - broken standard library: cannot find intrinsic operations on Optional - -- id: pointer_argument_intrinsics_not_found - msg: >- - broken standard library: cannot find intrinsic operations on - UnsafeMutablePointer - -- id: array_literal_intrinsics_not_found - msg: >- - broken standard library: cannot find intrinsic operations on Array - -- id: class_super_access - msg: >- - class %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}1|private or - fileprivate}3|cannot be declared %select{in this - context|fileprivate|internal|public|open}1}0 because its superclass - %select{is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2|uses - %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}2 - type as a generic parameter}4 - -- id: class_super_access_warn - msg: >- - class %select{should be declared - %select{private|fileprivate|internal|%error|%error}1|should not be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its - superclass %select{is - %select{private|fileprivate|internal|'@_spi'|'@_spi'}2|uses - %select{a private|a - fileprivate|an internal|an '@_spi'|an '@_spi'}2 - type as a generic parameter}4 - -- id: class_super_not_usable_from_inline - msg: >- - %select{type referenced from |}0the superclass of a '@usableFromInline' - class must be '@usableFromInline' or public - -- id: class_super_not_usable_from_inline_warn - msg: >- - %select{type referenced from |}0the superclass of a '@usableFromInline' - class should be '@usableFromInline' or public - -- id: dot_protocol_on_non_existential - msg: >- - cannot use 'Protocol' with non-protocol type %0 - -- id: tuple_single_element - msg: >- - cannot create a single-element tuple with an element label - -- id: tuple_ellipsis - msg: >- - cannot create a variadic tuple - -- id: tuple_duplicate_label - msg: >- - cannot create a tuple with a duplicate element label - -- id: enum_element_ellipsis - msg: >- - variadic enum cases are not supported - -- id: implicitly_unwrapped_optional_in_illegal_position_interpreted_as_optional - msg: >- - using '!' is not allowed here; treating this as '?' instead - -- id: implicitly_unwrapped_optional_deprecated_in_this_position - msg: >- - using '!' here is deprecated and will be removed in a future release - -- id: implicitly_unwrapped_optional_in_illegal_position - msg: >- - using '!' is not allowed here; perhaps '?' was intended? - -- id: invalid_ownership_type - msg: >- - %0 may only be applied to class and class-bound protocol types, not %1 - -- id: invalid_ownership_protocol_type - msg: >- - %0 must not be applied to non-class-bound %1; consider adding a protocol - conformance that has a class bound - -- id: invalid_ownership_incompatible_class - msg: >- - %0 is incompatible with %1 references - -- id: invalid_ownership_with_optional - msg: >- - %0 variable cannot have optional type - -- id: invalid_ownership_not_optional - msg: >- - %0 variable should have optional type %1 - -- id: invalid_ownership_is_let - msg: >- - %0 must be a mutable variable, because it may change at runtime - -- id: ownership_invalid_in_protocols - msg: >- - %0 cannot be applied to a property declaration in a protocol - -- id: ownership_invalid_in_protocols_compat_warning - msg: >- - %0 should not be applied to a property declaration in a protocol and will - be disallowed in future versions - -- id: required_initializer_nonclass - msg: >- - 'required' initializer in non-class type %0 - -- id: required_initializer_in_extension - msg: >- - 'required' initializer must be declared directly in class %0 (not in an - extension) - -- id: required_initializer_missing - msg: >- - 'required' initializer %0 must be provided by subclass of %1 - -- id: required_initializer_here - msg: >- - 'required' initializer is declared in superclass here - -- id: required_initializer_not_accessible - msg: >- - 'required' initializer must be accessible wherever class %0 can be - subclassed - -- id: required_initializer_missing_keyword - msg: >- - 'required' modifier must be present on all overrides of a required - initializer - -- id: required_initializer_override_wrong_keyword - msg: >- - use the 'required' modifier to override a required initializer - -- id: required_initializer_override_keyword - msg: >- - 'override' is implied when overriding a required initializer - -- id: overridden_required_initializer_here - msg: >- - overridden required initializer is here - -- id: attribute_requires_function_type - msg: >- - @%0 attribute only applies to function types - -- id: unsupported_convention - msg: >- - convention '%0' not supported - -- id: unreferenced_generic_parameter - msg: >- - generic parameter '%0' is not used in function signature - -- id: unexpected_ctype_for_non_c_convention - msg: >- - convention '%0' does not support the 'cType' argument label, did you mean - @convention(c, cType: "%1") or @convention(block, cType: "%1") instead? - -- id: unable_to_parse_c_function_type - msg: >- - unable to parse '%0'; it should be a C function pointer type or a block - pointer type - -- id: unsupported_opaque_type - msg: >- - 'some' types are only implemented for the declared type of properties and - subscripts and the return type of functions - -- id: opaque_type_unsupported_pattern - msg: >- - 'some' type can only be declared on a single property declaration - -- id: opaque_type_in_protocol_requirement - msg: >- - 'some' type cannot be the return type of a protocol requirement; - did you mean to add an associated type? - -- id: attr_only_on_parameters_of_differentiable - msg: >- - '%0' may only be used on parameters of '@differentiable' function types - -- id: differentiable_function_type_invalid_parameter - msg: >- - parameter type '%0' does not conform to 'Differentiable'%select{| and - satisfy '%0 == %0.TangentVector'}1, but the enclosing function type is - '@differentiable%select{|(linear)}1'%select{|; did you want to add - '@noDerivative' to this parameter?}2 - -- id: differentiable_function_type_invalid_result - msg: >- - result type '%0' does not conform to 'Differentiable'%select{| and - satisfy '%0 == %0.TangentVector'}1, but the enclosing function type is - '@differentiable%select{|(linear)}1' - -- id: opened_non_protocol - msg: >- - @opened cannot be applied to non-protocol type %0 - -- id: sil_function_ellipsis - msg: >- - SIL function types cannot be variadic - -- id: sil_function_input_label - msg: >- - SIL function types cannot have labeled inputs - -- id: sil_function_output_label - msg: >- - SIL function types cannot have labeled results - -- id: sil_non_coro_yields - msg: >- - non-coroutine SIL function types cannot have @yield results - -- id: sil_function_repeat_convention - msg: >- - repeated %select{parameter|result|callee}0 convention attribute - -- id: ast_subst_function_type - msg: >- - substitutions cannot be provided on a formal function type - -- id: sil_function_multiple_error_results - msg: >- - SIL function types cannot have multiple @error results - -- id: unsupported_sil_convention - msg: >- - convention '%0' not supported in SIL - -- id: illegal_sil_type - msg: >- - type %0 is not a legal SIL value type - -- id: sil_box_arg_mismatch - msg: >- - SIL box type has wrong number of generic arguments for layout - -- id: sil_metatype_without_repr - msg: >- - metatypes in SIL must have @thin, @thick, or @objc_metatype attribute - -- id: sil_metatype_multiple_reprs - msg: >- - metatypes in SIL can only be one of @thin, @thick, or @objc_metatype - -- id: objc_interop_disabled - msg: >- - Objective-C interoperability is disabled - -- id: attr_used_without_required_module - msg: >- - %0 attribute used without importing module %1 - -- id: invalid_objc_decl_context - msg: >- - @objc can only be used with members of classes, @objc protocols, and - concrete extensions of classes - -- id: invalid_objc_decl - msg: >- - only classes (and their extensions), protocols, methods, initializers, - properties, and subscript declarations can be declared @objc - -- id: invalid_objc_swift_rooted_class - msg: >- - only classes that inherit from NSObject can be declared @objc - -- id: invalid_nonobjc_decl - msg: >- - only class members and extensions of classes can be declared @nonobjc - -- id: invalid_nonobjc_extension - msg: >- - only extensions of classes can be declared @nonobjc - -- id: objc_in_extension_context - msg: >- - members of constrained extensions cannot be declared @objc - -- id: objc_in_generic_extension - msg: >- - extensions of %select{classes from generic context|generic classes}0 - cannot contain '@objc' members - -- id: objc_in_resilient_extension - msg: >- - '@objc' %0 in extension of subclass of %1 requires %2 %3 - -- id: objc_operator - msg: >- - operator methods cannot be declared @objc - -- id: objc_operator_proto - msg: >- - @objc protocols must not have operator requirements - -- id: objc_inference_swift3_dynamic - msg: >- - inference of '@objc' for 'dynamic' members is deprecated - -- id: objc_inference_swift3_objc_derived - msg: >- - inference of '@objc' for members of Objective-C-derived classes is - deprecated - -- id: objc_inference_swift3_addobjc - msg: >- - add '@objc' to continue exposing an Objective-C entry point (Swift 3 - behavior) - -- id: objc_inference_swift3_addnonobjc - msg: >- - add '@nonobjc' to suppress the Objective-C entry point (Swift 4 behavior) - -- id: objc_for_generic_class - msg: >- - generic subclasses of '@objc' classes cannot have an explicit '@objc' - because they are not directly visible from Objective-C - -- id: objc_for_resilient_class - msg: >- - explicit '@objc' on subclass of %0 requires %1 %2 - -- id: objc_getter_for_nonobjc_property - msg: >- - '@objc' getter for non-'@objc' property - -- id: objc_getter_for_nonobjc_subscript - msg: >- - '@objc' getter for non-'@objc' subscript - -- id: objc_setter_for_nonobjc_property - msg: >- - '@objc' setter for non-'@objc' property - -- id: objc_setter_for_nonobjc_subscript - msg: >- - '@objc' setter for non-'@objc' subscript - -- id: accessor_swift3_objc_inference - msg: >- - %select{%0 %1|%1}2 with '@objc' %select{getter|setter}3 depends on - deprecated inference of '@objc' - -- id: objc_enum_generic - msg: >- - '@objc' enum cannot be generic - -- id: objc_name_req_nullary - msg: >- - '@objc' %0 must have a simple name - -- id: objc_name_subscript - msg: >- - '@objc' subscript cannot have a name; did you mean to put the name on the - getter or setter? - -- id: objc_name_deinit - msg: >- - '@objc' deinitializer cannot have a name - -- id: objc_name_func_mismatch - msg: >- - '@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 - -- id: objc_enum_case_req_name - msg: >- - attribute has no effect; cases within an '@objc' enum are already exposed - to Objective-C - -- id: objc_enum_case_req_objc_enum - msg: >- - '@objc' enum case is not allowed outside of an '@objc' enum - -- id: objc_enum_case_multi - msg: >- - '@objc' enum case declaration defines multiple enum cases with the same - Objective-C name - -- id: objc_extension_not_class - msg: >- - '@objc' can only be applied to an extension of a class - -- id: attribute_meaningless_when_nonobjc - msg: >- - '@%0' attribute is meaningless on a property that cannot be represented - in Objective-C - -- id: objc_invalid_on_var - msg: >- - property cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because its type cannot be represented in Objective-C - -- id: objc_invalid_on_subscript - msg: >- - subscript cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because its type cannot be represented in Objective-C - -- id: objc_invalid_on_static_subscript - msg: >- - %0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked - @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member - of an @objc protocol|implicitly @objc|an @objc override|an implementation of - an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc - extension of a class (without @nonobjc)}1 - -- id: objc_invalid_with_generic_params - msg: >- - %0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked - @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member - of an @objc protocol|implicitly @objc|an @objc override|an implementation of - an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc - extension of a class (without @nonobjc)}1 because it has generic parameters - -- id: objc_convention_invalid - msg: >- - %0 is not representable in Objective-C, so it cannot be used with - '@convention(%1)' - -- id: paren_void_probably_void - msg: >- - when calling this function in Swift 4 or later, you must pass a '()' - tuple; did you mean for the input type to be '()'? - -- id: not_objc_empty_protocol_composition - msg: >- - 'Any' is not considered '@objc'; use 'AnyObject' instead - -- id: not_objc_protocol - msg: >- - protocol-constrained type containing protocol %0 cannot be represented in - Objective-C - -- id: not_objc_class_constraint - msg: >- - protocol-constrained type containing class %0 cannot be represented in - Objective-C - -- id: not_objc_error_protocol_composition - msg: >- - protocol-constrained type containing 'Error' cannot be represented in - Objective-C - -- id: not_objc_empty_tuple - msg: >- - empty tuple type cannot be represented in Objective-C - -- id: not_objc_tuple - msg: >- - tuples cannot be represented in Objective-C - -- id: not_objc_swift_class - msg: >- - classes not annotated with @objc cannot be represented in Objective-C - -- id: not_objc_swift_struct - msg: >- - Swift structs cannot be represented in Objective-C - -- id: not_objc_swift_enum - msg: >- - non-'@objc' enums cannot be represented in Objective-C - -- id: not_objc_generic_type_param - msg: >- - generic type parameters cannot be represented in Objective-C - -- id: not_objc_function_type_param - msg: >- - function types cannot be represented in Objective-C unless their - parameters and returns can be - -- id: not_objc_function_type_throwing - msg: >- - throwing function types cannot be represented in Objective-C - -- id: objc_inferring_on_objc_protocol_member - msg: >- - inferring '@objc' because the declaration is a member of an '@objc' protocol - -- id: objc_overriding_objc_decl - msg: >- - overriding '@objc' %select{property|subscript|initializer|method}0 %1 here - -- id: objc_witness_objc_requirement - msg: >- - satisfying requirement for %0 %1 in protocol %2 - -- id: witness_swift3_objc_inference - msg: >- - use of %0 %1 to satisfy a requirement of protocol %2 depends on '@objc' - inference deprecated in Swift 4 - -- id: no_opaque_return_type_of - msg: >- - unable to resolve type for _opaqueReturnTypeOf attribute - -- id: objc_observing_accessor - msg: >- - observing accessors are not allowed to be marked @objc - -- id: objc_addressor - msg: >- - addressors are not allowed to be marked @objc - -- id: objc_coroutine_accessor - msg: >- - 'read' and 'modify' accessors are not allowed to be marked @objc - -- id: objc_invalid_on_func_variadic - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because it has a variadic parameter - -- id: objc_invalid_on_func_inout - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an - @objc override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because inout parameters cannot be represented in - Objective-C - -- id: objc_invalid_on_func_param_type - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}1 because the type of the parameter %0 cannot be - represented in Objective-C - -- id: objc_invalid_on_func_single_param_type - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because the type of the parameter cannot be - represented in Objective-C - -- id: objc_invalid_on_func_result_type - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because its result type cannot be represented in - Objective-C - -- id: objc_invalid_on_foreign_class - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because Core Foundation types are not classes in - Objective-C - -- id: objc_invalid_on_throwing_optional_result - msg: >- - throwing method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because it returns a value of optional type %1; 'nil' - indicates failure to Objective-C - -- id: objc_invalid_on_throwing_result - msg: >- - throwing method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because it returns a value of type %1; return 'Void' - or a type that bridges to an Objective-C class - -- id: objc_invalid_on_failing_init - msg: >- - a failable and throwing initializer cannot be %select{marked - @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked - @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly - @objc|an @objc override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because 'nil' indicates failure to Objective-C - -- id: objc_in_objc_runtime_visible - msg: >- - %0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked - @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member - of an @objc protocol|implicitly @objc|an @objc override|an implementation of - an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an - @objc extension of a class (without @nonobjc)}1 because class %2 is only - visible via the Objective-C runtime - -- id: objc_override_method_selector_mismatch - msg: >- - Objective-C method has a different selector from the method it overrides - (%0 vs. %1) - -- id: objc_override_property_name_mismatch - msg: >- - Objective-C property has a different name from the property it overrides - (%0 vs. %1) - -- id: objc_ambiguous_inference - msg: >- - ambiguous inference of Objective-C name for %0 %1 (%2 vs %3) - -- id: objc_ambiguous_inference_candidate - msg: >- - %0 (in protocol %1) provides Objective-C name %2 - -- id: objc_ambiguous_error_convention - msg: >- - %0 overrides or implements protocol requirements for Objective-C - declarations with incompatible error argument conventions - -- id: objc_ambiguous_error_convention_candidate - msg: >- - %0 provides an error argument here - -- id: nonlocal_bridged_to_objc - msg: >- - conformance of %0 to %1 can only be written in module %2 - -- id: missing_bridging_function - msg: >- - missing - '%select{_forceBridgeFromObjectiveC|_conditionallyBridgeFromObjectiveC}0' - -- id: objc_redecl - msg: >- - %select{initializer %1|implicit initializer %1|deinitializer|implicit - deinitializer|method %1|getter for %1|subscript getter|setter for - %1|subscript setter}0 with Objective-C selector %4 conflicts with - %select{initializer %3|implicit initializer %3|deinitializer|implicit - deinitializer|method %3|getter for %3|subscript getter|setter - for %3|subscript setter}2 with the same Objective-C selector - -- id: objc_declared_here - msg: >- - %select{initializer %1|implicit initializer %1|deinitializer|implicit - deinitializer|method %1|getter for %1|subscript getter|setter for - %1|subscript setter}0 declared here - -- id: objc_redecl_same - msg: >- - %select{initializer %1|implicit initializer %1|deinitializer|implicit - deinitializer|method %1|getter for %1|subscript getter|setter for - %1|subscript setter}0 with Objective-C selector %2 conflicts with previous - declaration with the same Objective-C selector - -- id: objc_override_other - msg: >- - %select{initializer %1|implicit initializer %1|deinitializer|implicit - deinitializer|method %1|getter for %1|subscript getter|setter for - %1|subscript setter}0 with Objective-C selector %4 conflicts with - %select{initializer %3|implicit initializer %3|deinitializer|implicit - deinitializer|method %3|getter for %3|subscript getter|setter for - %3|subscript setter}2 from superclass %5 with the same Objective-C selector - -- id: objc_class_method_not_permitted - msg: >- - %select{initializer %1|implicit initializer %1|deinitializer|implicit - deinitializer|method %1|getter for %1|subscript getter|setter for - %1|subscript setter}0 defines Objective-C class method %2, which is not - permitted by Swift - -- id: objc_witness_selector_mismatch - msg: >- - Objective-C method %2 provided by %select{initializer %1|implicit - initializer %1|deinitializer|implicit deinitializer|method %1|getter for - %1|subscript getter|setter for %1|subscript setter}0 does not match the - requirement's selector (%3) - -- id: objc_optional_requirement_conflict - msg: >- - Objective-C method %4 provided by %select{initializer %1|implicit - initializer %1|deinitializer|implicit deinitializer|method %1|getter for - %1|subscript getter|setter for %1|subscript setter}0 conflicts with optional - requirement %select{initializer %3|implicit initializer - %3|deinitializer|implicit deinitializer|method %3|getter for %3|subscript - getter|setter for %3|subscript setter}2 in protocol %5 - -- id: objc_optional_requirement_swift_rename - msg: >- - rename %select{method|initializer|property|subscript}0 to match - requirement %1 - -- id: witness_non_objc - msg: >- - non-'@objc' %select{initializer %1|implicit initializer - %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript - getter|setter for %1|subscript setter}0 does not satisfy requirement of - '@objc' protocol %2 - -- id: witness_non_objc_optional - msg: >- - non-'@objc' %select{initializer %1|implicit initializer - %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript - getter|setter for %1|subscript setter}0 does not satisfy optional - requirement of '@objc' protocol %2 - -- id: witness_non_objc_storage - msg: >- - non-'@objc' %select{property %1|subscript}0 does not satisfy requirement - of '@objc' protocol %2 - -- id: witness_non_objc_storage_optional - msg: >- - non-'@objc' %select{property %1|subscript}0 does not satisfy optional - requirement of '@objc' protocol %2 - -- id: nonobjc_not_allowed - msg: >- - declaration is %select{marked @_cdecl|marked dynamic|marked @objc|marked - @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a - member of an @objc protocol|implicitly @objc|an @objc override|an - implementation of an @objc requirement|marked @IBInspectable|marked - @GKInspectable|in an @objc extension of a class (without @nonobjc)}0, - and cannot be marked @nonobjc - -- id: borrowed_with_objc_dynamic - msg: >- - %0 cannot be '@_borrowed' if it is '@objc dynamic' - -- id: borrowed_on_objc_protocol_requirement - msg: >- - %0 cannot be '@_borrowed' if it is an @objc protocol requirement - -- id: dynamic_with_transparent - msg: >- - a declaration cannot be both '@_tranparent' and 'dynamic' - -- id: dynamic_replacement_accessor_type_mismatch - msg: >- - replaced accessor %0's type does not match - -- id: dynamic_replacement_accessor_not_dynamic - msg: >- - replaced accessor for %0 is not marked dynamic - -- id: dynamic_replacement_accessor_not_explicit - msg: >- - replaced accessor - %select{get|set|_read|_modify|willSet|didSet|unsafeAddress|addressWithOwner|addressWithNativeOwner|unsafeMutableAddress|mutableAddressWithOwner|}0 - for %1 is not explicitly defined - -- id: dynamic_replacement_function_not_dynamic - msg: >- - replaced function %0 is not marked dynamic - -- id: dynamic_replacement_function_not_found - msg: >- - replaced function %0 could not be found - -- id: dynamic_replacement_accessor_not_found - msg: >- - replaced accessor for %0 could not be found - -- id: dynamic_replacement_accessor_ambiguous - msg: >- - replaced accessor for %0 occurs in multiple places - -- id: dynamic_replacement_accessor_ambiguous_candidate - msg: >- - candidate accessor found in module %0 - -- id: dynamic_replacement_function_of_type_not_found - msg: >- - replaced function %0 of type %1 could not be found - -- id: dynamic_replacement_found_function_of_type - msg: >- - found function %0 of type %1 - -- id: dynamic_replacement_not_in_extension - msg: >- - dynamicReplacement(for:) of %0 is not defined in an extension or at the - file level - -- id: dynamic_replacement_must_not_be_dynamic - msg: >- - dynamicReplacement(for:) of %0 must not be dynamic itself - -- id: dynamic_replacement_replaced_not_objc_dynamic - msg: >- - %0 is not marked @objc dynamic - -- id: dynamic_replacement_replacement_not_objc_dynamic - msg: >- - %0 is marked @objc dynamic - -- id: dynamic_replacement_replaced_constructor_is_convenience - msg: >- - replaced constructor %0 is marked as convenience - -- id: dynamic_replacement_replaced_constructor_is_not_convenience - msg: >- - replaced constructor %0 is not marked as convenience - -- id: non_nominal_type_eraser - msg: >- - type eraser must be a class, struct, or enum - -- id: type_eraser_does_not_conform - msg: >- - type eraser %0 must conform to protocol %1 - -- id: type_eraser_not_accessible - msg: >- - %select{private|fileprivate|internal|public|open}0 type eraser %1 cannot - have more restrictive access than protocol %2 (which is - %select{private|fileprivate|internal|public|open}3) - -- id: type_eraser_missing_init - msg: >- - type eraser %0 must have an initializer of the form 'init(erasing: - T)' - -- id: type_eraser_unviable_init - msg: >- - type eraser %0 has no viable initializer of the form 'init(erasing: T)' - -- id: type_eraser_declared_here - msg: >- - type eraser declared here - -- id: type_eraser_failable_init - msg: >- - 'init(erasing:)' cannot be failable - -- id: type_eraser_init_unsatisfied_requirements - msg: >- - 'init(erasing:)' cannot have unsatisfied requirements when %0 = 'some %1' - -- id: type_eraser_init_not_accessible - msg: >- - %select{private|fileprivate|internal|public|open}0 'init(erasing:)' - cannot have more restrictive access than protocol %1 (which is - %select{private|fileprivate|internal|public|open}2) - -- id: availability_decl_unavailable - msg: >- - %select{getter for |setter for |}0%1 is unavailable%select{ in - %3|}2%select{|: %4}4 - -- id: availability_decl_unavailable_warn - msg: >- - %select{getter for |setter for |}0%1 is unavailable%select{ in - %3|}2%select{|: %4}4 - -- id: availability_decl_unavailable_rename - msg: >- - %select{getter for |setter for |}0%1 has been %select{renamed to|replaced - by}2%select{| instance method| property}3 '%4'%select{|: %5}5 - -- id: availability_decl_unavailable_rename_warn - msg: >- - %select{getter for |setter for |}0%1 has been %select{renamed to|replaced - by}2%select{| instance method| property}3 '%4'%select{|: %5}5 - -- id: availability_marked_unavailable - msg: >- - %select{getter for |setter for |}0%1 has been explicitly marked - unavailable here - -- id: availability_introduced_in_version - msg: >- - %select{getter for |setter for |}0%1 was introduced in %2 %3 - -- id: availability_obsoleted - msg: >- - %select{getter for |setter for |}0%1 was obsoleted in %2 %3 - -- id: availability_deprecated - msg: >- - %select{getter for |setter for |}0%1 %select{is|%select{is|was}4}2 - deprecated%select{| in %3%select{| %5}4}2%select{|: %6}6 - -- id: availability_deprecated_rename - msg: >- - %select{getter for |setter for |}0%1 %select{is|%select{is|was}4}2 - deprecated%select{| in %3%select{| %5}4}2: %select{renamed to|replaced - by}6%select{| instance method| property}7 '%8' - -- id: note_deprecated_rename - msg: >- - use '%0' instead - -- id: availability_decl_more_than_enclosing - msg: >- - declaration cannot be more available than enclosing scope - -- id: availability_decl_more_than_enclosing_enclosing_here - msg: >- - enclosing scope here - -- id: availability_decl_only_version_newer - msg: >- - %0 is only available in %1 %2 or newer - -- id: availability_opaque_types_only_version_newer - msg: >- - 'some' return types are only available in %0 %1 or newer - -- id: availability_guard_with_version_check - msg: >- - add 'if #available' version check - -- id: availability_add_attribute - msg: >- - add @available attribute to enclosing %0 - -- id: availability_accessor_only_version_newer - msg: >- - %select{getter|setter}0 for %1 is only available in %2 %3 or newer - -- id: availability_inout_accessor_only_version_newer - msg: >- - cannot pass as inout because %select{getter|setter}0 for %1 is only - available in %2 %3 or newer - -- id: availability_query_required_for_platform - msg: >- - condition required for target platform '%0' - -- id: availability_query_useless_enclosing_scope - msg: >- - unnecessary check for '%0'; enclosing scope ensures guard will always be - true - -- id: availability_query_useless_enclosing_scope_here - msg: >- - enclosing scope here - -- id: availability_global_script_no_potential - msg: >- - global variable cannot be marked potentially unavailable with - '@available' in script mode - -- id: availability_stored_property_no_potential - msg: >- - stored properties cannot be marked potentially unavailable with - '@available' - -- id: availability_protocol_requires_version - msg: >- - protocol %0 requires %1 to be available in %2 %3 and newer - -- id: availability_protocol_requirement_here - msg: >- - protocol requirement here - -- id: public_decl_needs_availability - msg: >- - public declarations should have an availability attribute when building - with -require-explicit-availability - -- id: availabilty_string_subscript_migration - msg: >- - subscripts returning String were obsoleted in Swift 4; explicitly - construct a String from subscripted result - -- id: discardable_result_on_void_never_function - msg: >- - @discardableResult declared on a function returning %select{Never|Void}0 - is unnecessary - -- id: fixed_layout_attr_on_internal_type - msg: >- - '@_fixed_layout' attribute can only be applied to '@usableFromInline' or - public declarations, but %0 is - %select{private|fileprivate|internal|%error|%error}1 - -- id: fixed_layout_struct - msg: >- - '@frozen' attribute is now used for fixed-layout structs - -- id: frozen_attr_on_internal_type - msg: >- - '@frozen' attribute can only be applied to '@usableFromInline' or public - declarations, but %0 is %select{private|fileprivate|internal|%error|%error}1 - -- id: usable_from_inline_attr_with_explicit_access - msg: >- - '@usableFromInline' attribute can only be applied to internal - declarations, but %0 is %select{private|fileprivate|%error|public|open}1 - -- id: inlinable_implies_usable_from_inline - msg: >- - '@inlinable' declaration is already '@usableFromInline' - -- id: usable_from_inline_attr_in_protocol - msg: >- - '@usableFromInline' attribute cannot be used in protocols - -- id: local_type_in_inlinable_function - msg: >- - type %0 cannot be nested inside %select{a '@_transparent' function|an - '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default - argument value|a property initializer in a '@frozen' type}1 - -- id: resilience_decl_unavailable - msg: >- - %select{%0|%0 for}4 %1 is - %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and cannot be - referenced from %select{a '@_transparent' function|an '@inlinable' - function|an '@_alwaysEmitIntoClient' function|a default argument value|a - property initializer in a '@frozen' type}3 - -- id: resilience_decl_unavailable_warn - msg: >- - %select{%0|%0 for}4 %1 is - %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and should not be - referenced from %select{a '@_transparent' function|an '@inlinable' - function|an '@_alwaysEmitIntoClient' function|a default argument value|a - property initializer in a '@frozen' type}3 - -- id: inlinable_decl_ref_from_hidden_module - msg: >- - %0 %1 cannot be used in %select{a '@_transparent' function|an - '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default - argument value|a property initializer in a '@frozen' type}2 because - %select{%3 was imported implementation-only|it is an SPI imported from - %3|it is SPI}4 - -- id: resilience_decl_declared_here_public - msg: >- - %select{%0|%0 for}2 %1 is not public - -- id: resilience_decl_declared_here - msg: >- - %select{%0|%0 for}2 %1 is not '@usableFromInline' or public - -- id: class_designated_init_inlinable_resilient - msg: >- - initializer for class %0 is - '%select{@_transparent|@inlinable|@_alwaysEmitIntoClient|%error}1' - and must delegate to another initializer - -- id: attribute_invalid_on_stored_property - msg: >- - '%0' attribute cannot be applied to stored properties - -- id: inlinable_dynamic_not_supported - msg: >- - '@inlinable' attribute cannot be applied to 'dynamic' declarations - -- id: inlinable_decl_not_public - msg: >- - '@inlinable' attribute can only be applied to public declarations, but %0 - is %select{private|fileprivate|internal|%error|%error}1 - -- id: inlinable_resilient_deinit - msg: >- - deinitializer can only be '@inlinable' if the class is '@_fixed_layout' - -- id: specialize_attr_nongeneric_trailing_where - msg: >- - trailing 'where' clause in '_specialize' attribute of non-generic - function %0 - -- id: specialize_missing_where_clause - msg: >- - missing 'where' clause in '_specialize' attribute - -- id: specialize_empty_where_clause - msg: >- - empty 'where' clause in '_specialize' attribute - -- id: specialize_attr_non_concrete_same_type_req - msg: >- - Only concrete type same-type requirements are supported by '_specialize' - attribute - -- id: specialize_attr_only_generic_param_req - msg: >- - Only requirements on generic parameters are supported by '_specialize' - attribute - -- id: specialize_attr_only_one_concrete_same_type_req - msg: >- - Only one concrete type should be used in the same-type requirement in - '_specialize' attribute - -- id: specialize_attr_non_protocol_type_constraint_req - msg: >- - Only conformances to protocol types are supported by '_specialize' attribute - -- id: specialize_attr_type_parameter_count_mismatch - msg: >- - %select{too many|too few}2 type parameters are specified in '_specialize' - attribute (got %1, but expected %0) - -- id: specialize_attr_missing_constraint - msg: >- - Missing constraint for %0 in '_specialize' attribute - -- id: specialize_attr_unsupported_kind_of_req - msg: >- - Only same-type and layout requirements are supported by '_specialize' - attribute - -- id: pbd_never_used_stmtcond - msg: >- - value %0 was defined but never used; consider replacing with boolean test - -- id: unused_setter_parameter - msg: >- - setter argument %0 was never used, but the property was accessed - -- id: fixit_for_unused_setter_parameter - msg: >- - did you mean to use %0 instead of accessing the property's current value? - -- id: pbd_never_used - msg: >- - initialization of %select{variable|immutable value}1 %0 was never used; - consider replacing with assignment to '_' or removing it - -- id: capture_never_used - msg: >- - capture %0 was never used - -- id: variable_never_used - msg: >- - %select{variable|immutable value}1 %0 was never used; consider replacing - with '_' or removing it - -- id: immutable_value_never_used_but_assigned - msg: >- - immutable value %0 was never used; consider removing it - -- id: variable_never_mutated - msg: >- - variable %0 was never mutated; consider %select{removing 'var' to make - it|changing to 'let'}1 constant - -- id: variable_never_read - msg: >- - variable %0 was written to, but never read - -- id: observe_keypath_property_not_objc_dynamic - msg: >- - passing reference to non-'@objc dynamic' property %0 to KVO method %1 may - lead to unexpected behavior or runtime trap - -- id: default_magic_identifier_mismatch - msg: >- - parameter %0 with default argument '%1' passed to parameter %2, whose - default argument is '%3' - -- id: change_caller_default_to_match_callee - msg: >- - did you mean for parameter %0 to default to '%1'? - -- id: silence_default_magic_identifier_mismatch - msg: >- - add parentheses to silence this warning - -- id: debug_long_function_body - msg: >- - %0 %1 took %2ms to type-check (limit: %3ms) - -- id: debug_long_closure_body - msg: >- - closure took %0ms to type-check (limit: %1ms) - -- id: debug_long_expression - msg: >- - expression took %0ms to type-check (limit: %1ms) - -- id: empty_switch_stmt - msg: >- - 'switch' statement body must have at least one 'case' or 'default' block; - do you want to add a default case? - -- id: non_exhaustive_switch - msg: >- - switch must be exhaustive - -- id: possibly_non_exhaustive_switch - msg: >- - the compiler is unable to check that this switch is exhaustive in - reasonable time - -- id: missing_several_cases - msg: >- - do you want to add %select{missing cases|a default clause}0? - -- id: missing_unknown_case - msg: >- - handle unknown values using "@unknown default" - -- id: non_exhaustive_switch_drop_unknown - msg: >- - remove '@unknown' to handle remaining values - -- id: missing_particular_case - msg: >- - add missing case: '%0' - -- id: redundant_particular_case - msg: >- - case is already handled by previous patterns; consider removing it - -- id: redundant_particular_literal_case - msg: >- - literal value is already handled by previous pattern; consider removing it - -- id: redundant_particular_literal_case_here - msg: >- - first occurrence of identical literal pattern is here - -- id: non_exhaustive_switch_warn - msg: >- - switch must be exhaustive - -- id: non_exhaustive_switch_unknown_only - msg: >- - switch covers known cases, but %0 may have additional unknown - values%select{|, possibly added in future versions}1 - -- id: override_nsobject_hashvalue_error - msg: >- - 'NSObject.hashValue' is not overridable; did you mean to override - 'NSObject.hash'? - -- id: hashvalue_implementation - msg: >- - 'Hashable.hashValue' is deprecated as a protocol requirement; conform - type %0 to 'Hashable' by implementing 'hash(into:)' instead - -- id: property_wrapper_no_value_property - msg: >- - property wrapper type %0 does not contain a non-static property named %1 - -- id: property_wrapper_ambiguous_value_property - msg: >- - property wrapper type %0 has multiple non-static properties named %1 - -- id: property_wrapper_wrong_initial_value_init - msg: >- - %0 parameter type (%1) must be the same as its 'wrappedValue' property - type (%2) or an @autoclosure thereof - -- id: property_wrapper_failable_init - msg: >- - property wrapper initializer %0 cannot be failable - -- id: property_wrapper_type_requirement_not_accessible - msg: >- - %select{private|fileprivate|internal|public|open}0 %1 %2 cannot have more - restrictive access than its enclosing property wrapper type %3 (which is - %select{private|fileprivate|internal|public|open}4) - -- id: property_wrapper_ambiguous_enclosing_self_subscript - msg: >- - property wrapper type %0 has multiple enclosing-self subscripts %1 - -- id: property_wrapper_dynamic_self_type - msg: >- - property wrapper %select{wrapped value|projected value}0 cannot have - dynamic Self type - -- id: property_wrapper_attribute_not_on_property - msg: >- - property wrapper attribute %0 can only be applied to a property - -- id: property_wrapper_declared_here - msg: >- - property wrapper type %0 declared here - -- id: property_wrapper_mutating_get_composed_to_get_only - msg: >- - property wrapper %0 with a mutating getter cannot be composed inside - get-only property wrapper %1 - -- id: property_wrapper_local - msg: >- - property wrappers are not yet supported on local properties - -- id: property_wrapper_top_level - msg: >- - property wrappers are not yet supported in top-level code - -- id: property_wrapper_let - msg: >- - property wrapper can only be applied to a 'var' - -- id: property_wrapper_computed - msg: >- - property wrapper cannot be applied to a computed property - -- id: property_with_wrapper_conflict_attribute - msg: >- - property %0 with a wrapper cannot also be - %select{lazy|@NSCopying|@NSManaged|weak|unowned|unmanaged}1 - -- id: property_wrapper_not_single_var - msg: >- - property wrapper can only apply to a single variable - -- id: property_with_wrapper_in_bad_context - msg: >- - %select{|non-static |non-static }1property %0 declared inside %select{a - protocol|an extension|an enum}1 cannot have a wrapper - -- id: property_with_wrapper_overrides - msg: >- - property %0 with attached wrapper cannot override another property - -- id: property_wrapper_direct_init - msg: >- - initialize the property wrapper type directly with '(...') on the attribute - -- id: property_wrapper_incompatible_property - msg: >- - property type %0 does not match that of the 'wrappedValue' property of - its wrapper type %1 - -- id: property_wrapper_type_access - msg: >- - %select{%select{variable|constant}0|property}1 %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}3|private or - fileprivate}4|cannot be declared %select{in this - context|fileprivate|internal|public|open}3}2 because its property wrapper - type uses %select{a private|a fileprivate|an internal|%error|%error}5 type - -- id: property_wrapper_type_not_usable_from_inline - msg: >- - property wrapper type referenced from a '@usableFromInline' - %select{%select{variable|constant}0|property}1 must be '@usableFromInline' - or public - -- id: property_wrapper_wrapperValue - msg: >- - property wrapper's 'wrapperValue' property should be renamed to - 'projectedValue'; use of 'wrapperValue' is deprecated - -- id: property_wrapper_init_initialValue - msg: >- - property wrapper's 'init(initialValue:)' should be renamed to - 'init(wrappedValue:)'; use of 'init(initialValue:)' is deprecated - -- id: property_wrapper_projection_value_missing - msg: >- - could not find projection value property %0 - -- id: property_wrapper_missing_arg_init - msg: >- - missing argument for parameter %0 in property wrapper initializer; add - 'wrappedValue' and %0 arguments in '@%1(...)' - -- id: function_builder_decl - msg: >- - closure containing a declaration cannot be used with function builder %0 - -- id: note_function_builder_decl - msg: >- - closure containing a declaration cannot be used with function builder %0 - -- id: function_builder_control_flow - msg: >- - closure containing control flow statement cannot be used with function - builder %0 - -- id: note_function_builder_control_flow - msg: >- - closure containing control flow statement cannot be used with function - builder %0 - -- id: function_builder_attribute_not_allowed_here - msg: >- - function builder attribute %0 can only be applied to a parameter, - function, or computed property - -- id: function_builder_attribute_on_storage_without_getter - msg: >- - function builder attribute %0 can only be applied to a - %select{subscript|property|constant|variable}1 if it defines a getter - -- id: function_builder_parameter_not_of_function_type - msg: >- - function builder attribute %0 can only be applied to a parameter of - function type - -- id: function_builder_parameter_autoclosure - msg: >- - function builder attribute %0 cannot be applied to an autoclosure parameter - -- id: function_builder_multiple - msg: >- - only one function builder attribute can be attached to a - %select{declaration|parameter}0 - -- id: previous_function_builder_here - msg: >- - previous function builder specified here - -- id: function_builder_arguments - msg: >- - function builder attributes cannot have arguments - -- id: function_builder_disabled_by_return - msg: >- - application of function builder %0 disabled by explicit 'return' - statement - -- id: function_builder_remove_attr - msg: >- - remove the attribute to explicitly disable the function builder - -- id: function_builder_remove_returns - msg: >- - remove 'return' statements to apply the function builder - -- id: function_builder_infer_ambig - msg: >- - ambiguous function builder inferred for %0: %1 or %2 - -- id: function_builder_infer_add_return - msg: >- - add an explicit 'return' statement to not use a function builder - -- id: function_builder_infer_pick_specific - msg: >- - apply function builder %0 (inferred from %select{protocol|dynamic - replacement of}1 %2) - -- id: warn_reordering_tuple_shuffle_deprecated - msg: >- - expression shuffles the elements of this tuple; this behavior is - deprecated - -- id: differentiable_programming_attr_used_without_required_module - msg: >- - '@%0' attribute used without importing module %1 - -- id: oslog_arg_must_be_bool_literal - msg: >- - argument must be a bool literal - -- id: oslog_arg_must_be_integer_literal - msg: >- - argument must be an integer literal - -- id: oslog_arg_must_be_string_literal - msg: >- - argument must be a string literal - -- id: oslog_arg_must_be_float_literal - msg: >- - argument must be a floating-point literal - -- id: oslog_arg_must_be_metatype_literal - msg: >- - argument must be a .self - -- id: oslog_arg_must_be_closure - msg: >- - argument must be a closure - -- id: argument_must_be_constant - msg: >- - argument must be an expression with only literals - -- id: oslog_message_must_be_string_interpolation - msg: >- - argument must be a string interpolation - -- id: oslog_arg_must_be_enum_case - msg: >- - argument must be a case of enum %0 - -- id: oslog_arg_must_be_type_member_access - msg: >- - argument must be a static method or property of %0 - -- id: atomics_ordering_must_be_constant - msg: >- - ordering argument must be a static method or property of %0 - -- id: warning_from_clang - msg: >- - %0 - -- id: error_from_clang - msg: >- - %0 - -- id: note_from_clang - msg: >- - %0 - -- id: remark_from_clang - msg: >- - %0 - -- id: clang_cannot_build_module - msg: >- - could not build %select{C|Objective-C}0 module '%1' - -- id: bridging_header_missing - msg: >- - bridging header '%0' does not exist - -- id: bridging_header_error - msg: >- - failed to import bridging header '%0' - -- id: could_not_rewrite_bridging_header - msg: >- - failed to serialize bridging header; target may not be debuggable outside - of its original project - -- id: bridging_header_pch_error - msg: >- - failed to emit precompiled header '%0' for bridging header '%1' - -- id: emit_pcm_error - msg: >- - failed to emit precompiled module '%0' for module map '%1' - -- id: dump_pcm_error - msg: >- - failed to dump precompiled module '%0' - -- id: invalid_swift_name_method - msg: >- - too %select{few|many}0 parameters in swift_name attribute (expected %1; - got %2) - -- id: note_while_importing - msg: >- - while importing '%0' - -- id: swift_name_protocol_static - msg: >- - swift_name cannot be used to define %select{static member|init}0 on - protocol - -- id: swift_name_no_prototype - msg: >- - swift_name cannot be used on a non-prototyped function declaration - -- id: inconsistent_swift_name - msg: >- - inconsistent Swift name for Objective-C %select{method|property}0 '%1' in - '%2' (%3 in '%4' vs. %5 in '%6') - -- id: unresolvable_clang_decl - msg: >- - imported declaration '%0' could not be mapped to '%1' - -- id: unresolvable_clang_decl_is_a_framework_bug - msg: >- - please report this issue to the owners of '%0' - -- id: implicit_bridging_header_imported_from_module - msg: >- - implicit import of bridging header '%0' via module %1 is deprecated and - will be removed in a later version of Swift - -- id: bridging_module_missing - msg: >- - unable to find module '%0' for implicit conversion function '%0.%1' - -- id: bridging_function_missing - msg: >- - unable to find implicit conversion function '%0.%1' - -- id: bridging_function_overloaded - msg: >- - multiple definitions of implicit conversion function '%0.%1' - -- id: bridging_function_not_function - msg: >- - definition of implicit conversion function '%0.%1' is not a function - -- id: bridging_function_not_correct_type - msg: >- - definition of implicit conversion function '%0.%1' is not of the correct - type - -- id: bridging_objcbridgeable_missing - msg: >- - cannot find definition of '_ObjectiveCBridgeable' protocol - -- id: bridging_objcbridgeable_broken - msg: >- - broken definition of '_ObjectiveCBridgeable' protocol: missing %0 - -- id: invalid_sil_builtin - msg: >- - INTERNAL ERROR: invalid use of builtin: %0 - -- id: could_not_find_bridge_type - msg: >- - could not find Objective-C bridge type for type %0; did you forget to - import Foundation? - -- id: could_not_find_pointer_pointee_property - msg: >- - could not find 'pointee' property of pointer type %0 - -- id: writeback_overlap_property - msg: >- - inout writeback to computed property %0 occurs in multiple arguments to - call, introducing invalid aliasing - -- id: writeback_overlap_subscript - msg: >- - inout writeback through subscript occurs in multiple arguments to call, - introducing invalid aliasing - -- id: writebackoverlap_note - msg: >- - concurrent writeback occurred here - -- id: inout_argument_alias - msg: >- - inout arguments are not allowed to alias each other - -- id: previous_inout_alias - msg: >- - previous aliasing argument - -- id: unimplemented_generator_witnesses - msg: >- - protocol conformance emission for generator coroutines is unimplemented - -- id: exclusivity_access_required - msg: >- - overlapping accesses to %0, but - %select{initialization|read|modification|deinitialization}1 requires - exclusive access; %select{consider copying to a local variable|consider - calling MutableCollection.swapAt(_:_:)}2 - -- id: exclusivity_access_required_unknown_decl - msg: >- - overlapping accesses, but - %select{initialization|read|modification|deinitialization}0 - requires exclusive access; consider copying to a local variable - -- id: exclusivity_conflicting_access - msg: >- - conflicting access is here - -- id: unsupported_c_function_pointer_conversion - msg: >- - C function pointer signature %0 is not compatible with expected type %1 - -- id: c_function_pointer_from_function_with_context - msg: >- - a C function pointer cannot be formed from a %select{local - function|closure}0 that captures %select{context|generic parameters|dynamic - Self type}1 - -- id: objc_selector_malformed - msg: >- - the type ObjectiveC.Selector is malformed - -- id: capture_before_declaration - msg: >- - closure captures %0 before it is declared - -- id: capture_before_declaration_defer - msg: >- - 'defer' block captures %0 before it is declared - -- id: captured_value_declared_here - msg: >- - captured value declared here - -- id: escaping_inout_capture - msg: >- - escaping %select{local function|closure|autoclosure}0 captures 'inout' - parameter %1 - -- id: inout_param_defined_here - msg: >- - parameter %0 is declared 'inout' - -- id: escaping_mutable_self_capture - msg: >- - escaping %select{local function|closure|autoclosure}0 captures mutating - 'self' parameter - -- id: escaping_noescape_param_capture - msg: >- - escaping %select{local function|closure|autoclosure}0 captures - non-escaping parameter %1 - -- id: noescape_param_defined_here - msg: >- - parameter %0 is implicitly non-escaping - -- id: escaping_noescape_var_capture - msg: >- - escaping %select{local function|closure|autoclosure}0 captures - non-escaping value - -- id: value_captured_here - msg: >- - captured here - -- id: copy_inout_captured_by_autoclosure - msg: >- - pass a copy of %0 - -- id: copy_self_captured_by_autoclosure - msg: >- - pass a copy of 'self' - -- id: value_captured_transitively - msg: >- - captured indirectly by this call - -- id: err_noescape_param_call - msg: >- - passing a %select{|closure which captures a }1non-escaping function - parameter %0 to a call to a non-escaping function parameter can allow - re-entrant modification of a variable - -- id: variable_defined_here - msg: >- - %select{variable|constant}0 defined here - -- id: variable_used_before_initialized - msg: >- - %select{variable|constant}1 '%0' used before being initialized - -- id: variable_inout_before_initialized - msg: >- - %select{variable|constant}1 '%0' passed by reference before being - initialized - -- id: variable_closure_use_uninit - msg: >- - %select{variable|constant}1 '%0' captured by a closure before being - initialized - -- id: variable_defer_use_uninit - msg: >- - %select{variable|constant}1 '%0' used in defer before being initialized - -- id: self_closure_use_uninit - msg: >- - 'self' captured by a closure before all members were initialized - -- id: variable_addrtaken_before_initialized - msg: >- - address of %select{variable|constant}1 '%0' taken before it is initialized - -- id: ivar_not_initialized_at_superinit - msg: >- - property '%0' not initialized at super.init call - -- id: ivar_not_initialized_at_implicit_superinit - msg: >- - property '%0' not initialized at implicitly generated super.init call - -- id: self_use_before_fully_init - msg: >- - 'self' used in %select{method call|property access}1 %0 before - %select{all stored properties are initialized|'super.init' call|'self.init' - call}2 - -- id: use_of_self_before_fully_init - msg: >- - 'self' used before all stored properties are initialized - -- id: stored_property_not_initialized - msg: >- - '%0' not initialized - -- id: selfinit_multiple_times - msg: >- - '%select{super|self}0.init' called multiple times in initializer - -- id: superselfinit_not_called_before_return - msg: >- - '%select{super|self}0.init' isn't called on all paths before returning - from initializer - -- id: self_before_superinit - msg: >- - 'self' used before 'super.init' call - -- id: self_before_selfinit - msg: >- - 'self' used before 'self.init' call - -- id: self_before_selfinit_value_type - msg: >- - 'self' used before 'self.init' call or assignment to 'self' - -- id: self_inside_catch_superselfinit - msg: >- - 'self' used inside 'catch' block reachable from %select{super|self}0.init - call - -- id: return_from_init_without_initing_stored_properties - msg: >- - return from initializer without initializing all stored properties - -- id: variable_function_use_uninit - msg: >- - %select{variable|constant}1 '%0' used by function definition before being - initialized - -- id: struct_not_fully_initialized - msg: >- - struct '%0' must be completely initialized before a member is stored to - -- id: immutable_property_already_initialized - msg: >- - immutable value '%0' may only be initialized once - -- id: initial_value_provided_in_let_decl - msg: >- - initial value already provided in 'let' declaration - -- id: mutation_of_property_of_immutable_value - msg: >- - cannot mutate %select{property %0|subscript}1 of immutable value '%2' - -- id: using_mutating_accessor_on_immutable_value - msg: >- - mutating accessor for %select{property %0|subscript}1 may not be used on - immutable value '%2' - -- id: mutating_method_called_on_immutable_value - msg: >- - mutating %select{method|operator}1 %0 may not be used on immutable value - '%2' - -- id: immutable_value_passed_inout - msg: >- - immutable value '%0' must not be passed inout - -- id: assignment_to_immutable_value - msg: >- - immutable value '%0' must not be assigned to - -- id: designated_init_in_cross_module_extension - msg: >- - initializer for struct %0 must use "self.init(...)" or "self = - ..."%select{| on all paths}1 because %select{it is not in module %2|the - struct was imported from C}3 - -- id: designated_init_c_struct_fix - msg: >- - use "self.init()" to initialize the struct with zero values - -- id: missing_return - msg: >- - missing return in a %select{function|closure}1 expected to return %0 - -- id: missing_return_last_expr - msg: >- - missing return in a %select{function|closure}1 expected to return %0; - did you mean to return the last expression? - -- id: missing_never_call - msg: >- - %select{function|closure}1 with uninhabited return type %0 is missing - call to another never-returning function on all paths - -- id: guard_body_must_not_fallthrough - msg: >- - 'guard' body must not fall through, consider using a 'return' or 'throw' - to exit the scope - -- id: unreachable_code - msg: >- - will never be executed - -- id: unreachable_code_uninhabited_param_note - msg: >- - '%0' is uninhabited, so this function body can never be executed - -- id: unreachable_code_branch - msg: >- - condition always evaluates to %select{false|true}0 - -- id: call_to_noreturn_note - msg: >- - a call to a never-returning function - -- id: unreachable_code_after_stmt - msg: >- - code after '%select{return|break|continue|throw}0' will never be executed - -- id: unreachable_case - msg: >- - %select{case|default}0 will never be executed - -- id: switch_on_a_constant - msg: >- - switch condition evaluates to a constant - -- id: unreachable_code_note - msg: >- - will never be executed - -- id: warn_infinite_recursive_function - msg: >- - all paths through this function will call itself - -- id: circular_transparent - msg: >- - inlining 'transparent' functions forms circular loop - -- id: note_while_inlining - msg: >- - while inlining here - -- id: cannot_prespecialize - msg: >- - Cannot pre-specialize %0 - -- id: missing_prespecialization - msg: >- - Pre-specialized function %0 missing in SwiftOnoneSupport module - -- id: integer_conversion_overflow - msg: >- - integer overflows when converted from %0 to %1 - -- id: integer_conversion_overflow_builtin_types - msg: >- - integer overflows when converted from %select{unsigned|signed}0 %1 to - %select{unsigned|signed}2 %3 - -- id: integer_conversion_overflow_warn - msg: >- - integer overflows when converted from %0 to %1 - -- id: negative_integer_literal_overflow_unsigned - msg: >- - negative integer '%1' overflows when stored into unsigned type %0 - -- id: integer_literal_overflow - msg: >- - integer literal '%1' overflows when stored into %0 - -- id: integer_literal_overflow_builtin_types - msg: >- - integer literal '%2' overflows when stored into %select{unsigned|signed}0 %1 - -- id: integer_literal_overflow_warn - msg: >- - integer literal overflows when stored into %0 - -- id: arithmetic_operation_overflow - msg: >- - arithmetic operation '%0 %1 %2' (on type %3) results in an overflow - -- id: arithmetic_operation_overflow_generic_type - msg: >- - arithmetic operation '%0 %1 %2' (on %select{unsigned|signed}3 %4-bit - integer type) results in an overflow - -- id: division_overflow - msg: >- - division '%0 %1 %2' results in an overflow - -- id: division_by_zero - msg: >- - division by zero - -- id: wrong_non_negative_assumption - msg: >- - assumed non-negative value '%0' is negative - -- id: shifting_all_significant_bits - msg: >- - shift amount is greater than or equal to type size in bits - -- id: static_report_error - msg: >- - static report error - -- id: pound_assert_condition_not_constant - msg: >- - #assert condition not constant - -- id: pound_assert_failure - msg: >- - %0 - -- id: constexpr_unknown_reason_default - msg: >- - cannot evaluate expression as constant here - -- id: constexpr_unevaluable_operation - msg: >- - cannot constant evaluate operation%select{| used by this call}0 - -- id: constexpr_too_many_instructions - msg: >- - exceeded instruction limit: %0 when evaluating the expression at compile - time - -- id: constexpr_limit_exceeding_instruction - msg: >- - limit exceeded %select{here|during this call}0 - -- id: constexpr_loop_found_note - msg: >- - control-flow loop found during evaluation - -- id: constexpr_loop_instruction - msg: >- - found loop %select{here|inside this call}0 - -- id: constexpr_overflow - msg: >- - integer overflow detected - -- id: constexpr_overflow_operation - msg: >- - operation%select{| performed during this call}0 overflows - -- id: constexpr_trap - msg: >- - %0 - -- id: constexpr_trap_operation - msg: >- - operation%select{| performed during this call}0 traps - -- id: constexpr_invalid_operand_seen - msg: >- - operation with invalid operands encountered during evaluation - -- id: constexpr_operand_invalid_here - msg: >- - operation with invalid operands encountered %select{here|during this call}0 - -- id: constexpr_value_unknown_at_top_level - msg: >- - cannot evaluate top-level value as constant here - -- id: constexpr_multiple_writers_found_at_top_level - msg: >- - top-level value has multiple assignments - -- id: constexpr_unsupported_instruction_found - msg: >- - encountered operation not supported by the evaluator: %0 - -- id: constexpr_unsupported_instruction_found_here - msg: >- - operation%select{| used by this call is}0 not supported by the evaluator - -- id: constexpr_found_callee_with_no_body - msg: >- - encountered call to '%0' whose body is not available. Imported functions - must be marked '@inlinable' to constant evaluate - -- id: constexpr_callee_with_no_body - msg: >- - %select{|calls a }0function whose body is not available - -- id: constexpr_found_call_with_unknown_arg - msg: >- - encountered call to '%0' where the %1 argument is not a constant - -- id: constexpr_call_with_unknown_arg - msg: >- - %select{|makes a }0function call with non-constant arguments - -- id: constexpr_untracked_sil_value_use_found - msg: >- - encountered use of a variable not tracked by the evaluator - -- id: constexpr_untracked_sil_value_used_here - msg: >- - untracked variable used %select{here|by this call}0 - -- id: constexpr_unevaluable_cast_found - msg: >- - encountered an unevaluable cast - -- id: constexpr_unevaluable_cast_used_here - msg: >- - unevaluable cast encountered %select{here|by this call}0 - -- id: constexpr_unresolvable_witness_call - msg: >- - encountered unresolvable witness method call: '%0' - -- id: constexpr_no_witness_table_entry - msg: >- - cannot find witness table entry %select{for this call|for a - witness-method invoked during this call}0 - -- id: constexpr_witness_call_with_no_conformance - msg: >- - cannot find concrete conformance %select{for this call|for a - witness-method invoked during this call}0 - -- id: constexpr_unknown_control_flow_due_to_skip - msg: >- - branch depends on non-constant value produced by an unevaluated - instructions - -- id: constexpr_returned_by_unevaluated_instruction - msg: >- - result of an unevaluated instruction is not a constant - -- id: constexpr_mutated_by_unevaluated_instruction - msg: >- - value mutable by an unevaluated instruction is not a constant - -- id: not_constant_evaluable - msg: >- - not constant evaluable - -- id: constexpr_imported_func_not_onone - msg: >- - imported constant evaluable function '%0' must be annotated - '@_optimize(none)' - -- id: autodiff_internal_swift_not_imported - msg: >- - Automatic differentiation internal error: the Swift module is not - imported - -- id: autodiff_differentiation_module_not_imported - msg: >- - Automatic differentiation requires the '_Differentiation' module to be - imported - -- id: autodiff_conversion_to_linear_function_not_supported - msg: >- - conversion to '@differentiable(linear)' function type is not yet - supported - -- id: autodiff_function_not_differentiable_error - msg: >- - function is not differentiable - -- id: autodiff_expression_not_differentiable_error - msg: >- - expression is not differentiable - -- id: autodiff_expression_not_differentiable_note - msg: >- - expression is not differentiable - -- id: autodiff_when_differentiating_function_call - msg: >- - when differentiating this function call - -- id: autodiff_when_differentiating_function_definition - msg: >- - when differentiating this function definition - -- id: autodiff_implicitly_inherited_differentiable_attr_here - msg: >- - differentiability required by the corresponding protocol requirement here - -- id: autodiff_jvp_control_flow_not_supported - msg: >- - forward-mode differentiation does not yet support control flow - -- id: autodiff_control_flow_not_supported - msg: >- - cannot differentiate unsupported control flow - -- id: autodiff_missing_return - msg: >- - missing return for differentiation - -- id: autodiff_external_nondifferentiable_function - msg: >- - cannot differentiate functions that have not been marked - '@differentiable' and that are defined in other files - -- id: autodiff_opaque_function_not_differentiable - msg: >- - opaque non-'@differentiable' function is not differentiable - -- id: autodiff_private_derivative_from_fragile - msg: >- - differentiated functions in %select{'@inlinable' functions|default - arguments}0 must be marked '@differentiable' or have a public - '@derivative'%select{|; this is not possible with a closure, make a - top-level function instead}1 - -- id: autodiff_function_noderivative_parameter_not_differentiable - msg: >- - cannot differentiate with respect to a '@noDerivative' parameter - -- id: autodiff_function_assoc_func_unmet_requirements - msg: >- - function call is not differentiable because generic requirements are not - met: '%0' - -- id: autodiff_nondifferentiable_argument - msg: >- - cannot differentiate through a non-differentiable argument; do you want - to use 'withoutDerivative(at:)'? - -- id: autodiff_nondifferentiable_result - msg: >- - cannot differentiate through a non-differentiable result; do you want to - use 'withoutDerivative(at:)'? - -- id: autodiff_protocol_member_not_differentiable - msg: >- - member is not differentiable because the corresponding protocol - requirement is not '@differentiable' - -- id: autodiff_class_member_not_differentiable - msg: >- - member is not differentiable because the corresponding class member is - not '@differentiable' - -- id: autodiff_member_subset_indices_not_differentiable - msg: >- - member is differentiable only with respect to a smaller subset of arguments - -- id: autodiff_cannot_param_subset_thunk_partially_applied_orig_fn - msg: >- - cannot convert a direct method reference to a '@differentiable' function; - use an explicit closure instead - -- id: autodiff_cannot_differentiate_through_multiple_results - msg: >- - cannot differentiate through multiple results - -- id: autodiff_cannot_differentiate_through_inout_arguments - msg: >- - cannot differentiate through 'inout' arguments - -- id: autodiff_enums_unsupported - msg: >- - differentiating enum values is not yet supported - -- id: autodiff_stored_property_parent_not_differentiable - msg: >- - cannot differentiate access to property '%0.%1' because '%0' does not - conform to 'Differentiable' - -- id: autodiff_stored_property_not_differentiable - msg: >- - cannot differentiate access to property '%0.%1' because property type %2 - does not conform to 'Differentiable' - -- id: autodiff_stored_property_tangent_not_struct - msg: >- - cannot differentiate access to property '%0.%1' because - '%0.TangentVector' is not a struct - -- id: autodiff_stored_property_no_corresponding_tangent - msg: >- - cannot differentiate access to property '%0.%1' because - '%0.TangentVector' does not have a stored property named '%1' - -- id: autodiff_tangent_property_wrong_type - msg: >- - cannot differentiate access to property '%0.%1' because - '%0.TangentVector.%1' does not have expected type %2 - -- id: autodiff_tangent_property_not_stored - msg: >- - cannot differentiate access to property '%0.%1' because - '%0.TangentVector.%1' is not a stored property - -- id: autodiff_coroutines_not_supported - msg: >- - differentiation of coroutine calls is not yet supported - -- id: autodiff_cannot_differentiate_writes_to_global_variables - msg: >- - cannot differentiate writes to global variables - -- id: autodiff_cannot_differentiate_writes_to_mutable_captures - msg: >- - cannot differentiate writes to mutable captures - -- id: non_physical_addressof - msg: >- - addressof only works with purely physical lvalues; use - 'withUnsafePointer' or 'withUnsafeBytes' unless you're implementing - 'withUnsafePointer' or 'withUnsafeBytes' - -- id: non_borrowed_indirect_addressof - msg: >- - addressof only works with borrowable in-memory rvalues; use - 'withUnsafePointer' or 'withUnsafeBytes' unless you're implementing - 'withUnsafePointer' or 'withUnsafeBytes' - -- id: opt_remark_passed - msg: >- - %0 - -- id: opt_remark_missed - msg: >- - %0 - -- id: float_to_int_overflow - msg: >- - invalid%select{| implicit}2 conversion: '%0' overflows %1 - -- id: negative_fp_literal_overflow_unsigned - msg: >- - negative literal '%0' cannot be converted to %select{|unsigned }2%1 - -- id: warning_float_trunc_overflow - msg: >- - '%0' overflows to %select{|-}2inf during conversion to %1 - -- id: warning_float_trunc_underflow - msg: >- - '%0' underflows and loses precision during conversion to %1 - -- id: warning_float_trunc_hex_inexact - msg: >- - '%0' loses precision during conversion to %1 - -- id: warning_float_overflows_maxbuiltin - msg: >- - '%0' overflows to %select{|-}1inf because its magnitude exceeds the - limits of a float literal - -- id: warning_int_to_fp_inexact - msg: >- - '%1' is not exactly representable as %0; it becomes '%2' - -- id: return_before_yield - msg: >- - accessor must yield before returning - -- id: multiple_yields - msg: >- - accessor must not yield more than once - -- id: previous_yield - msg: >- - previous yield was here - -- id: possible_return_before_yield - msg: >- - accessor must yield on all paths before returning - -- id: branch_doesnt_yield - msg: >- - missing yield when the condition is %select{false|true}0 - -- id: named_case_doesnt_yield - msg: >- - missing yield in the %0 case - -- id: case_doesnt_yield - msg: >- - missing yield in %select{this|the nil|the non-nil}0 case - -- id: switch_value_case_doesnt_yield - msg: >- - missing yield in the %0 case - -- id: try_branch_doesnt_yield - msg: >- - missing yield when error is %select{not |}0thrown - -- id: oslog_constant_eval_trap - msg: >- - %0 - -- id: oslog_too_many_instructions - msg: >- - interpolated expression and arguments are too complex - -- id: oslog_invalid_log_message - msg: >- - invalid log message; extending types defined in the os module is not - supported - -- id: oslog_const_evaluable_fun_error - msg: >- - '%0' failed evaluation - -- id: oslog_non_constant_message - msg: >- - 'OSLogMessage' instance passed to the log call is not a constant - -- id: oslog_non_constant_interpolation - msg: >- - 'OSLogInterpolation' instance passed to 'OSLogMessage.init' is not a - constant - -- id: oslog_property_not_constant - msg: >- - 'OSLogInterpolation.%0' is not a constant - -- id: oslog_message_alive_after_opts - msg: >- - string interpolation cannot be used in this context; if you are calling - an os_log function, try a different overload - -- id: oslog_message_explicitly_created - msg: >- - 'OSLogMessage' must be created from a string interpolation or string - literal - -- id: oslog_call_in_unreachable_code - msg: >- - os log call will never be executed and may have undiagnosed errors - -- id: global_string_pointer_on_non_constant - msg: >- - globalStringTablePointer builtin must be used only on string literals - -- id: polymorphic_builtin_passed_non_trivial_non_builtin_type - msg: >- - Argument of type %0 can not be passed as an argument to a Polymorphic - builtin. Polymorphic builtins can only be passed arguments that are trivial - builtin typed - -- id: polymorphic_builtin_passed_type_without_static_overload - msg: >- - Static overload %0 does not exist for polymorphic builtin '%1'. Static - overload implied by passing argument of type %2 - -- id: box_to_stack_cannot_promote_box_to_stack_due_to_escape_alloc - msg: >- - Can not promote value from heap to stack due to value escaping - -- id: box_to_stack_cannot_promote_box_to_stack_due_to_escape_location - msg: >- - value escapes here - -- id: no_llvm_target - msg: >- - error loading LLVM target for triple '%0': %1 - -- id: error_codegen_init_fail - msg: >- - cannot initialize code generation passes for target - -- id: irgen_unimplemented - msg: >- - unimplemented IR generation feature %0 - -- id: irgen_failure - msg: >- - IR generation failure: %0 - -- id: type_to_verify_not_found - msg: >- - unable to find type '%0' to verify - -- id: type_to_verify_ambiguous - msg: >- - type to verify '%0' is ambiguous - -- id: type_to_verify_dependent - msg: >- - type to verify '%0' has unbound generic parameters - -- id: too_few_output_filenames - msg: >- - too few output file names specified - -- id: no_input_files_for_mt - msg: >- - no swift input files for multi-threaded compilation - -- id: alignment_dynamic_type_layout_unsupported - msg: >- - @_alignment is not supported on types with dynamic layout - -- id: alignment_less_than_natural - msg: >- - @_alignment cannot decrease alignment below natural alignment of %0 - -- id: alignment_more_than_maximum - msg: >- - @_alignment cannot increase alignment above maximum alignment of %0 - -- id: warning_no_such_sdk - msg: >- - no such SDK: '%0' - -- id: error_no_frontend_args - msg: >- - no arguments provided to '-frontend' - -- id: error_no_such_file_or_directory - msg: >- - no such file or directory: '%0' - -- id: error_unsupported_target_os - msg: >- - unsupported target OS: '%0' - -- id: error_unsupported_target_arch - msg: >- - unsupported target architecture: '%0' - -- id: error_unsupported_opt_for_target - msg: >- - unsupported option '%0' for target '%1' - -- id: warning_inferred_simulator_target - msg: >- - inferring simulator environment for target '%0'; use '-target %1' instead - -- id: error_argument_not_allowed_with - msg: >- - argument '%0' is not allowed with '%1' - -- id: warning_argument_not_supported_with_optimization - msg: >- - argument '%0' is not supported with optimization - -- id: error_option_requires_sanitizer - msg: >- - option '%0' requires a sanitizer to be enabled. Use -sanitize= to enable - a sanitizer - -- id: warning_option_requires_specific_sanitizer - msg: >- - option '%0' has no effect when '%1' sanitizer is disabled. Use - -sanitize=%1 to enable the sanitizer - -- id: error_option_missing_required_argument - msg: >- - option '%0' is missing a required argument (%1) - -- id: cannot_open_file - msg: >- - cannot open file '%0' (%1) - -- id: cannot_open_serialized_file - msg: >- - cannot open file '%0' for diagnostics emission (%1) - -- id: error_open_input_file - msg: >- - error opening input file '%0' (%1) - -- id: error_clang_importer_create_fail - msg: >- - clang importer creation failed - -- id: error_missing_arg_value - msg: >- - missing argument value for '%0', expected %1 argument(s) - -- id: error_unknown_arg - msg: >- - unknown argument: '%0' - -- id: error_invalid_arg_value - msg: >- - invalid value '%1' in '%0' - -- id: warning_invalid_locale_code - msg: >- - unsupported locale code; supported locale codes are: '%0' - -- id: warning_locale_path_not_found - msg: >- - specified localization directory '%0' does not exist, translation is - disabled - -- id: warning_cannot_find_locale_file - msg: >- - cannot find translations for '%0' at '%1': no such file - -- id: warning_cannot_multithread_batch_mode - msg: >- - ignoring -num-threads argument; cannot multithread batch mode - -- id: error_unsupported_option_argument - msg: >- - unsupported argument '%1' to option '%0' - -- id: error_immediate_mode_missing_stdlib - msg: >- - could not load the swift standard library - -- id: error_immediate_mode_missing_library - msg: >- - could not load %select{shared library|framework}0 '%1' - -- id: error_immediate_mode_primary_file - msg: >- - immediate mode is incompatible with -primary-file - -- id: error_missing_frontend_action - msg: >- - no frontend action was selected - -- id: error_invalid_source_location_str - msg: >- - invalid source location string '%0' - -- id: error_no_source_location_scope_map - msg: >- - -dump-scope-maps argument must be 'expanded' or a list of source - locations - -- id: note_valid_swift_versions - msg: >- - valid arguments to '-swift-version' are %0 - -- id: error_mode_cannot_emit_dependencies - msg: >- - this mode does not support emitting dependency files - -- id: error_mode_cannot_emit_reference_dependencies - msg: >- - this mode does not support emitting reference dependency files - -- id: error_mode_cannot_emit_swift_ranges - msg: >- - this mode does not support emitting unparsed ranges files - -- id: error_mode_cannot_emit_compiled_source - msg: >- - this mode does not support emitting compiled source files - -- id: error_mode_cannot_emit_header - msg: >- - this mode does not support emitting Objective-C headers - -- id: error_mode_cannot_emit_loaded_module_trace - msg: >- - this mode does not support emitting the loaded module trace - -- id: error_mode_cannot_emit_module - msg: >- - this mode does not support emitting modules - -- id: error_mode_cannot_emit_module_doc - msg: >- - this mode does not support emitting module documentation files - -- id: error_mode_cannot_emit_module_source_info - msg: >- - this mode does not support emitting module source info files - -- id: error_mode_cannot_emit_interface - msg: >- - this mode does not support emitting module interface files - -- id: cannot_emit_ir_skipping_function_bodies - msg: >- - -experimental-skip-non-inlinable-function-bodies does not support - emitting IR - -- id: emit_reference_dependencies_without_primary_file - msg: >- - ignoring -emit-reference-dependencies (requires -primary-file) - -- id: emit_swift_ranges_without_primary_file - msg: >- - ignoring -emit-swift-ranges (requires -primary-file) - -- id: emit_compiled_source_without_primary_file - msg: >- - ignoring -emit-compiled-source (requires -primary-file) - -- id: error_bad_module_name - msg: >- - module name "%0" is not a valid identifier%select{|; use -module-name - flag to specify an alternate name}1 - -- id: error_stdlib_module_name - msg: >- - module name "%0" is reserved for the standard library%select{|; use - -module-name flag to specify an alternate name}1 - -- id: error_stdlib_not_found - msg: >- - unable to load standard library for target '%0' - -- id: error_unable_to_load_supplementary_output_file_map - msg: >- - unable to load supplementary output file map '%0': %1 - -- id: error_missing_entry_in_supplementary_output_file_map - msg: >- - supplementary output file map '%0' is missing an entry for '%1' (this - likely indicates a compiler issue; please file a bug report) - -- id: error_repl_requires_no_input_files - msg: >- - REPL mode requires no input files - -- id: error_mode_requires_one_input_file - msg: >- - this mode requires a single input file - -- id: error_mode_requires_an_input_file - msg: >- - this mode requires at least one input file - -- id: error_mode_requires_one_sil_multi_sib - msg: >- - this mode requires .sil for primary-file and only .sib for other inputs - -- id: error_no_output_filename_specified - msg: >- - an output filename was not specified for a mode which requires an output - filename - -- id: error_implicit_output_file_is_directory - msg: >- - the implicit output file '%0' is a directory; explicitly specify a - filename using -o - -- id: error_if_any_output_files_are_specified_they_all_must_be - msg: >- - if any output files are specified, they all must be - -- id: error_primary_file_not_found - msg: >- - primary file '%0' was not found in file list '%1' - -- id: error_cannot_have_input_files_with_file_list - msg: >- - cannot have input files with file list - -- id: error_cannot_have_primary_files_with_primary_file_list - msg: >- - cannot have primary input files with primary file list - -- id: error_cannot_have_supplementary_outputs - msg: >- - cannot have '%0' with '%1' - -- id: error_duplicate_input_file - msg: >- - duplicate input file '%0' - -- id: repl_must_be_initialized - msg: >- - variables currently must have an initial value when entered at the top - level of the REPL - -- id: verify_encountered_fatal - msg: >- - fatal error encountered while in -verify mode - -- id: error_parse_input_file - msg: >- - error parsing input file '%0' (%1) - -- id: error_write_index_unit - msg: >- - writing index unit file: %0 - -- id: error_create_index_dir - msg: >- - creating index directory: %0 - -- id: error_write_index_record - msg: >- - writing index record file: %0 - -- id: error_index_failed_status_check - msg: >- - failed file status check: %0 - -- id: error_index_inputs_more_than_outputs - msg: >- - index output filenames do not match input source files - -- id: error_wrong_number_of_arguments - msg: >- - wrong number of '%0' arguments (expected %1, got %2) - -- id: error_formatting_multiple_file_ranges - msg: >- - file ranges don't support multiple input files - -- id: error_formatting_invalid_range - msg: >- - file range is invalid - -- id: stats_disabled - msg: >- - compiler was not built with support for collecting statistics - -- id: tbd_warn_truncating_version - msg: >- - truncating %select{current|compatibility}0 version '%1' in TBD file to - fit in 32-bit space used by old mach-o format - -- id: tbd_err_invalid_version - msg: >- - invalid dynamic library %select{current|compatibility}0 version '%1' - -- id: tbd_only_supported_in_whole_module - msg: >- - TBD generation is only supported when the whole module can be seen - -- id: tbd_not_supported_with_cmo - msg: >- - Test-Based InstallAPI (TBD) is not support with cross-module-optimization - -- id: linker_directives_choice_confusion - msg: >- - only one of -emit-ldadd-cfile-path and -module-installname-map-file can - be specified;the c file won't be generated - -- id: previous_installname_map_missing - msg: >- - cannot open previous install name map from %0 - -- id: previous_installname_map_corrupted - msg: >- - previous install name map from %0 is malformed - -- id: explicit_swift_module_map_missing - msg: >- - cannot open explicit Swift module map from %0 - -- id: explicit_swift_module_map_corrupted - msg: >- - explicit Swift module map from %0 is malformed - -- id: default_previous_install_name - msg: >- - default previous install name for %0 is %1 - -- id: platform_previous_install_name - msg: >- - previous install name for %0 in %1 is %2 - -- id: unknown_platform_name - msg: >- - unkown platform name %0 - -- id: unknown_swift_module_name - msg: >- - cannot find Swift module with name %0 - -- id: cannot_find_install_name - msg: >- - cannot find previous install name for module %0 in %1 - -- id: symbol_in_tbd_not_in_ir - msg: >- - symbol '%0' (%1) is in TBD file, but not in generated IR - -- id: symbol_in_ir_not_in_tbd - msg: >- - symbol '%0' (%1) is in generated IR file, but not in TBD file - -- id: tbd_validation_failure - msg: >- - please file a radar or open a bug on bugs.swift.org with this code, and - add -Xfrontend -validate-tbd-against-ir=none to squash the errors - -- id: redundant_prefix_compilation_flag - msg: >- - invalid argument '-D%0'; did you provide a redundant '-D' in your build - settings? - -- id: invalid_conditional_compilation_flag - msg: >- - conditional compilation flags must be valid Swift identifiers (rather - than '%0') - -- id: cannot_assign_value_to_conditional_compilation_flag - msg: >- - conditional compilation flags do not have values in Swift; they are - either present or absent (rather than '%0') - -- id: framework_search_path_includes_framework_extension - msg: >- - framework search path ends in ".framework"; add directory containing - framework instead: %0 - -- id: error_optimization_remark_pattern - msg: >- - %0 in '%1' - -- id: error_invalid_debug_prefix_map - msg: >- - invalid argument '%0' to -debug-prefix-map; it must be of the form - 'original=remapped' - -- id: error_invalid_coverage_prefix_map - msg: >- - invalid argument '%0' to -coverage-prefix-map; it must be of the form - 'original=remapped' - -- id: error_unable_to_write_swift_ranges_file - msg: >- - unable to write unparsed ranges file '$0': %1 - -- id: error_unable_to_write_compiled_source_file - msg: >- - unable to write compiled source file: '$0': %1 - -- id: invalid_vfs_overlay_file - msg: >- - invalid virtual overlay file '%0' - -- id: module_interface_scoped_import_unsupported - msg: >- - scoped imports are not yet supported in module interfaces - -- id: warn_unsupported_module_interface_swift_version - msg: >- - module interfaces are only supported with Swift language version 5 or - later (currently using -swift-version %0) - -- id: warn_unsupported_module_interface_library_evolution - msg: >- - module interfaces are only supported with -enable-library-evolution - -- id: error_extracting_version_from_module_interface - msg: >- - error extracting version from module interface - -- id: unsupported_version_of_module_interface - msg: >- - unsupported version of module interface '%0': '%1' - -- id: error_opening_explicit_module_file - msg: >- - failed to open explicit Swift module: %0 - -- id: error_extracting_flags_from_module_interface - msg: >- - error extracting flags from module interface - -- id: rebuilding_module_from_interface - msg: >- - rebuilding module '%0' from interface '%1' - -- id: out_of_date_module_here - msg: >- - %select{compiled|cached|forwarding|prebuilt}0 module is out of date: '%1' - -- id: module_interface_dependency_out_of_date - msg: >- - dependency is out of date: '%0' - -- id: module_interface_dependency_missing - msg: >- - dependency is missing: '%0' - -- id: compiled_module_invalid - msg: >- - unable to load compiled module '%0' - -- id: compiled_module_invalid_reason - msg: >- - unable to load compiled module '%0': %1 - -- id: unknown_forced_module_loading_mode - msg: >- - unknown value for SWIFT_FORCE_MODULE_LOADING variable: '%0' - -- id: error_creating_remark_serializer - msg: >- - error while creating remark serializer: '%0' - -- id: interface_file_lock_failure - msg: >- - could not acquire lock file for module interface '%0' - -- id: interface_file_lock_timed_out - msg: >- - timed out waiting to acquire lock file for module interface '%0' - -- id: dependency_cascading_mismatch - msg: >- - expected %select{non-cascading|cascading}0 dependency; found - %select{non-cascading|cascading}1 dependency instead - -- id: potential_dependency_cascading_mismatch - msg: >- - expected %select{non-cascading|cascading}0 potential member dependency; - found %select{non-cascading|cascading}1 potential member dependency instead - -- id: missing_member_dependency - msg: >- - expected %select{%error|provided|member|potential member|dynamic member}0 - dependency does not exist: %1 - -- id: unexpected_dependency - msg: >- - unexpected %0 %select{%error|%error|member|potential member|dynamic - member}1 dependency: %2 - -- id: unexpected_provided_entity - msg: >- - unexpected provided entity: %0 - -- id: negative_expectation_violated - msg: >- - unexpected dependency exists: %0 - -- id: expectation_missing_opening_braces - msg: >- - expected {{ in expectation - -- id: expectation_missing_closing_braces - msg: >- - didn't find '}}' to match '{{' in expectation - -- id: module_incompatible_with_skip_function_bodies - msg: >- - module '%0' cannot be built with - -experimental-skip-non-inlinable-function-bodies; this option has been - automatically disabled - -- id: warning_parallel_execution_not_supported - msg: >- - parallel execution not supported; falling back to serial execution - -- id: error_unable_to_execute_command - msg: >- - unable to execute command: %0 - -- id: error_command_signalled_without_signal_number - msg: >- - %0 command failed due to signal (use -v to see invocation) - -- id: error_command_signalled - msg: >- - %0 command failed due to signal %1 (use -v to see invocation) - -- id: error_command_failed - msg: >- - %0 command failed with exit code %1 (use -v to see invocation) - -- id: error_expected_one_frontend_job - msg: >- - unable to handle compilation, expected exactly one frontend job - -- id: error_expected_frontend_command - msg: >- - expected a swift frontend command - -- id: error_cannot_specify__o_for_multiple_outputs - msg: >- - cannot specify -o when generating multiple output files - -- id: error_static_emit_executable_disallowed - msg: >- - -static may not be used with -emit-executable - -- id: error_unable_to_load_output_file_map - msg: >- - unable to load output file map '%1': %0 - -- id: error_no_output_file_map_specified - msg: >- - no output file map specified - -- id: error_unable_to_make_temporary_file - msg: >- - unable to make temporary file: %0 - -- id: error_no_input_files - msg: >- - no input files - -- id: error_unexpected_input_file - msg: >- - unexpected input file: %0 - -- id: error_unknown_target - msg: >- - unknown target '%0' - -- id: error_framework_bridging_header - msg: >- - using bridging headers with framework targets is unsupported - -- id: error_bridging_header_module_interface - msg: >- - using bridging headers with module interfaces is unsupported - -- id: error_i_mode - msg: >- - the flag '-i' is no longer required and has been removed; use '%0 - input-filename' - -- id: warning_unnecessary_repl_mode - msg: >- - unnecessary option '%0'; this is the default for '%1' with no input files - -- id: error_unsupported_option - msg: >- - option '%0' is not supported by '%1'; did you mean to use '%2'? - -- id: incremental_requires_output_file_map - msg: >- - ignoring -incremental (currently requires an output file map) - -- id: incremental_requires_build_record_entry - msg: >- - ignoring -incremental; output file map has no master dependencies entry - ("%0" under "") - -- id: unable_to_open_incremental_comparison_log - msg: >- - unable to open incremental comparison log file '%0' - -- id: error_os_minimum_deployment - msg: >- - Swift requires a minimum deployment target of %0 - -- id: error_sdk_too_old - msg: >- - Swift does not support the SDK '%0' - -- id: error_ios_maximum_deployment_32 - msg: >- - iOS %0 does not support 32-bit programs - -- id: error_unsupported_target_variant - msg: >- - unsupported '%select{-target|-target-variant}1' value '%0'; use - 'ios-macabi' instead - -- id: warn_arclite_not_found_when_link_objc_runtime - msg: >- - unable to find Objective-C runtime support library 'arclite'; pass - '-no-link-objc-runtime' to silence this warning - -- id: error_two_files_same_name - msg: >- - filename "%0" used twice: '%1' and '%2' - -- id: note_explain_two_files_same_name - msg: >- - filenames are used to distinguish private declarations with the same name - -- id: warn_cannot_stat_input - msg: >- - unable to determine when '%0' was last modified: %1 - -- id: warn_unable_to_load_dependencies - msg: >- - unable to load dependencies file "%0", disabling incremental mode - -- id: error_input_changed_during_build - msg: >- - input file '%0' was modified during the build - -- id: error_conflicting_options - msg: >- - conflicting options '%0' and '%1' - -- id: error_option_not_supported - msg: >- - '%0' is not supported with '%1' - -- id: warn_ignore_embed_bitcode - msg: >- - ignoring -embed-bitcode since no object file is being generated - -- id: warn_ignore_embed_bitcode_marker - msg: >- - ignoring -embed-bitcode-marker since no object file is being generated - -- id: verify_debug_info_requires_debug_option - msg: >- - ignoring '-verify-debug-info'; no debug info is being generated - -- id: verify_incremental_dependencies_needs_incremental - msg: >- - '-verify-incremental-dependencies' requires '-incremental' - -- id: error_profile_missing - msg: >- - no profdata file exists at '%0' - -- id: warn_opt_remark_disabled - msg: >- - Emission of optimization records has been disabled, because it requires a - single compiler invocation: consider enabling the -whole-module-optimization - flag - -- id: warn_ignoring_batch_mode - msg: >- - ignoring '-enable-batch-mode' because '%0' was also specified - -- id: warn_ignoring_wmo - msg: >- - ignoring '-wmo' because '-dump-ast' was also specified - -- id: warn_ignoring_source_range_dependencies - msg: >- - ignoring '-enable-source-range-dependencies' because '%0' was also specified - -- id: warn_bad_swift_ranges_header - msg: >- - ignoring '-enable-source-range-dependencies' because of bad header in '%0' - -- id: warn_bad_swift_ranges_format - msg: >- - ignoring '-enable-source-range-dependencies' because of bad format '%1' - in '%0' - -- id: warn_use_filelists_deprecated - msg: >- - the option '-driver-use-filelists' is deprecated; use - '-driver-filelist-threshold=0' instead - -- id: warn_unable_to_load_swift_ranges - msg: >- - unable to load swift ranges file "%0", %1 - -- id: warn_unable_to_load_compiled_swift - msg: >- - unable to load previously compiled swift file "%0", %1 - -- id: warn_unable_to_load_primary - msg: >- - unable to load primary swift file "%0", %1 - -- id: cannot_find_migration_script - msg: >- - missing migration script from path '%0' - -- id: error_darwin_static_stdlib_not_supported - msg: >- - -static-stdlib is no longer supported on Apple platforms - -- id: warn_drv_darwin_sdk_invalid_settings - msg: >- - SDK settings were ignored because 'SDKSettings.json' could not be parsed - -- id: invalid_name - msg: >- - '%0' is not a valid name - -- id: invalid_location - msg: >- - given location is not valid - -- id: arity_mismatch - msg: >- - the given new name '%0' does not match the arity of the old name '%1' - -- id: name_not_functionlike - msg: >- - the 'call' name usage cannot be used with a non-function-like name '%0' - -- id: unresolved_location - msg: >- - cannot resolve location as name - -- id: location_module_mismatch - msg: >- - given location does not belong to module '%0' - -- id: value_decl_no_loc - msg: >- - value decl '%0' has no declaration location - -- id: value_decl_referenced_out_of_range - msg: >- - value decl '%0' is referenced out of range - -- id: multi_entry_range - msg: >- - selected range has more than one entry point - -- id: orphan_loop_keyword - msg: >- - selected range contains %0 but not its target loop - -- id: invalid_default_location - msg: >- - given location is not on a default statement - -- id: no_parent_switch - msg: >- - cannot find enclosing switch statement - -- id: no_remaining_cases - msg: >- - no remaining cases to expand - -- id: mismatched_rename - msg: >- - the name at the given location cannot be renamed to '%0' - -- id: no_insert_position - msg: >- - cannot find inserting position - -- id: generic_sig_change - msg: >- - %0 has generic signature change from %1 to %2 - -- id: raw_type_change - msg: >- - %0(%1) is now %2 representable - -- id: removed_decl - msg: >- - %0 has been removed%select{| (deprecated)}1 - -- id: moved_decl - msg: >- - %0 has been moved to %1 - -- id: renamed_decl - msg: >- - %0 has been renamed to %1 - -- id: decl_type_change - msg: >- - %0 has %1 type change from %2 to %3 - -- id: decl_attr_change - msg: >- - %0 changes from %1 to %2 - -- id: decl_new_attr - msg: >- - %0 is now %1 - -- id: decl_reorder - msg: >- - %0 in a non-resilient type changes position from %1 to %2 - -- id: decl_added - msg: >- - %0 is added to a non-resilient type - -- id: var_has_fixed_order_change - msg: >- - %0 is %select{now|no longer}1 a stored property - -- id: func_has_fixed_order_change - msg: >- - %0 is %select{now|no longer}1 a non-final instance function - -- id: default_arg_removed - msg: >- - %0 has removed default argument from %1 - -- id: conformance_removed - msg: >- - %0 has removed %select{conformance to|inherited protocol}2 %1 - -- id: conformance_added - msg: >- - %0 has added inherited protocol %1 - -- id: existing_conformance_added - msg: >- - %0 has added a conformance to an existing protocol %1 - -- id: default_associated_type_removed - msg: >- - %0 has removed default type %1 - -- id: protocol_req_added - msg: >- - %0 has been added as a protocol requirement - -- id: super_class_removed - msg: >- - %0 has removed its super class %1 - -- id: super_class_changed - msg: >- - %0 has changed its super class from %1 to %2 - -- id: decl_kind_changed - msg: >- - %0 has been changed to a %1 - -- id: optional_req_changed - msg: >- - %0 is %select{now|no longer}1 an optional requirement - -- id: no_longer_open - msg: >- - %0 is no longer open for subclassing - -- id: func_type_escaping_changed - msg: >- - %0 has %select{removed|added}2 @escaping in %1 - -- id: func_self_access_change - msg: >- - %0 has self access kind changing from %1 to %2 - -- id: param_ownership_change - msg: >- - %0 has %1 changing from %2 to %3 - -- id: type_witness_change - msg: >- - %0 has type witness type for %1 changing from %2 to %3 - -- id: decl_new_witness_table_entry - msg: >- - %0 now requires %select{|no}1 new witness table entry - -- id: new_decl_without_intro - msg: >- - %0 is a new API without @available attribute - -- id: objc_name_change - msg: >- - %0 has ObjC name change from %1 to %2 - -- id: desig_init_added - msg: >- - %0 has been added as a designated initializer to an open class - -- id: added_invisible_designated_init - msg: >- - %0 has new designated initializers that are not visible to clients - -- id: not_inheriting_convenience_inits - msg: >- - %0 no longer inherits convenience inits from its superclass - -- id: enum_case_added - msg: >- - %0 has been added as a new enum case - diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index 00f23b8a0f267..d692ef67d1d70 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -9,6 +9,26 @@ project(swift-stdlib LANGUAGES C CXX) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") +# +# User-configurable options for the standard library. +# + +option(SWIFT_ENABLE_COMPATIBILITY_OVERRIDES + "Support back-deploying compatibility fixes for newer apps running on older runtimes." + TRUE) + +option(SWIFT_RUNTIME_MACHO_NO_DYLD + "Build stdlib assuming the runtime environment uses Mach-O but does not support dynamic modules." + FALSE) + +option(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + "Build the standard libraries assuming that they will be used in an environment with only a single thread." + FALSE) + +# +# End of user-configurable options. +# + include(AddSwiftStdlib) # Create convenience targets for the Swift standard library. diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index a899f495df78f..adf466ee1c144 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -2,20 +2,6 @@ include(AddSwift) include(SwiftSource) -function(is_darwin_based_sdk sdk_name out_var) - if ("${sdk_name}" STREQUAL "OSX" OR - "${sdk_name}" STREQUAL "IOS" OR - "${sdk_name}" STREQUAL "IOS_SIMULATOR" OR - "${sdk_name}" STREQUAL "TVOS" OR - "${sdk_name}" STREQUAL "TVOS_SIMULATOR" OR - "${sdk_name}" STREQUAL "WATCHOS" OR - "${sdk_name}" STREQUAL "WATCHOS_SIMULATOR") - set(${out_var} TRUE PARENT_SCOPE) - else() - set(${out_var} FALSE PARENT_SCOPE) - endif() -endfunction() - function(add_dependencies_multiple_targets) cmake_parse_arguments( ADMT # prefix @@ -63,8 +49,7 @@ function(_add_target_variant_c_compile_link_flags) set(result ${${CFLAGS_RESULT_VAR_NAME}}) - is_darwin_based_sdk("${CFLAGS_SDK}" IS_DARWIN) - if(IS_DARWIN) + if("${CFLAGS_SDK}" IN_LIST SWIFT_APPLE_PLATFORMS) # Check if there's a specific OS deployment version needed for this invocation if("${CFLAGS_SDK}" STREQUAL "OSX") if(DEFINED maccatalyst_build_flavor) @@ -98,7 +83,7 @@ function(_add_target_variant_c_compile_link_flags) endif() set(_sysroot "${SWIFT_SDK_${CFLAGS_SDK}_ARCH_${CFLAGS_ARCH}_PATH}") - if(IS_DARWIN) + if(SWIFT_SDK_${CFLAGS_SDK}_USE_ISYSROOT) list(APPEND result "-isysroot" "${_sysroot}") elseif(NOT SWIFT_COMPILER_IS_MSVC_LIKE AND NOT "${_sysroot}" STREQUAL "/") list(APPEND result "--sysroot=${_sysroot}") @@ -113,7 +98,7 @@ function(_add_target_variant_c_compile_link_flags) endif() endif() - if(IS_DARWIN) + if("${CFLAGS_SDK}" IN_LIST SWIFT_APPLE_PLATFORMS) # We collate -F with the framework path to avoid unwanted deduplication # of options by target_compile_options -- this way no undesired # side effects are introduced should a new search path be added. @@ -179,13 +164,18 @@ function(_add_target_variant_c_compile_flags) MACCATALYST_BUILD_FLAVOR "${CFLAGS_MACCATALYST_BUILD_FLAVOR}") is_build_type_optimized("${CFLAGS_BUILD_TYPE}" optimized) - if(optimized) - list(APPEND result "-O2") + is_build_type_with_debuginfo("${CFLAGS_BUILD_TYPE}" debuginfo) + + # Add -O0/-O2/-O3/-Os/-g/... based on CFLAGS_BUILD_TYPE. + list(APPEND result "${CMAKE_CXX_FLAGS_${CFLAGS_BUILD_TYPE}}") + if(optimized) # Omit leaf frame pointers on x86 production builds (optimized, no debug # info, and no asserts). - is_build_type_with_debuginfo("${CFLAGS_BUILD_TYPE}" debug) - if(NOT debug AND NOT CFLAGS_ENABLE_ASSERTIONS) + if(NOT debuginfo AND NOT CFLAGS_ENABLE_ASSERTIONS) + # Unfortunately, this cannot be folded into the standard + # CMAKE_CXX_FLAGS_... because Apple multi-SDK builds use different + # architectures for different SDKs (CFLAGS_ARCH isn't constant here). if("${CFLAGS_ARCH}" STREQUAL "i386" OR "${CFLAGS_ARCH}" STREQUAL "i686") if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) list(APPEND result "-momit-leaf-frame-pointer") @@ -194,27 +184,6 @@ function(_add_target_variant_c_compile_flags) endif() endif() endif() - else() - if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) - list(APPEND result "-O0") - else() - list(APPEND result "/Od") - endif() - endif() - - # CMake automatically adds the flags for debug info if we use MSVC/clang-cl. - if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) - is_build_type_with_debuginfo("${CFLAGS_BUILD_TYPE}" debuginfo) - if(debuginfo) - _compute_lto_flag("${CFLAGS_ENABLE_LTO}" _lto_flag_out) - if(_lto_flag_out) - list(APPEND result "-gline-tables-only") - else() - list(APPEND result "-g") - endif() - else() - list(APPEND result "-g0") - endif() endif() if("${CFLAGS_SDK}" STREQUAL "WINDOWS") @@ -329,6 +298,22 @@ function(_add_target_variant_c_compile_flags) list(APPEND result "-D_WASI_EMULATED_MMAN") endif() + if(SWIFT_DISABLE_OBJC_INTEROP) + list(APPEND result "-DSWIFT_OBJC_INTEROP=0") + endif() + + if(NOT SWIFT_ENABLE_COMPATIBILITY_OVERRIDES) + list(APPEND result "-DSWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES") + endif() + + if(SWIFT_RUNTIME_MACHO_NO_DYLD) + list(APPEND result "-DSWIFT_RUNTIME_MACHO_NO_DYLD") + endif() + + if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) + list(APPEND result "-DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME") + endif() + set("${CFLAGS_RESULT_VAR_NAME}" "${result}" PARENT_SCOPE) endfunction() @@ -497,7 +482,7 @@ function(_add_swift_lipo_target) list(APPEND source_binaries $) endforeach() - if(${LIPO_SDK} IN_LIST SWIFT_APPLE_PLATFORMS) + if("${SWIFT_SDK_${LIPO_SDK}_OBJECT_FORMAT}" STREQUAL "MACHO") if(LIPO_CODESIGN) set(codesign_command COMMAND "codesign" "-f" "-s" "-" "${LIPO_OUTPUT}") endif() diff --git a/stdlib/cmake/modules/SwiftSource.cmake b/stdlib/cmake/modules/SwiftSource.cmake index e6f63c08298d1..d7ac8afa8f0bf 100644 --- a/stdlib/cmake/modules/SwiftSource.cmake +++ b/stdlib/cmake/modules/SwiftSource.cmake @@ -11,6 +11,21 @@ function(compute_library_subdir result_var_name sdk arch) endif() endfunction() +# Return a swiftc flag (e.g. -O or -Onone) to control optimization level based +# on the build type. +function(swift_optimize_flag_for_build_type build_type result_var_name) + if("${build_type}" STREQUAL "Debug") + set("${result_var_name}" "-Onone" PARENT_SCOPE) + elseif("${build_type}" STREQUAL "RelWithDebInfo" OR + "${build_type}" STREQUAL "Release") + set("${result_var_name}" "-O" PARENT_SCOPE) + elseif("${build_type}" STREQUAL "MinSizeRel") + set("${result_var_name}" "-Osize" PARENT_SCOPE) + else() + message(FATAL_ERROR "Unknown build type: ${build_type}") + endif() +endfunction() + # Process the sources within the given variable, pulling out any Swift # sources to be compiled with 'swift' directly. This updates # ${sourcesvar} in place with the resulting list and ${externalvar} with the @@ -195,8 +210,7 @@ function(_add_target_variant_swift_compile_flags list(APPEND result "-sdk" "${SWIFT_SDK_${sdk}_ARCH_${arch}_PATH}") endif() - is_darwin_based_sdk("${sdk}" IS_DARWIN) - if(IS_DARWIN) + if("${sdk}" IN_LIST SWIFT_APPLE_PLATFORMS) set(sdk_deployment_version "${SWIFT_SDK_${sdk}_DEPLOYMENT_VERSION}") get_target_triple(target target_variant "${sdk}" "${arch}" MACCATALYST_BUILD_FLAVOR "${VARIANT_MACCATALYST_BUILD_FLAVOR}" @@ -224,7 +238,7 @@ function(_add_target_variant_swift_compile_flags list(APPEND result "-resource-dir" "${SWIFTLIB_DIR}") endif() - if(IS_DARWIN) + if("${sdk}" IN_LIST SWIFT_APPLE_PLATFORMS) # We collate -F with the framework path to avoid unwanted deduplication # of options by target_compile_options -- this way no undesired # side effects are introduced should a new search path be added. @@ -232,12 +246,8 @@ function(_add_target_variant_swift_compile_flags "-F${SWIFT_SDK_${sdk}_ARCH_${arch}_PATH}/../../../Developer/Library/Frameworks") endif() - is_build_type_optimized("${build_type}" optimized) - if(optimized) - list(APPEND result "-O") - else() - list(APPEND result "-Onone") - endif() + swift_optimize_flag_for_build_type("${CMAKE_BUILD_TYPE}" optimize_flag) + list(APPEND result "${optimize_flag}") is_build_type_with_debuginfo("${build_type}" debuginfo) if(debuginfo) @@ -396,7 +406,7 @@ function(_compile_swift_files list(APPEND swift_flags "-enable-library-evolution") endif() - if(SWIFT_STDLIB_USE_NONATOMIC_RC) + if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) list(APPEND swift_flags "-Xfrontend" "-assume-single-threaded") endif() @@ -441,6 +451,10 @@ function(_compile_swift_files list(APPEND swift_flags "-warn-swift3-objc-inference-complete") endif() + if(SWIFT_DISABLE_OBJC_INTEROP) + list(APPEND swift_flags "-Xfrontend" "-disable-objc-interop") + endif() + list(APPEND swift_flags ${SWIFT_EXPERIMENTAL_EXTRA_FLAGS}) if(SWIFTFILE_OPT_FLAGS) diff --git a/stdlib/private/DifferentiationUnittest/CMakeLists.txt b/stdlib/private/DifferentiationUnittest/CMakeLists.txt index bb6284b191310..33da12b9b766a 100644 --- a/stdlib/private/DifferentiationUnittest/CMakeLists.txt +++ b/stdlib/private/DifferentiationUnittest/CMakeLists.txt @@ -1,6 +1,6 @@ add_swift_target_library(swiftDifferentiationUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB # This file should be listed first. Module name is inferred from the filename. - DifferentiationUnittest.swift + GYB_SOURCES DifferentiationUnittest.swift.gyb SWIFT_MODULE_DEPENDS _Differentiation StdlibUnittest INSTALL_IN_COMPONENT stdlib-experimental diff --git a/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift b/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb similarity index 50% rename from stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift rename to stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb index f24dd18a7925e..282f89f93324f 100644 --- a/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift +++ b/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb @@ -1,4 +1,4 @@ -//===--- DifferentiationUnittest.swift ------------------------------------===// +//===--- DifferentiationUnittest.swift.gyb --------------------------------===// // // This source file is part of the Swift.org open source project // @@ -43,19 +43,21 @@ public extension TestSuite { _ testFunction: @escaping () -> Void ) { test(name, file: file, line: line) { - withLeakChecking(expectedLeakCount: expectedLeakCount, file: file, - line: line, testFunction) + withLeakChecking( + expectedLeakCount: expectedLeakCount, file: file, + line: line, testFunction) } } } -/// A type that tracks the number of live instances of a wrapped value type. +/// A resilient type that tracks the number of live instances of a wrapped +/// value type. /// /// `Tracked` is used to check for memory leaks in functions created via /// automatic differentiation. public struct Tracked { - fileprivate class Box { - fileprivate var value : T + internal class Box { + fileprivate var value: T init(_ value: T) { self.value = value _GlobalLeakCount.count += 1 @@ -64,71 +66,109 @@ public struct Tracked { _GlobalLeakCount.count -= 1 } } - private var handle: Box + internal var handle: Box - @differentiable(where T : Differentiable, T == T.TangentVector) + @differentiable(where T: Differentiable, T == T.TangentVector) public init(_ value: T) { self.handle = Box(value) } - @differentiable(where T : Differentiable, T == T.TangentVector) + @differentiable(where T: Differentiable, T == T.TangentVector) public var value: T { get { handle.value } set { handle.value = newValue } } } -extension Tracked : ExpressibleByFloatLiteral where T : ExpressibleByFloatLiteral { +/// A non-resilient type that tracks the number of live instances of a wrapped +/// value type. +/// +/// `NonresilientTracked` is used to check for memory leaks in functions +/// created via automatic differentiation. +@frozen +public struct NonresilientTracked { + @usableFromInline + internal class Box { + fileprivate var value: T + init(_ value: T) { + self.value = value + _GlobalLeakCount.count += 1 + } + deinit { + _GlobalLeakCount.count -= 1 + } + } + @usableFromInline + internal var handle: Box + + @differentiable(where T: Differentiable, T == T.TangentVector) + public init(_ value: T) { + self.handle = Box(value) + } + + @differentiable(where T: Differentiable, T == T.TangentVector) + public var value: T { + get { handle.value } + set { handle.value = newValue } + } +} + +% for Self in ['Tracked', 'NonresilientTracked']: + +extension ${Self}: ExpressibleByFloatLiteral +where T: ExpressibleByFloatLiteral { public init(floatLiteral value: T.FloatLiteralType) { self.handle = Box(T(floatLiteral: value)) } } -extension Tracked : CustomStringConvertible { - public var description: String { return "Tracked(\(value))" } +extension ${Self}: CustomStringConvertible { + public var description: String { return "${Self}(\(value))" } } -extension Tracked : ExpressibleByIntegerLiteral where T : ExpressibleByIntegerLiteral { +extension ${Self}: ExpressibleByIntegerLiteral +where T: ExpressibleByIntegerLiteral { public init(integerLiteral value: T.IntegerLiteralType) { self.handle = Box(T(integerLiteral: value)) } } -extension Tracked : Comparable where T : Comparable { - public static func < (lhs: Tracked, rhs: Tracked) -> Bool { +extension ${Self}: Comparable where T: Comparable { + public static func < (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value < rhs.value } - public static func <= (lhs: Tracked, rhs: Tracked) -> Bool { + public static func <= (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value <= rhs.value } - public static func > (lhs: Tracked, rhs: Tracked) -> Bool { + public static func > (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value > rhs.value } - public static func >= (lhs: Tracked, rhs: Tracked) -> Bool { + public static func >= (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value >= rhs.value } } -extension Tracked : AdditiveArithmetic where T : AdditiveArithmetic { - public static var zero: Tracked { return Tracked(T.zero) } - public static func + (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value + rhs.value) +extension ${Self}: AdditiveArithmetic where T: AdditiveArithmetic { + public static var zero: ${Self} { return ${Self}(T.zero) } + public static func + (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value + rhs.value) } - public static func - (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value - rhs.value) + public static func - (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value - rhs.value) } } -extension Tracked : Equatable where T : Equatable { - public static func == (lhs: Tracked, rhs: Tracked) -> Bool { +extension ${Self}: Equatable where T: Equatable { + public static func == (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value == rhs.value } } -extension Tracked : SignedNumeric & Numeric where T : SignedNumeric, T == T.Magnitude { - public typealias Magnitude = Tracked +extension ${Self}: SignedNumeric & Numeric +where T: SignedNumeric, T == T.Magnitude { + public typealias Magnitude = ${Self} - public init?(exactly source: U) where U : BinaryInteger { + public init?(exactly source: U) where U: BinaryInteger { if let t = T(exactly: source) { self.init(t) } @@ -136,169 +176,191 @@ extension Tracked : SignedNumeric & Numeric where T : SignedNumeric, T == T.Magn } public var magnitude: Magnitude { return Magnitude(value.magnitude) } - public static func * (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value * rhs.value) + public static func * (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value * rhs.value) } - public static func *= (lhs: inout Tracked, rhs: Tracked) { + public static func *= (lhs: inout ${Self}, rhs: ${Self}) { lhs = lhs * rhs } } -extension Tracked where T : FloatingPoint { - public static func / (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value / rhs.value) +extension ${Self} where T: FloatingPoint { + public static func / (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value / rhs.value) } - public static func /= (lhs: inout Tracked, rhs: Tracked) { + public static func /= (lhs: inout ${Self}, rhs: ${Self}) { lhs = lhs / rhs } } -extension Tracked : Strideable where T : Strideable, T.Stride == T.Stride.Magnitude { - public typealias Stride = Tracked +extension ${Self}: Strideable +where T: Strideable, T.Stride == T.Stride.Magnitude { + public typealias Stride = ${Self} - public func distance(to other: Tracked) -> Stride { + public func distance(to other: ${Self}) -> Stride { return Stride(value.distance(to: other.value)) } - public func advanced(by n: Stride) -> Tracked { - return Tracked(value.advanced(by: n.value)) + public func advanced(by n: Stride) -> ${Self} { + return ${Self}(value.advanced(by: n.value)) } } // For now, `T` must be restricted to trivial types (like `Float` or `Tensor`). -extension Tracked : Differentiable where T : Differentiable, T == T.TangentVector { - public typealias TangentVector = Tracked +extension ${Self}: Differentiable +where T: Differentiable, T == T.TangentVector { + public typealias TangentVector = ${Self} } -extension Tracked where T : Differentiable, T == T.TangentVector { +extension ${Self} where T: Differentiable, T == T.TangentVector { @usableFromInline @derivative(of: init) internal static func _vjpInit(_ value: T) - -> (value: Self, pullback: (Self.TangentVector) -> (T.TangentVector)) { - return (Tracked(value), { v in v.value }) + -> (value: Self, pullback: (Self.TangentVector) -> (T.TangentVector)) + { + return (${Self}(value), { v in v.value }) } @usableFromInline @derivative(of: init) internal static func _jvpInit(_ value: T) - -> (value: Self, differential: (T.TangentVector) -> (Self.TangentVector)) { - return (Tracked(value), { v in Tracked(v) }) + -> (value: Self, differential: (T.TangentVector) -> (Self.TangentVector)) + { + return (${Self}(value), { v in ${Self}(v) }) } @usableFromInline @derivative(of: value) - internal func _vjpValue() -> (value: T, pullback: (T.TangentVector) -> Self.TangentVector) { - return (value, { v in Tracked(v) }) + internal func _vjpValue() -> ( + value: T, pullback: (T.TangentVector) -> Self.TangentVector + ) { + return (value, { v in ${Self}(v) }) } @usableFromInline @derivative(of: value) - internal func _jvpValue() -> (value: T, differential: (Self.TangentVector) -> T.TangentVector) { + internal func _jvpValue() -> ( + value: T, differential: (Self.TangentVector) -> T.TangentVector + ) { return (value, { v in v.value }) } } -extension Tracked where T : Differentiable, T == T.TangentVector { +extension ${Self} where T: Differentiable, T == T.TangentVector { @usableFromInline @derivative(of: +) internal static func _vjpAdd(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs + rhs, { v in (v, v) }) } @usableFromInline @derivative(of: +) internal static func _jvpAdd(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> Self) { + -> (value: Self, differential: (Self, Self) -> Self) + { return (lhs + rhs, { $0 + $1 }) } @usableFromInline @derivative(of: -) internal static func _vjpSubtract(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs - rhs, { v in (v, .zero - v) }) } @usableFromInline @derivative(of: -) internal static func _jvpSubtract(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> Self) { + -> (value: Self, differential: (Self, Self) -> Self) + { return (lhs - rhs, { $0 - $1 }) } } -extension Tracked where T : Differentiable & SignedNumeric, T == T.Magnitude, - T == T.TangentVector { +extension ${Self} +where + T: Differentiable & SignedNumeric, T == T.Magnitude, + T == T.TangentVector +{ @usableFromInline @derivative(of: *) internal static func _vjpMultiply(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs * rhs, { v in (v * rhs, v * lhs) }) } @usableFromInline @derivative(of: *) internal static func _jvpMultiply(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> (Self)) { + -> (value: Self, differential: (Self, Self) -> (Self)) + { return (lhs * rhs, { (dx, dy) in dx * rhs + dy * lhs }) } } -extension Tracked where T : Differentiable & FloatingPoint, T == T.TangentVector { +extension ${Self} +where T: Differentiable & FloatingPoint, T == T.TangentVector { @usableFromInline @derivative(of: /) internal static func _vjpDivide(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs / rhs, { v in (v / rhs, -lhs / (rhs * rhs) * v) }) } @usableFromInline @derivative(of: /) internal static func _jvpDivide(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> (Self)) { + -> (value: Self, differential: (Self, Self) -> (Self)) + { return (lhs / rhs, { (dx, dy) in dx / rhs - lhs / (rhs * rhs) * dy }) } } -// Differential operators for `Tracked`. +// Differential operators for `${Self}`. public func gradient( - at x: T, in f: @differentiable (T) -> Tracked + at x: T, in f: @differentiable (T) -> ${Self} ) -> T.TangentVector where R.TangentVector == R { return pullback(at: x, in: f)(1) } public func gradient( - at x: T, _ y: U, in f: @differentiable (T, U) -> Tracked + at x: T, _ y: U, in f: @differentiable (T, U) -> ${Self} ) -> (T.TangentVector, U.TangentVector) where R.TangentVector == R { return pullback(at: x, y, in: f)(1) } public func derivative( - at x: Tracked, in f: @differentiable (Tracked) -> R + at x: ${Self}, in f: @differentiable (${Self}) -> R ) -> R.TangentVector where T.TangentVector == T { return differential(at: x, in: f)(1) } public func derivative( - at x: Tracked, _ y: Tracked, - in f: @differentiable (Tracked, Tracked) -> R + at x: ${Self}, _ y: ${Self}, + in f: @differentiable (${Self}, ${Self}) -> R ) -> R.TangentVector where T.TangentVector == T, U.TangentVector == U { return differential(at: x, y, in: f)(1, 1) } public func valueWithGradient( - at x: T, in f: @differentiable (T) -> Tracked -) -> (value: Tracked, gradient: T.TangentVector) { + at x: T, in f: @differentiable (T) -> ${Self} +) -> (value: ${Self}, gradient: T.TangentVector) { let (y, pullback) = valueWithPullback(at: x, in: f) return (y, pullback(1)) } public func valueWithDerivative( - at x: Tracked, in f: @differentiable (Tracked) -> R + at x: ${Self}, in f: @differentiable (${Self}) -> R ) -> (value: R, derivative: R.TangentVector) { let (y, differential) = valueWithDifferential(at: x, in: f) return (y, differential(1)) } + +% end diff --git a/stdlib/public/Darwin/Foundation/IndexPath.swift b/stdlib/public/Darwin/Foundation/IndexPath.swift index 62b29064ab5a6..5c5d89d4ed702 100644 --- a/stdlib/public/Darwin/Foundation/IndexPath.swift +++ b/stdlib/public/Darwin/Foundation/IndexPath.swift @@ -617,16 +617,17 @@ public struct IndexPath : ReferenceConvertible, Equatable, Hashable, MutableColl fileprivate init(nsIndexPath: __shared ReferenceType) { let count = nsIndexPath.length - if count == 0 { + switch count { + case 0: _indexes = [] - } else if count == 1 { + case 1: _indexes = .single(nsIndexPath.index(atPosition: 0)) - } else if count == 2 { + case 2: _indexes = .pair(nsIndexPath.index(atPosition: 0), nsIndexPath.index(atPosition: 1)) - } else { - var indexes = Array(repeating: 0, count: count) - indexes.withUnsafeMutableBufferPointer { (buffer: inout UnsafeMutableBufferPointer) -> Void in + default: + let indexes = Array(unsafeUninitializedCapacity: count) { buffer, initializedCount in nsIndexPath.getIndexes(buffer.baseAddress!, range: NSRange(location: 0, length: count)) + initializedCount = count } _indexes = .array(indexes) } diff --git a/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb b/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb index 8de2cd5ca2a5b..f2ff2fcbff530 100644 --- a/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb +++ b/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb @@ -205,8 +205,9 @@ extension ${Self} { static func _jvpMultiplyAssign(_ lhs: inout ${Self}, _ rhs: ${Self}) -> ( value: Void, differential: (inout ${Self}, ${Self}) -> Void ) { + let oldLhs = lhs lhs *= rhs - return ((), { $0 *= $1 }) + return ((), { $0 = $0 * rhs + oldLhs * $1 }) } ${Availability(bits)} @@ -251,8 +252,9 @@ extension ${Self} { static func _jvpDivideAssign(_ lhs: inout ${Self}, _ rhs: ${Self}) -> ( value: Void, differential: (inout ${Self}, ${Self}) -> Void ) { + let oldLhs = lhs lhs /= rhs - return ((), { $0 /= $1 }) + return ((), { $0 = ($0 * rhs - oldLhs * $1) / (rhs * rhs) }) } } diff --git a/stdlib/public/Platform/ucrt.modulemap b/stdlib/public/Platform/ucrt.modulemap index 03fe87bf74451..2d88621038f4a 100644 --- a/stdlib/public/Platform/ucrt.modulemap +++ b/stdlib/public/Platform/ucrt.modulemap @@ -95,6 +95,7 @@ module ucrt [system] { module stat { header "sys/stat.h" + header "direct.h" export * } diff --git a/stdlib/public/Platform/winsdk.modulemap b/stdlib/public/Platform/winsdk.modulemap index 9baba25569167..fc0d961bd50a9 100644 --- a/stdlib/public/Platform/winsdk.modulemap +++ b/stdlib/public/Platform/winsdk.modulemap @@ -21,6 +21,10 @@ module WinSDK [system] { link "WS2_32.Lib" } + module WinSock { + header "winsock.h" + } + module core { module acl { header "AclAPI.h" @@ -206,6 +210,11 @@ module WinSDK [system] { export * } + module WinBase { + header "winbase.h" + export * + } + module WinCrypt { header "wincrypt.h" export * @@ -241,5 +250,12 @@ module WinSDK [system] { link "RpcRT4.Lib" } + + module WinSVC { + header "winsvc.h" + export * + + link "AdvAPI32.Lib" + } } diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp index d9d437f234ff0..729765edd1893 100644 --- a/stdlib/public/Reflection/TypeLowering.cpp +++ b/stdlib/public/Reflection/TypeLowering.cpp @@ -317,13 +317,13 @@ class UnsupportedEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *index) const { + int *index) const override { return false; } bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { return false; } }; @@ -337,13 +337,13 @@ class EmptyEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *index) const { + int *index) const override { return false; } bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { return false; } }; @@ -361,14 +361,14 @@ class TrivialEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *index) const { + int *index) const override { *index = -1; return true; } bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { *CaseIndex = 0; return true; } @@ -389,7 +389,7 @@ class NoPayloadEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *index) const { + int *index) const override { uint32_t tag = 0; if (!reader.readInteger(address, getSize(), &tag)) { return false; @@ -404,7 +404,7 @@ class NoPayloadEnumTypeInfo: public EnumTypeInfo { bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { uint32_t tag = 0; if (!reader.readInteger(address, getSize(), &tag)) { return false; @@ -433,7 +433,7 @@ class SinglePayloadEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *extraInhabitantIndex) const { + int *extraInhabitantIndex) const override { FieldInfo PayloadCase = getCases()[0]; if (getSize() < PayloadCase.TI.getSize()) { // Single payload enums that use a separate tag don't export any XIs @@ -464,7 +464,7 @@ class SinglePayloadEnumTypeInfo: public EnumTypeInfo { bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { auto PayloadCase = getCases()[0]; auto PayloadSize = PayloadCase.TI.getSize(); auto DiscriminatorAddress = address + PayloadSize; @@ -550,7 +550,7 @@ class SimpleMultiPayloadEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *extraInhabitantIndex) const { + int *extraInhabitantIndex) const override { unsigned long PayloadSize = getPayloadSize(); unsigned PayloadCount = getNumPayloadCases(); unsigned TagSize = getSize() - PayloadSize; @@ -573,7 +573,7 @@ class SimpleMultiPayloadEnumTypeInfo: public EnumTypeInfo { bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { unsigned long PayloadSize = getPayloadSize(); unsigned PayloadCount = getNumPayloadCases(); unsigned NumCases = getNumCases(); @@ -802,7 +802,7 @@ class MultiPayloadEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *extraInhabitantIndex) const { + int *extraInhabitantIndex) const override { unsigned long payloadSize = getPayloadSize(); // Multi payload enums that use spare bits export unused tag values as XIs. @@ -879,7 +879,7 @@ class MultiPayloadEnumTypeInfo: public EnumTypeInfo { bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { unsigned long payloadSize = getPayloadSize(); unsigned NumPayloadCases = getNumPayloadCases(); @@ -1034,7 +1034,10 @@ class ExistentialTypeInfoBuilder { ++WitnessTableCount; if (auto *Superclass = TC.getBuilder().lookupSuperclass(P)) { - auto *SuperclassTI = TC.getTypeInfo(Superclass); + // ObjC class info should be available in the metadata, so it's safe + // to not pass an external provider here. This helps preserving the + // layering. + auto *SuperclassTI = TC.getTypeInfo(Superclass, nullptr); if (SuperclassTI == nullptr) { DEBUG_LOG(fprintf(stderr, "No TypeInfo for superclass: "); Superclass->dump()); @@ -1140,7 +1143,7 @@ class ExistentialTypeInfoBuilder { Invalid = true; } - const TypeInfo *build() { + const TypeInfo *build(remote::TypeInfoProvider *ExternalTypeInfo) { examineProtocols(); if (Invalid) @@ -1176,12 +1179,14 @@ class ExistentialTypeInfoBuilder { // Class existentials consist of a single retainable pointer // followed by witness tables. if (Refcounting == ReferenceCounting::Unknown) - builder.addField("object", TC.getUnknownObjectTypeRef()); + builder.addField("object", TC.getUnknownObjectTypeRef(), + ExternalTypeInfo); else - builder.addField("object", TC.getNativeObjectTypeRef()); + builder.addField("object", TC.getNativeObjectTypeRef(), + ExternalTypeInfo); break; case ExistentialTypeRepresentation::Opaque: { - auto *TI = TC.getTypeInfo(TC.getRawPointerTypeRef()); + auto *TI = TC.getTypeInfo(TC.getRawPointerTypeRef(), ExternalTypeInfo); if (TI == nullptr) { DEBUG_LOG(fprintf(stderr, "No TypeInfo for RawPointer\n")); return nullptr; @@ -1195,21 +1200,21 @@ class ExistentialTypeInfoBuilder { TI->getAlignment(), /*numExtraInhabitants=*/0, /*bitwiseTakable=*/true); - builder.addField("metadata", TC.getAnyMetatypeTypeRef()); + builder.addField("metadata", TC.getAnyMetatypeTypeRef(), ExternalTypeInfo); break; } case ExistentialTypeRepresentation::Error: - builder.addField("error", TC.getUnknownObjectTypeRef()); + builder.addField("error", TC.getUnknownObjectTypeRef(), ExternalTypeInfo); break; } for (unsigned i = 0; i < WitnessTableCount; ++i) - builder.addField("wtable", TC.getRawPointerTypeRef()); + builder.addField("wtable", TC.getRawPointerTypeRef(), ExternalTypeInfo); return builder.build(); } - const TypeInfo *buildMetatype() { + const TypeInfo *buildMetatype(remote::TypeInfoProvider *ExternalTypeInfo) { examineProtocols(); if (Invalid) @@ -1226,9 +1231,9 @@ class ExistentialTypeInfoBuilder { RecordTypeInfoBuilder builder(TC, RecordKind::ExistentialMetatype); - builder.addField("metadata", TC.getAnyMetatypeTypeRef()); + builder.addField("metadata", TC.getAnyMetatypeTypeRef(), ExternalTypeInfo); for (unsigned i = 0; i < WitnessTableCount; ++i) - builder.addField("wtable", TC.getRawPointerTypeRef()); + builder.addField("wtable", TC.getRawPointerTypeRef(), ExternalTypeInfo); return builder.build(); } @@ -1285,9 +1290,10 @@ unsigned RecordTypeInfoBuilder::addField(unsigned fieldSize, return offset; } -void RecordTypeInfoBuilder::addField(const std::string &Name, - const TypeRef *TR) { - const TypeInfo *TI = TC.getTypeInfo(TR); +void RecordTypeInfoBuilder::addField( + const std::string &Name, const TypeRef *TR, + remote::TypeInfoProvider *ExternalTypeInfo) { + const TypeInfo *TI = TC.getTypeInfo(TR, ExternalTypeInfo); if (TI == nullptr) { DEBUG_LOG(fprintf(stderr, "No TypeInfo for field type: "); TR->dump()); Invalid = true; @@ -1394,14 +1400,13 @@ TypeConverter::getThinFunctionTypeInfo() { /// Thick functions consist of a function pointer and nullable retainable /// context pointer. The context is modeled exactly like a native Swift /// class reference. -const TypeInfo * -TypeConverter::getThickFunctionTypeInfo() { +const TypeInfo *TypeConverter::getThickFunctionTypeInfo() { if (ThickFunctionTI != nullptr) return ThickFunctionTI; RecordTypeInfoBuilder builder(*this, RecordKind::ThickFunction); - builder.addField("function", getThinFunctionTypeRef()); - builder.addField("context", getNativeObjectTypeRef()); + builder.addField("function", getThinFunctionTypeRef(), nullptr); + builder.addField("context", getNativeObjectTypeRef(), nullptr); ThickFunctionTI = builder.build(); return ThickFunctionTI; @@ -1758,14 +1763,14 @@ class EnumTypeInfoBuilder { : TC(TC), Size(0), Alignment(1), NumExtraInhabitants(0), BitwiseTakable(true), Invalid(false) {} - const TypeInfo * - build(const TypeRef *TR, RemoteRef FD) { + const TypeInfo *build(const TypeRef *TR, RemoteRef FD, + remote::TypeInfoProvider *ExternalTypeInfo) { // Sort enum into payload and no-payload cases. unsigned NoPayloadCases = 0; std::vector PayloadCases; std::vector Fields; - if (!TC.getBuilder().getFieldTypeRefs(TR, FD, Fields)) { + if (!TC.getBuilder().getFieldTypeRefs(TR, FD, ExternalTypeInfo, Fields)) { Invalid = true; return nullptr; } @@ -1777,7 +1782,7 @@ class EnumTypeInfoBuilder { } else { PayloadCases.push_back(Case); auto *CaseTR = getCaseTypeRef(Case); - auto *CaseTI = TC.getTypeInfo(CaseTR); + auto *CaseTI = TC.getTypeInfo(CaseTR, ExternalTypeInfo); addCase(Case.Name, CaseTR, CaseTI); } } @@ -1810,7 +1815,7 @@ class EnumTypeInfoBuilder { } else if (PayloadCases.size() == 1) { // SinglePayloadEnumImplStrategy auto *CaseTR = getCaseTypeRef(PayloadCases[0]); - auto *CaseTI = TC.getTypeInfo(CaseTR); + auto *CaseTI = TC.getTypeInfo(CaseTR, ExternalTypeInfo); if (CaseTR == nullptr || CaseTI == nullptr) { return nullptr; } @@ -1910,11 +1915,13 @@ class EnumTypeInfoBuilder { class LowerType : public TypeRefVisitor { TypeConverter &TC; + remote::TypeInfoProvider *ExternalTypeInfo; public: using TypeRefVisitor::visit; - LowerType(TypeConverter &TC) : TC(TC) {} + LowerType(TypeConverter &TC, remote::TypeInfoProvider *ExternalTypeInfo) + : TC(TC), ExternalTypeInfo(ExternalTypeInfo) {} const TypeInfo *visitBuiltinTypeRef(const BuiltinTypeRef *B) { /// The context field of a thick function is a Builtin.NativeObject. @@ -1950,6 +1957,18 @@ class LowerType // Otherwise, we're out of luck. if (FD == nullptr) { + if (ExternalTypeInfo) { + // Ask the ExternalTypeInfo. It may be a Clang-imported type. + std::string MangledName; + if (auto N = dyn_cast(TR)) + MangledName = N->getMangledName(); + else if (auto BG = dyn_cast(TR)) + MangledName = BG->getMangledName(); + if (!MangledName.empty()) + if (auto *imported = ExternalTypeInfo->getTypeInfo(MangledName)) + return imported; + } + DEBUG_LOG(fprintf(stderr, "No TypeInfo for nominal type: "); TR->dump()); return nullptr; } @@ -1966,17 +1985,17 @@ class LowerType RecordTypeInfoBuilder builder(TC, RecordKind::Struct); std::vector Fields; - if (!TC.getBuilder().getFieldTypeRefs(TR, FD, Fields)) + if (!TC.getBuilder().getFieldTypeRefs(TR, FD, ExternalTypeInfo, Fields)) return nullptr; for (auto Field : Fields) - builder.addField(Field.Name, Field.TR); + builder.addField(Field.Name, Field.TR, ExternalTypeInfo); return builder.build(); } case FieldDescriptorKind::Enum: case FieldDescriptorKind::MultiPayloadEnum: { EnumTypeInfoBuilder builder(TC); - return builder.build(TR, FD); + return builder.build(TR, FD, ExternalTypeInfo); } case FieldDescriptorKind::ObjCClass: return TC.getReferenceTypeInfo(ReferenceKind::Strong, @@ -2002,7 +2021,8 @@ class LowerType const TypeInfo *visitTupleTypeRef(const TupleTypeRef *T) { RecordTypeInfoBuilder builder(TC, RecordKind::Tuple); for (auto Element : T->getElements()) - builder.addField("", Element); + // The label is not going to be relevant/harmful for looking up type info. + builder.addField("", Element, ExternalTypeInfo); return builder.build(); } @@ -2016,7 +2036,7 @@ class LowerType ReferenceCounting::Unknown); case FunctionMetadataConvention::Thin: case FunctionMetadataConvention::CFunctionPointer: - return TC.getTypeInfo(TC.getThinFunctionTypeRef()); + return TC.getTypeInfo(TC.getThinFunctionTypeRef(), ExternalTypeInfo); } swift_runtime_unreachable("Unhandled FunctionMetadataConvention in switch."); @@ -2026,7 +2046,7 @@ class LowerType visitProtocolCompositionTypeRef(const ProtocolCompositionTypeRef *PC) { ExistentialTypeInfoBuilder builder(TC); builder.addProtocolComposition(PC); - return builder.build(); + return builder.build(ExternalTypeInfo); } const TypeInfo *visitMetatypeTypeRef(const MetatypeTypeRef *M) { @@ -2037,7 +2057,7 @@ class LowerType case MetatypeRepresentation::Thin: return TC.getEmptyTypeInfo(); case MetatypeRepresentation::Thick: - return TC.getTypeInfo(TC.getAnyMetatypeTypeRef()); + return TC.getTypeInfo(TC.getAnyMetatypeTypeRef(), ExternalTypeInfo); } swift_runtime_unreachable("Unhandled MetatypeRepresentation in switch."); @@ -2055,7 +2075,7 @@ class LowerType return nullptr; } - return builder.buildMetatype(); + return builder.buildMetatype(ExternalTypeInfo); } const TypeInfo * @@ -2102,7 +2122,7 @@ class LowerType if (auto *EnumTI = dyn_cast(TI)) { if (EnumTI->isOptional() && Kind == ReferenceKind::Weak) { - auto *TI = TC.getTypeInfo(EnumTI->getCases()[0].TR); + auto *TI = TC.getTypeInfo(EnumTI->getCases()[0].TR, ExternalTypeInfo); return rebuildStorageTypeInfo(TI, Kind); } } @@ -2142,7 +2162,7 @@ class LowerType const TypeInfo * visitAnyStorageTypeRef(const TypeRef *TR, ReferenceKind Kind) { - return rebuildStorageTypeInfo(TC.getTypeInfo(TR), Kind); + return rebuildStorageTypeInfo(TC.getTypeInfo(TR, ExternalTypeInfo), Kind); } #define REF_STORAGE(Name, name, ...) \ @@ -2170,9 +2190,11 @@ class LowerType } }; -const TypeInfo *TypeConverter::getTypeInfo(const TypeRef *TR) { +const TypeInfo * +TypeConverter::getTypeInfo(const TypeRef *TR, + remote::TypeInfoProvider *ExternalTypeInfo) { // See if we already computed the result - auto found = Cache.find(TR); + auto found = Cache.find({TR, ExternalTypeInfo}); if (found != Cache.end()) return found->second; @@ -2184,16 +2206,17 @@ const TypeInfo *TypeConverter::getTypeInfo(const TypeRef *TR) { } // Compute the result and cache it - auto *TI = LowerType(*this).visit(TR); - Cache[TR] = TI; + auto *TI = LowerType(*this, ExternalTypeInfo).visit(TR); + Cache.insert({{TR, ExternalTypeInfo}, TI}); RecursionCheck.erase(TR); return TI; } -const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR, - unsigned start) { +const TypeInfo *TypeConverter::getClassInstanceTypeInfo( + const TypeRef *TR, unsigned start, + remote::TypeInfoProvider *ExternalTypeInfo) { auto FD = getBuilder().getFieldTypeInfo(TR); if (FD == nullptr) { DEBUG_LOG(fprintf(stderr, "No field descriptor: "); TR->dump()); @@ -2208,7 +2231,7 @@ const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR, RecordTypeInfoBuilder builder(*this, RecordKind::ClassInstance); std::vector Fields; - if (!getBuilder().getFieldTypeRefs(TR, FD, Fields)) + if (!getBuilder().getFieldTypeRefs(TR, FD, ExternalTypeInfo, Fields)) return nullptr; // Start layout from the given instance start offset. This should @@ -2219,7 +2242,7 @@ const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR, /*bitwiseTakable=*/true); for (auto Field : Fields) - builder.addField(Field.Name, Field.TR); + builder.addField(Field.Name, Field.TR, ExternalTypeInfo); return builder.build(); } case FieldDescriptorKind::Struct: diff --git a/stdlib/public/Reflection/TypeRef.cpp b/stdlib/public/Reflection/TypeRef.cpp index d1ef7a63351e7..5b5b1ddebb630 100644 --- a/stdlib/public/Reflection/TypeRef.cpp +++ b/stdlib/public/Reflection/TypeRef.cpp @@ -109,8 +109,14 @@ class PrintTypeRef : public TypeRefVisitor { void visitTupleTypeRef(const TupleTypeRef *T) { printHeader("tuple"); - for (auto element : T->getElements()) - printRec(element); + T->getLabels(); + auto Labels = T->getLabels(); + for (auto NameElement : llvm::zip_first(Labels, T->getElements())) { + auto Label = std::get<0>(NameElement); + if (!Label.empty()) + fprintf(file, "%s = ", Label.str().c_str()); + printRec(std::get<1>(NameElement)); + } fprintf(file, ")"); } @@ -400,6 +406,14 @@ class DemanglingForTypeRef : public TypeRefVisitor { Demangle::Demangler &Dem; + /// Demangle a type and dive into the outermost Type node. + Demangle::NodePointer demangleAndUnwrapType(llvm::StringRef mangledName) { + auto node = Dem.demangleType(mangledName); + if (node && node->getKind() == Node::Kind::Type && node->getNumChildren()) + node = node->getFirstChild(); + return node; + } + public: DemanglingForTypeRef(Demangle::Demangler &Dem) : Dem(Dem) {} @@ -414,13 +428,32 @@ class DemanglingForTypeRef } Demangle::NodePointer visitBuiltinTypeRef(const BuiltinTypeRef *B) { - return Dem.demangleType(B->getMangledName()); + return demangleAndUnwrapType(B->getMangledName()); } Demangle::NodePointer visitNominalTypeRef(const NominalTypeRef *N) { - if (auto parent = N->getParent()) - assert(false && "not implemented"); - return Dem.demangleType(N->getMangledName()); + auto node = demangleAndUnwrapType(N->getMangledName()); + if (!node || node->getNumChildren() != 2) + return node; + + auto parent = N->getParent(); + if (!parent) + return node; + + // Swap in the richer parent that is stored in the NominalTypeRef + // instead of what is encoded in the mangled name. The mangled name's + // context has been "unspecialized" by NodeBuilder. + auto parentNode = visit(parent); + if (!parentNode) + return node; + if (parentNode->getKind() == Node::Kind::Type && + parentNode->getNumChildren()) + parentNode = parentNode->getFirstChild(); + + auto contextualizedNode = Dem.createNode(node->getKind()); + contextualizedNode->addChild(parentNode, Dem); + contextualizedNode->addChild(node->getChild(1), Dem); + return contextualizedNode; } Demangle::NodePointer @@ -459,9 +492,15 @@ class DemanglingForTypeRef Demangle::NodePointer visitTupleTypeRef(const TupleTypeRef *T) { auto tuple = Dem.createNode(Node::Kind::Tuple); - for (auto element : T->getElements()) { + auto Labels = T->getLabels(); + for (auto LabelElement : llvm::zip(Labels, T->getElements())) { auto tupleElt = Dem.createNode(Node::Kind::TupleElement); - tupleElt->addChild(visit(element), Dem); + auto Label = std::get<0>(LabelElement); + if (!Label.empty()) { + auto name = Dem.createNode(Node::Kind::TupleElementName, Label); + tupleElt->addChild(name, Dem); + } + tupleElt->addChild(visit(std::get<1>(LabelElement)), Dem); tuple->addChild(tupleElt, Dem); } return tuple; @@ -605,7 +644,10 @@ class DemanglingForTypeRef Demangle::NodePointer visitMetatypeTypeRef(const MetatypeTypeRef *M) { auto node = Dem.createNode(Node::Kind::Metatype); - assert(!M->wasAbstract() && "not implemented"); + // FIXME: This is lossy. @objc_metatype is also abstract. + auto repr = Dem.createNode(Node::Kind::MetatypeRepresentation, + M->wasAbstract() ? "@thick" : "@thin"); + node->addChild(repr, Dem); node->addChild(visit(M->getInstanceType()), Dem); return node; } @@ -638,7 +680,7 @@ class DemanglingForTypeRef } Demangle::NodePointer visitForeignClassTypeRef(const ForeignClassTypeRef *F) { - return Dem.demangleType(F->getName()); + return demangleAndUnwrapType(F->getName()); } Demangle::NodePointer visitObjCClassTypeRef(const ObjCClassTypeRef *OC) { @@ -816,7 +858,8 @@ class ThickenMetatype std::vector Elements; for (auto Element : T->getElements()) Elements.push_back(visit(Element)); - return TupleTypeRef::create(Builder, Elements); + std::string Labels = T->getLabelString(); + return TupleTypeRef::create(Builder, Elements, std::move(Labels)); } const TypeRef *visitFunctionTypeRef(const FunctionTypeRef *F) { @@ -901,7 +944,7 @@ class TypeRefSubstitution using TypeRefVisitor::visit; TypeRefSubstitution(TypeRefBuilder &Builder, GenericArgumentMap Substitutions) - : Builder(Builder), Substitutions(Substitutions) {} + : Builder(Builder), Substitutions(Substitutions) {} const TypeRef *visitBuiltinTypeRef(const BuiltinTypeRef *B) { return B; @@ -929,7 +972,8 @@ class TypeRefSubstitution std::vector Elements; for (auto Element : T->getElements()) Elements.push_back(visit(Element)); - return TupleTypeRef::create(Builder, Elements); + std::string Labels = T->getLabelString(); + return TupleTypeRef::create(Builder, Elements, std::move(Labels)); } const TypeRef *visitFunctionTypeRef(const FunctionTypeRef *F) { @@ -1081,8 +1125,8 @@ class TypeRefSubstitution } }; -const TypeRef * -TypeRef::subst(TypeRefBuilder &Builder, const GenericArgumentMap &Subs) const { +const TypeRef *TypeRef::subst(TypeRefBuilder &Builder, + const GenericArgumentMap &Subs) const { return TypeRefSubstitution(Builder, Subs).visit(this); } diff --git a/stdlib/public/Reflection/TypeRefBuilder.cpp b/stdlib/public/Reflection/TypeRefBuilder.cpp index 772afeb1e98f2..4440a974da740 100644 --- a/stdlib/public/Reflection/TypeRefBuilder.cpp +++ b/stdlib/public/Reflection/TypeRefBuilder.cpp @@ -135,7 +135,8 @@ lookupTypeWitness(const std::string &MangledTypeName, auto SubstitutedTypeName = readTypeRef(AssocTy, AssocTy->SubstitutedTypeName); auto Demangled = demangleTypeRef(SubstitutedTypeName); - auto *TypeWitness = swift::Demangle::decodeMangledType(*this, Demangled); + auto *TypeWitness = + swift::Demangle::decodeMangledType(*this, Demangled).getType(); AssociatedTypeCache.insert(std::make_pair(key, TypeWitness)); return TypeWitness; @@ -145,8 +146,7 @@ lookupTypeWitness(const std::string &MangledTypeName, return nullptr; } -const TypeRef * TypeRefBuilder:: -lookupSuperclass(const TypeRef *TR) { +const TypeRef *TypeRefBuilder::lookupSuperclass(const TypeRef *TR) { const auto &FD = getFieldTypeInfo(TR); if (FD == nullptr) return nullptr; @@ -155,7 +155,8 @@ lookupSuperclass(const TypeRef *TR) { return nullptr; auto Demangled = demangleTypeRef(readTypeRef(FD, FD->Superclass)); - auto Unsubstituted = swift::Demangle::decodeMangledType(*this, Demangled); + auto Unsubstituted = + swift::Demangle::decodeMangledType(*this, Demangled).getType(); if (!Unsubstituted) return nullptr; @@ -202,8 +203,8 @@ TypeRefBuilder::getFieldTypeInfo(const TypeRef *TR) { } bool TypeRefBuilder::getFieldTypeRefs( - const TypeRef *TR, - RemoteRef FD, + const TypeRef *TR, RemoteRef FD, + remote::TypeInfoProvider *ExternalTypeInfo, std::vector &Fields) { if (FD == nullptr) return false; @@ -226,7 +227,8 @@ bool TypeRefBuilder::getFieldTypeRefs( } auto Demangled = demangleTypeRef(readTypeRef(Field,Field->MangledTypeName)); - auto Unsubstituted = swift::Demangle::decodeMangledType(*this, Demangled); + auto Unsubstituted = + swift::Demangle::decodeMangledType(*this, Demangled).getType(); if (!Unsubstituted) return false; @@ -304,7 +306,7 @@ TypeRefBuilder::getClosureContextInfo(RemoteRef CD) { if (CR->hasMangledTypeName()) { auto MangledName = readTypeRef(CR, CR->MangledTypeName); auto DemangleTree = demangleTypeRef(MangledName); - TR = swift::Demangle::decodeMangledType(*this, DemangleTree); + TR = swift::Demangle::decodeMangledType(*this, DemangleTree).getType(); } Info.CaptureTypes.push_back(TR); } @@ -316,7 +318,7 @@ TypeRefBuilder::getClosureContextInfo(RemoteRef CD) { if (MSR->hasMangledTypeName()) { auto MangledName = readTypeRef(MSR, MSR->MangledTypeName); auto DemangleTree = demangleTypeRef(MangledName); - TR = swift::Demangle::decodeMangledType(*this, DemangleTree); + TR = swift::Demangle::decodeMangledType(*this, DemangleTree).getType(); } const MetadataSource *MS = nullptr; @@ -344,12 +346,17 @@ TypeRefBuilder::dumpTypeRef(RemoteRef MangledName, auto DemangleTree = demangleTypeRef(MangledName); auto TypeName = nodeToString(DemangleTree); fprintf(file, "%s\n", TypeName.c_str()); - auto TR = swift::Demangle::decodeMangledType(*this, DemangleTree); - if (!TR) { + auto Result = swift::Demangle::decodeMangledType(*this, DemangleTree); + if (Result.isError()) { + auto *Error = Result.getError(); + char *ErrorStr = Error->copyErrorString(); auto str = getTypeRefString(MangledName); - fprintf(file, "!!! Invalid typeref: %s\n", std::string(str.begin(), str.end()).c_str()); + fprintf(file, "!!! Invalid typeref: %s - %s\n", + std::string(str.begin(), str.end()).c_str(), ErrorStr); + Error->freeErrorString(ErrorStr); return; } + auto TR = Result.getType(); TR->dump(file); fprintf(file, "\n"); } diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index 114cf058512d0..9d5afad1cf41f 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -298,7 +298,7 @@ swift_reflection_typeRefForMangledTypeName(SwiftReflectionContextRef ContextRef, const char *MangledTypeName, uint64_t Length) { auto Context = ContextRef->nativeContext; - auto TR = Context->readTypeFromMangledName(MangledTypeName, Length); + auto TR = Context->readTypeFromMangledName(MangledTypeName, Length).getType(); return reinterpret_cast(TR); } @@ -447,6 +447,12 @@ static swift_childinfo_t convertChild(const TypeInfo *TI, unsigned Index) { FieldInfo = &(RecordTI->getFields()[Index]); } else { assert(false && "convertChild(TI): TI must be record or enum typeinfo"); + return { + "unknown TypeInfo kind", + 0, + SWIFT_UNKNOWN, + 0, + }; } return { @@ -471,7 +477,7 @@ swift_reflection_infoForTypeRef(SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef) { auto Context = ContextRef->nativeContext; auto TR = reinterpret_cast(OpaqueTypeRef); - auto TI = Context->getTypeInfo(TR); + auto TI = Context->getTypeInfo(TR, nullptr); return convertTypeInfo(TI); } @@ -481,7 +487,7 @@ swift_reflection_childOfTypeRef(SwiftReflectionContextRef ContextRef, unsigned Index) { auto Context = ContextRef->nativeContext; auto TR = reinterpret_cast(OpaqueTypeRef); - auto *TI = Context->getTypeInfo(TR); + auto *TI = Context->getTypeInfo(TR, nullptr); return convertChild(TI, Index); } @@ -489,7 +495,7 @@ swift_typeinfo_t swift_reflection_infoForMetadata(SwiftReflectionContextRef ContextRef, uintptr_t Metadata) { auto Context = ContextRef->nativeContext; - auto *TI = Context->getMetadataTypeInfo(Metadata); + auto *TI = Context->getMetadataTypeInfo(Metadata, nullptr); return convertTypeInfo(TI); } @@ -498,7 +504,7 @@ swift_reflection_childOfMetadata(SwiftReflectionContextRef ContextRef, uintptr_t Metadata, unsigned Index) { auto Context = ContextRef->nativeContext; - auto *TI = Context->getMetadataTypeInfo(Metadata); + auto *TI = Context->getMetadataTypeInfo(Metadata, nullptr); return convertChild(TI, Index); } @@ -506,7 +512,7 @@ swift_typeinfo_t swift_reflection_infoForInstance(SwiftReflectionContextRef ContextRef, uintptr_t Object) { auto Context = ContextRef->nativeContext; - auto *TI = Context->getInstanceTypeInfo(Object); + auto *TI = Context->getInstanceTypeInfo(Object, nullptr); return convertTypeInfo(TI); } @@ -515,7 +521,7 @@ swift_reflection_childOfInstance(SwiftReflectionContextRef ContextRef, uintptr_t Object, unsigned Index) { auto Context = ContextRef->nativeContext; - auto *TI = Context->getInstanceTypeInfo(Object); + auto *TI = Context->getInstanceTypeInfo(Object, nullptr); return convertChild(TI, Index); } @@ -529,10 +535,9 @@ int swift_reflection_projectExistential(SwiftReflectionContextRef ContextRef, auto RemoteExistentialAddress = RemoteAddress(ExistentialAddress); const TypeRef *InstanceTR = nullptr; RemoteAddress RemoteStartOfInstanceData(nullptr); - auto Success = Context->projectExistential(RemoteExistentialAddress, - ExistentialTR, - &InstanceTR, - &RemoteStartOfInstanceData); + auto Success = Context->projectExistential( + RemoteExistentialAddress, ExistentialTR, &InstanceTR, + &RemoteStartOfInstanceData, nullptr); if (Success) { *InstanceTypeRef = reinterpret_cast(InstanceTR); @@ -549,10 +554,11 @@ int swift_reflection_projectEnumValue(SwiftReflectionContextRef ContextRef, auto Context = ContextRef->nativeContext; auto EnumTR = reinterpret_cast(EnumTypeRef); auto RemoteEnumAddress = RemoteAddress(EnumAddress); - if (!Context->projectEnumValue(RemoteEnumAddress, EnumTR, CaseIndex)) { + if (!Context->projectEnumValue(RemoteEnumAddress, EnumTR, CaseIndex, + nullptr)) { return false; } - auto TI = Context->getTypeInfo(EnumTR); + auto TI = Context->getTypeInfo(EnumTR, nullptr); auto *RecordTI = dyn_cast(TI); assert(RecordTI != nullptr); if (static_cast(*CaseIndex) >= RecordTI->getNumCases()) { @@ -574,7 +580,7 @@ void swift_reflection_dumpInfoForTypeRef(SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef) { auto Context = ContextRef->nativeContext; auto TR = reinterpret_cast(OpaqueTypeRef); - auto TI = Context->getTypeInfo(TR); + auto TI = Context->getTypeInfo(TR, nullptr); if (TI == nullptr) { fprintf(stdout, "\n"); } else { @@ -599,7 +605,7 @@ void swift_reflection_dumpInfoForTypeRef(SwiftReflectionContextRef ContextRef, void swift_reflection_dumpInfoForMetadata(SwiftReflectionContextRef ContextRef, uintptr_t Metadata) { auto Context = ContextRef->nativeContext; - auto TI = Context->getMetadataTypeInfo(Metadata); + auto TI = Context->getMetadataTypeInfo(Metadata, nullptr); if (TI == nullptr) { fprintf(stdout, "\n"); } else { @@ -610,7 +616,7 @@ void swift_reflection_dumpInfoForMetadata(SwiftReflectionContextRef ContextRef, void swift_reflection_dumpInfoForInstance(SwiftReflectionContextRef ContextRef, uintptr_t Object) { auto Context = ContextRef->nativeContext; - auto TI = Context->getInstanceTypeInfo(Object); + auto TI = Context->getInstanceTypeInfo(Object, nullptr); if (TI == nullptr) { fprintf(stdout, "%s", "\n"); } else { diff --git a/stdlib/public/SwiftShims/LibcOverlayShims.h b/stdlib/public/SwiftShims/LibcOverlayShims.h index b4c2ba1d0a002..6395656355330 100644 --- a/stdlib/public/SwiftShims/LibcOverlayShims.h +++ b/stdlib/public/SwiftShims/LibcOverlayShims.h @@ -52,7 +52,7 @@ static inline int _swift_stdlib_fcntlPtr(int fd, int cmd, void* ptr) { #endif // Environment -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) static inline char * _Nullable * _Null_unspecified _swift_stdlib_getEnviron() { extern char **environ; return environ; diff --git a/stdlib/public/core/Array.swift b/stdlib/public/core/Array.swift index fd72700ca95b8..fe5f0da2198d7 100644 --- a/stdlib/public/core/Array.swift +++ b/stdlib/public/core/Array.swift @@ -264,7 +264,7 @@ /// let colors = ["periwinkle", "rose", "moss"] /// let moreColors: [String?] = ["ochre", "pine"] /// -/// let url = NSURL(fileURLWithPath: "names.plist") +/// let url = URL(fileURLWithPath: "names.plist") /// (colors as NSArray).write(to: url, atomically: true) /// // true /// @@ -852,14 +852,14 @@ extension Array: RangeReplaceableCollection { /// `LazyMapCollection, Int>` to a simple /// `[String]`. /// - /// func cacheImagesWithNames(names: [String]) { + /// func cacheImages(withNames names: [String]) { /// // custom image loading and caching /// } /// /// let namedHues: [String: Int] = ["Vermillion": 18, "Magenta": 302, /// "Gold": 50, "Cerise": 320] /// let colorNames = Array(namedHues.keys) - /// cacheImagesWithNames(colorNames) + /// cacheImages(withNames: colorNames) /// /// print(colorNames) /// // Prints "["Gold", "Cerise", "Magenta", "Vermillion"]" diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 5cb634ad1d360..ad74e0e699039 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -211,6 +211,7 @@ set(SWIFTLIB_SOURCES CollectionOfOne.swift DiscontiguousSlice.swift Diffing.swift + FloatingPointRandom.swift Mirror.swift PlaygroundDisplay.swift CommandLine.swift @@ -287,8 +288,10 @@ if(SWIFT_STDLIB_SIL_DEBUGGING) list(APPEND swift_stdlib_compile_flags "-Xfrontend" "-gsil") endif() -list(APPEND swift_stdlib_compile_flags "-Xllvm" "-sil-inline-generics") -list(APPEND swift_stdlib_compile_flags "-Xllvm" "-sil-partial-specialization") +if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel") + list(APPEND swift_stdlib_compile_flags "-Xllvm" "-sil-inline-generics") + list(APPEND swift_stdlib_compile_flags "-Xllvm" "-sil-partial-specialization") +endif() if(SWIFT_STDLIB_ENABLE_STDLIBCORE_EXCLUSIVITY_CHECKING) list(APPEND swift_stdlib_compile_flags "-enforce-exclusivity=checked") endif() diff --git a/stdlib/public/core/DebuggerSupport.swift b/stdlib/public/core/DebuggerSupport.swift index 0e7095aebd783..82cfedd5eb4fb 100644 --- a/stdlib/public/core/DebuggerSupport.swift +++ b/stdlib/public/core/DebuggerSupport.swift @@ -152,7 +152,14 @@ public enum _DebuggerSupport { // yes, a type can lie and say it's a class when it's not since we only // check the displayStyle - but then the type would have a custom Mirror // anyway, so there's that... - let willExpand = mirror.displayStyle != .`class` || value is CustomReflectable? + let isNonClass = mirror.displayStyle != .`class` + let isCustomReflectable: Bool + if let value = value { + isCustomReflectable = value is CustomReflectable + } else { + isCustomReflectable = true + } + let willExpand = isNonClass || isCustomReflectable let count = mirror._children.count let bullet = isRoot && (count == 0 || !willExpand) ? "" diff --git a/stdlib/public/core/FloatingPoint.swift b/stdlib/public/core/FloatingPoint.swift index a6339654ff6d9..9f931663e9923 100644 --- a/stdlib/public/core/FloatingPoint.swift +++ b/stdlib/public/core/FloatingPoint.swift @@ -1890,7 +1890,26 @@ extension BinaryFloatingPoint { /// - Parameter value: A floating-point value to be converted. @inlinable public init(_ value: Source) { - self = Self._convert(from: value).value +#if !os(macOS) && !(os(iOS) && targetEnvironment(macCatalyst)) + if #available(iOS 14.0, watchOS 7.0, tvOS 14.0, *) { + if case let value_ as Float16 = value { + self = Self(Float(value_)) + return + } + } +#endif + switch value { + case let value_ as Float: + self = Self(value_) + case let value_ as Double: + self = Self(value_) +#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + case let value_ as Float80: + self = Self(value_) +#endif + default: + self = Self._convert(from: value).value + } } /// Creates a new instance from the given value, if it can be represented @@ -2013,205 +2032,4 @@ extension BinaryFloatingPoint where Self.RawSignificand: FixedWidthInteger { guard exact else { return nil } self = value_ } - - /// Returns a random value within the specified range, using the given - /// generator as a source for randomness. - /// - /// Use this method to generate a floating-point value within a specific - /// range when you are using a custom random number generator. This example - /// creates three new values in the range `10.0 ..< 20.0`. - /// - /// for _ in 1...3 { - /// print(Double.random(in: 10.0 ..< 20.0, using: &myGenerator)) - /// } - /// // Prints "18.1900709259179" - /// // Prints "14.2286325689993" - /// // Prints "13.1485686260762" - /// - /// The `random(in:using:)` static method chooses a random value from a - /// continuous uniform distribution in `range`, and then converts that value - /// to the nearest representable value in this type. Depending on the size - /// and span of `range`, some concrete values may be represented more - /// frequently than others. - /// - /// - Note: The algorithm used to create random values may change in a future - /// version of Swift. If you're passing a generator that results in the - /// same sequence of floating-point values each time you run your program, - /// that sequence may change when your program is compiled using a - /// different version of Swift. - /// - /// - Parameters: - /// - range: The range in which to create a random value. - /// `range` must be finite and non-empty. - /// - generator: The random number generator to use when creating the - /// new random value. - /// - Returns: A random value within the bounds of `range`. - @inlinable - public static func random( - in range: Range, - using generator: inout T - ) -> Self { - _precondition( - !range.isEmpty, - "Can't get random value with an empty range" - ) - let delta = range.upperBound - range.lowerBound - // TODO: this still isn't quite right, because the computation of delta - // can overflow (e.g. if .upperBound = .maximumFiniteMagnitude and - // .lowerBound = -.upperBound); this should be re-written with an - // algorithm that handles that case correctly, but this precondition - // is an acceptable short-term fix. - _precondition( - delta.isFinite, - "There is no uniform distribution on an infinite range" - ) - let rand: Self.RawSignificand - if Self.RawSignificand.bitWidth == Self.significandBitCount + 1 { - rand = generator.next() - } else { - let significandCount = Self.significandBitCount + 1 - let maxSignificand: Self.RawSignificand = 1 << significandCount - // Rather than use .next(upperBound:), which has to work with arbitrary - // upper bounds, and therefore does extra work to avoid bias, we can take - // a shortcut because we know that maxSignificand is a power of two. - rand = generator.next() & (maxSignificand - 1) - } - let unitRandom = Self.init(rand) * (Self.ulpOfOne / 2) - let randFloat = delta * unitRandom + range.lowerBound - if randFloat == range.upperBound { - return Self.random(in: range, using: &generator) - } - return randFloat - } - - /// Returns a random value within the specified range. - /// - /// Use this method to generate a floating-point value within a specific - /// range. This example creates three new values in the range - /// `10.0 ..< 20.0`. - /// - /// for _ in 1...3 { - /// print(Double.random(in: 10.0 ..< 20.0)) - /// } - /// // Prints "18.1900709259179" - /// // Prints "14.2286325689993" - /// // Prints "13.1485686260762" - /// - /// The `random()` static method chooses a random value from a continuous - /// uniform distribution in `range`, and then converts that value to the - /// nearest representable value in this type. Depending on the size and span - /// of `range`, some concrete values may be represented more frequently than - /// others. - /// - /// This method is equivalent to calling `random(in:using:)`, passing in the - /// system's default random generator. - /// - /// - Parameter range: The range in which to create a random value. - /// `range` must be finite and non-empty. - /// - Returns: A random value within the bounds of `range`. - @inlinable - public static func random(in range: Range) -> Self { - var g = SystemRandomNumberGenerator() - return Self.random(in: range, using: &g) - } - - /// Returns a random value within the specified range, using the given - /// generator as a source for randomness. - /// - /// Use this method to generate a floating-point value within a specific - /// range when you are using a custom random number generator. This example - /// creates three new values in the range `10.0 ... 20.0`. - /// - /// for _ in 1...3 { - /// print(Double.random(in: 10.0 ... 20.0, using: &myGenerator)) - /// } - /// // Prints "18.1900709259179" - /// // Prints "14.2286325689993" - /// // Prints "13.1485686260762" - /// - /// The `random(in:using:)` static method chooses a random value from a - /// continuous uniform distribution in `range`, and then converts that value - /// to the nearest representable value in this type. Depending on the size - /// and span of `range`, some concrete values may be represented more - /// frequently than others. - /// - /// - Note: The algorithm used to create random values may change in a future - /// version of Swift. If you're passing a generator that results in the - /// same sequence of floating-point values each time you run your program, - /// that sequence may change when your program is compiled using a - /// different version of Swift. - /// - /// - Parameters: - /// - range: The range in which to create a random value. Must be finite. - /// - generator: The random number generator to use when creating the - /// new random value. - /// - Returns: A random value within the bounds of `range`. - @inlinable - public static func random( - in range: ClosedRange, - using generator: inout T - ) -> Self { - _precondition( - !range.isEmpty, - "Can't get random value with an empty range" - ) - let delta = range.upperBound - range.lowerBound - // TODO: this still isn't quite right, because the computation of delta - // can overflow (e.g. if .upperBound = .maximumFiniteMagnitude and - // .lowerBound = -.upperBound); this should be re-written with an - // algorithm that handles that case correctly, but this precondition - // is an acceptable short-term fix. - _precondition( - delta.isFinite, - "There is no uniform distribution on an infinite range" - ) - let rand: Self.RawSignificand - if Self.RawSignificand.bitWidth == Self.significandBitCount + 1 { - rand = generator.next() - let tmp: UInt8 = generator.next() & 1 - if rand == Self.RawSignificand.max && tmp == 1 { - return range.upperBound - } - } else { - let significandCount = Self.significandBitCount + 1 - let maxSignificand: Self.RawSignificand = 1 << significandCount - rand = generator.next(upperBound: maxSignificand + 1) - if rand == maxSignificand { - return range.upperBound - } - } - let unitRandom = Self.init(rand) * (Self.ulpOfOne / 2) - let randFloat = delta * unitRandom + range.lowerBound - return randFloat - } - - /// Returns a random value within the specified range. - /// - /// Use this method to generate a floating-point value within a specific - /// range. This example creates three new values in the range - /// `10.0 ... 20.0`. - /// - /// for _ in 1...3 { - /// print(Double.random(in: 10.0 ... 20.0)) - /// } - /// // Prints "18.1900709259179" - /// // Prints "14.2286325689993" - /// // Prints "13.1485686260762" - /// - /// The `random()` static method chooses a random value from a continuous - /// uniform distribution in `range`, and then converts that value to the - /// nearest representable value in this type. Depending on the size and span - /// of `range`, some concrete values may be represented more frequently than - /// others. - /// - /// This method is equivalent to calling `random(in:using:)`, passing in the - /// system's default random generator. - /// - /// - Parameter range: The range in which to create a random value. Must be finite. - /// - Returns: A random value within the bounds of `range`. - @inlinable - public static func random(in range: ClosedRange) -> Self { - var g = SystemRandomNumberGenerator() - return Self.random(in: range, using: &g) - } } diff --git a/stdlib/public/core/FloatingPointRandom.swift b/stdlib/public/core/FloatingPointRandom.swift new file mode 100644 index 0000000000000..8aeb16eb36030 --- /dev/null +++ b/stdlib/public/core/FloatingPointRandom.swift @@ -0,0 +1,215 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +extension BinaryFloatingPoint where Self.RawSignificand: FixedWidthInteger { + + /// Returns a random value within the specified range, using the given + /// generator as a source for randomness. + /// + /// Use this method to generate a floating-point value within a specific + /// range when you are using a custom random number generator. This example + /// creates three new values in the range `10.0 ..< 20.0`. + /// + /// for _ in 1...3 { + /// print(Double.random(in: 10.0 ..< 20.0, using: &myGenerator)) + /// } + /// // Prints "18.1900709259179" + /// // Prints "14.2286325689993" + /// // Prints "13.1485686260762" + /// + /// The `random(in:using:)` static method chooses a random value from a + /// continuous uniform distribution in `range`, and then converts that value + /// to the nearest representable value in this type. Depending on the size + /// and span of `range`, some concrete values may be represented more + /// frequently than others. + /// + /// - Note: The algorithm used to create random values may change in a future + /// version of Swift. If you're passing a generator that results in the + /// same sequence of floating-point values each time you run your program, + /// that sequence may change when your program is compiled using a + /// different version of Swift. + /// + /// - Parameters: + /// - range: The range in which to create a random value. + /// `range` must be finite and non-empty. + /// - generator: The random number generator to use when creating the + /// new random value. + /// - Returns: A random value within the bounds of `range`. + @inlinable + public static func random( + in range: Range, + using generator: inout T + ) -> Self { + _precondition( + !range.isEmpty, + "Can't get random value with an empty range" + ) + let delta = range.upperBound - range.lowerBound + // TODO: this still isn't quite right, because the computation of delta + // can overflow (e.g. if .upperBound = .maximumFiniteMagnitude and + // .lowerBound = -.upperBound); this should be re-written with an + // algorithm that handles that case correctly, but this precondition + // is an acceptable short-term fix. + _precondition( + delta.isFinite, + "There is no uniform distribution on an infinite range" + ) + let rand: Self.RawSignificand + if Self.RawSignificand.bitWidth == Self.significandBitCount + 1 { + rand = generator.next() + } else { + let significandCount = Self.significandBitCount + 1 + let maxSignificand: Self.RawSignificand = 1 << significandCount + // Rather than use .next(upperBound:), which has to work with arbitrary + // upper bounds, and therefore does extra work to avoid bias, we can take + // a shortcut because we know that maxSignificand is a power of two. + rand = generator.next() & (maxSignificand - 1) + } + let unitRandom = Self.init(rand) * (Self.ulpOfOne / 2) + let randFloat = delta * unitRandom + range.lowerBound + if randFloat == range.upperBound { + return Self.random(in: range, using: &generator) + } + return randFloat + } + + /// Returns a random value within the specified range. + /// + /// Use this method to generate a floating-point value within a specific + /// range. This example creates three new values in the range + /// `10.0 ..< 20.0`. + /// + /// for _ in 1...3 { + /// print(Double.random(in: 10.0 ..< 20.0)) + /// } + /// // Prints "18.1900709259179" + /// // Prints "14.2286325689993" + /// // Prints "13.1485686260762" + /// + /// The `random()` static method chooses a random value from a continuous + /// uniform distribution in `range`, and then converts that value to the + /// nearest representable value in this type. Depending on the size and span + /// of `range`, some concrete values may be represented more frequently than + /// others. + /// + /// This method is equivalent to calling `random(in:using:)`, passing in the + /// system's default random generator. + /// + /// - Parameter range: The range in which to create a random value. + /// `range` must be finite and non-empty. + /// - Returns: A random value within the bounds of `range`. + @inlinable + public static func random(in range: Range) -> Self { + var g = SystemRandomNumberGenerator() + return Self.random(in: range, using: &g) + } + + /// Returns a random value within the specified range, using the given + /// generator as a source for randomness. + /// + /// Use this method to generate a floating-point value within a specific + /// range when you are using a custom random number generator. This example + /// creates three new values in the range `10.0 ... 20.0`. + /// + /// for _ in 1...3 { + /// print(Double.random(in: 10.0 ... 20.0, using: &myGenerator)) + /// } + /// // Prints "18.1900709259179" + /// // Prints "14.2286325689993" + /// // Prints "13.1485686260762" + /// + /// The `random(in:using:)` static method chooses a random value from a + /// continuous uniform distribution in `range`, and then converts that value + /// to the nearest representable value in this type. Depending on the size + /// and span of `range`, some concrete values may be represented more + /// frequently than others. + /// + /// - Note: The algorithm used to create random values may change in a future + /// version of Swift. If you're passing a generator that results in the + /// same sequence of floating-point values each time you run your program, + /// that sequence may change when your program is compiled using a + /// different version of Swift. + /// + /// - Parameters: + /// - range: The range in which to create a random value. Must be finite. + /// - generator: The random number generator to use when creating the + /// new random value. + /// - Returns: A random value within the bounds of `range`. + @inlinable + public static func random( + in range: ClosedRange, + using generator: inout T + ) -> Self { + _precondition( + !range.isEmpty, + "Can't get random value with an empty range" + ) + let delta = range.upperBound - range.lowerBound + // TODO: this still isn't quite right, because the computation of delta + // can overflow (e.g. if .upperBound = .maximumFiniteMagnitude and + // .lowerBound = -.upperBound); this should be re-written with an + // algorithm that handles that case correctly, but this precondition + // is an acceptable short-term fix. + _precondition( + delta.isFinite, + "There is no uniform distribution on an infinite range" + ) + let rand: Self.RawSignificand + if Self.RawSignificand.bitWidth == Self.significandBitCount + 1 { + rand = generator.next() + let tmp: UInt8 = generator.next() & 1 + if rand == Self.RawSignificand.max && tmp == 1 { + return range.upperBound + } + } else { + let significandCount = Self.significandBitCount + 1 + let maxSignificand: Self.RawSignificand = 1 << significandCount + rand = generator.next(upperBound: maxSignificand + 1) + if rand == maxSignificand { + return range.upperBound + } + } + let unitRandom = Self.init(rand) * (Self.ulpOfOne / 2) + let randFloat = delta * unitRandom + range.lowerBound + return randFloat + } + + /// Returns a random value within the specified range. + /// + /// Use this method to generate a floating-point value within a specific + /// range. This example creates three new values in the range + /// `10.0 ... 20.0`. + /// + /// for _ in 1...3 { + /// print(Double.random(in: 10.0 ... 20.0)) + /// } + /// // Prints "18.1900709259179" + /// // Prints "14.2286325689993" + /// // Prints "13.1485686260762" + /// + /// The `random()` static method chooses a random value from a continuous + /// uniform distribution in `range`, and then converts that value to the + /// nearest representable value in this type. Depending on the size and span + /// of `range`, some concrete values may be represented more frequently than + /// others. + /// + /// This method is equivalent to calling `random(in:using:)`, passing in the + /// system's default random generator. + /// + /// - Parameter range: The range in which to create a random value. Must be finite. + /// - Returns: A random value within the bounds of `range`. + @inlinable + public static func random(in range: ClosedRange) -> Self { + var g = SystemRandomNumberGenerator() + return Self.random(in: range, using: &g) + } +} diff --git a/stdlib/public/core/GroupInfo.json b/stdlib/public/core/GroupInfo.json index 289703802610a..8b4fbcaae345f 100644 --- a/stdlib/public/core/GroupInfo.json +++ b/stdlib/public/core/GroupInfo.json @@ -169,7 +169,8 @@ "Floating": [ "FloatingPoint.swift", "FloatingPointParsing.swift", - "FloatingPointTypes.swift"], + "FloatingPointTypes.swift", + "FloatingPointRandom.swift"], "Vector": [ "SIMDVector.swift", "SIMDVectorTypes.swift"]} diff --git a/stdlib/public/core/Integers.swift b/stdlib/public/core/Integers.swift index 7c637c6fe7bc9..1b7ba775989ff 100644 --- a/stdlib/public/core/Integers.swift +++ b/stdlib/public/core/Integers.swift @@ -1211,7 +1211,7 @@ public protocol BinaryInteger : /// /// - Parameter rhs: The value to divide this value by. /// - Returns: A tuple containing the quotient and remainder of this value - /// divided by `rhs`. The remainder has the same sign as `rhs`. + /// divided by `rhs`. The remainder has the same sign as `lhs`. func quotientAndRemainder(dividingBy rhs: Self) -> (quotient: Self, remainder: Self) diff --git a/stdlib/public/core/OutputStream.swift b/stdlib/public/core/OutputStream.swift index 7faafbaa27c98..52101107dde33 100644 --- a/stdlib/public/core/OutputStream.swift +++ b/stdlib/public/core/OutputStream.swift @@ -225,10 +225,7 @@ public protocol LosslessStringConvertible: CustomStringConvertible { /// /// let p = Point(x: 21, y: 30) /// print(String(reflecting: p)) -/// // Prints "p: Point = { -/// // x = 21 -/// // y = 30 -/// // }" +/// // Prints "Point(x: 21, y: 30)" /// /// After adding `CustomDebugStringConvertible` conformance by implementing the /// `debugDescription` property, `Point` provides its own custom debugging @@ -236,12 +233,12 @@ public protocol LosslessStringConvertible: CustomStringConvertible { /// /// extension Point: CustomDebugStringConvertible { /// var debugDescription: String { -/// return "Point(x: \(x), y: \(y))" +/// return "(\(x), \(y))" /// } /// } /// /// print(String(reflecting: p)) -/// // Prints "Point(x: 21, y: 30)" +/// // Prints "(21, 30)" public protocol CustomDebugStringConvertible { /// A textual representation of this instance, suitable for debugging. /// diff --git a/stdlib/public/core/StringObject.swift b/stdlib/public/core/StringObject.swift index 30f3989df4699..ebc2ce510be99 100644 --- a/stdlib/public/core/StringObject.swift +++ b/stdlib/public/core/StringObject.swift @@ -293,7 +293,7 @@ extension _StringObject.CountAndFlags { on arm64. */ extension _StringObject.Nibbles { - // The canonical empty sting is an empty small string + // The canonical empty string is an empty small string @inlinable @inline(__always) internal static var emptyString: UInt64 { return _StringObject.Nibbles.small(isASCII: true) diff --git a/stdlib/public/core/UnicodeHelpers.swift b/stdlib/public/core/UnicodeHelpers.swift index 64e7ea189fd9f..1e538f9349d4b 100644 --- a/stdlib/public/core/UnicodeHelpers.swift +++ b/stdlib/public/core/UnicodeHelpers.swift @@ -397,12 +397,13 @@ extension _StringGuts { } // TODO(String performance): Stack buffer if small enough - var cus = Array(repeating: 0, count: count) - cus.withUnsafeMutableBufferPointer { + let cus = Array(unsafeUninitializedCapacity: count) { + buffer, initializedCapacity in _cocoaStringCopyCharacters( from: self._object.cocoaObject, range: start..getKind() == MetadataKind::Class + && targetType->getKind() == MetadataKind::Class) { + auto srcClassType = cast(srcType); + auto srcDescr = srcClassType->getDescription(); + if (srcDescr == &NOMINAL_TYPE_DESCR_SYM(s12__SwiftValueC)) { + auto srcValue = reinterpret_cast(&object); + void *result; + auto destLocation = reinterpret_cast(&result); + if (swift_unboxFromSwiftValueWithType(srcValue, destLocation, targetType)) { + swift_unknownObjectRelease(const_cast(object)); + return result; + } + } + } +#endif + return nullptr; } @@ -3262,3 +3289,30 @@ HeapObject *_swift_bridgeToObjectiveCUsingProtocolIfPossible( #define OVERRIDE_CASTING COMPATIBILITY_OVERRIDE #include "CompatibilityOverride.def" +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX + +// A way for the new implementation to call the old one, so we +// can support switching between the two until the new one is +// fully settled. + +// XXX TODO XXX Once the new implementation is stable, remove the following, +// swift_dynamicCastImpl above, and all the other code above that only exists to +// support that. (Don't forget _dynamicCastToExistential!!) This file should +// be only ~1400 lines when you're done. + +extern "C" { + bool swift_dynamicCast_OLD(OpaqueValue *destLocation, + OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType, + DynamicCastFlags flags) + { + return swift_dynamicCastImpl(destLocation, srcValue, srcType, destType, flags); + } +} + +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX diff --git a/stdlib/public/runtime/CompatibilityOverride.cpp b/stdlib/public/runtime/CompatibilityOverride.cpp index 8c5b3f747e4fd..000ff0dff2600 100644 --- a/stdlib/public/runtime/CompatibilityOverride.cpp +++ b/stdlib/public/runtime/CompatibilityOverride.cpp @@ -14,6 +14,8 @@ // //===----------------------------------------------------------------------===// +#ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES + #include "CompatibilityOverride.h" #include "ImageInspection.h" @@ -49,12 +51,7 @@ static_assert(std::is_pod::value, static OverrideSection *getOverrideSectionPtr() { static OverrideSection *OverrideSectionPtr; static swift_once_t Predicate; - // WebAssembly: hack -#ifdef __wasm__ - swift_once_real(&Predicate, [](void *) { -#else swift_once(&Predicate, [](void *) { -#endif size_t Size; OverrideSectionPtr = static_cast( lookupSection("__DATA", "__swift53_hooks", &Size)); @@ -73,3 +70,5 @@ static OverrideSection *getOverrideSectionPtr() { return Section->name; \ } #include "CompatibilityOverride.def" + +#endif // #ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES diff --git a/stdlib/public/runtime/CompatibilityOverride.def b/stdlib/public/runtime/CompatibilityOverride.def index 06ee84685dc35..1489ee07e1eeb 100644 --- a/stdlib/public/runtime/CompatibilityOverride.def +++ b/stdlib/public/runtime/CompatibilityOverride.def @@ -40,6 +40,7 @@ #ifdef OVERRIDE # define OVERRIDE_METADATALOOKUP OVERRIDE # define OVERRIDE_CASTING OVERRIDE +# define OVERRIDE_DYNAMICCASTING OVERRIDE # define OVERRIDE_OBJC OVERRIDE # define OVERRIDE_FOREIGN OVERRIDE # define OVERRIDE_PROTOCOLCONFORMANCE OVERRIDE @@ -52,6 +53,9 @@ # ifndef OVERRIDE_CASTING # define OVERRIDE_CASTING(...) # endif +# ifndef OVERRIDE_DYNAMICCASTING +# define OVERRIDE_DYNAMICCASTING(...) +# endif # ifndef OVERRIDE_OBJC # define OVERRIDE_OBJC(...) # endif @@ -69,12 +73,12 @@ # endif #endif -OVERRIDE_CASTING(dynamicCast, bool, , , swift::, - (OpaqueValue *dest, OpaqueValue *src, - const Metadata *srcType, - const Metadata *targetType, - DynamicCastFlags flags), - (dest, src, srcType, targetType, flags)) +OVERRIDE_DYNAMICCASTING(dynamicCast, bool, , , swift::, + (OpaqueValue *dest, OpaqueValue *src, + const Metadata *srcType, + const Metadata *targetType, + DynamicCastFlags flags), + (dest, src, srcType, targetType, flags)) OVERRIDE_CASTING(dynamicCastClass, const void *, , , swift::, @@ -134,18 +138,11 @@ OVERRIDE_PROTOCOLCONFORMANCE(conformsToProtocol, const WitnessTable *, , , swift const ProtocolDescriptor *protocol), (type, protocol)) -OVERRIDE_PROTOCOLCONFORMANCE(conformsToSwiftProtocol, - const ProtocolConformanceDescriptor *, , , swift::, - (const Metadata * const type, - const ProtocolDescriptor *protocol, - StringRef moduleName), - (type, protocol, moduleName)) - OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , , swift::, (const void *pattern, const void *arguments), (pattern, arguments)) -OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeInfo, , SWIFT_CC(swift), swift::, +OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeLookupErrorOr, , SWIFT_CC(swift), swift::, (MetadataRequest request, Demangler &demangler, Demangle::NodePointer node, @@ -153,7 +150,7 @@ OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeInfo, , SWIFT_CC(swift), swift SubstGenericParameterFn substGenericParam, SubstDependentWitnessTableFn substWitnessTable), (request, demangler, node, arguments, substGenericParam, substWitnessTable)) -OVERRIDE_METADATALOOKUP(getTypeByMangledName, TypeInfo, , SWIFT_CC(swift), swift::, +OVERRIDE_METADATALOOKUP(getTypeByMangledName, TypeLookupErrorOr, , SWIFT_CC(swift), swift::, (MetadataRequest request, StringRef typeName, const void * const *arguments, @@ -219,6 +216,7 @@ OVERRIDE_FOREIGN(dynamicCastForeignClassUnconditional, const void *, , , swift:: #undef OVERRIDE #undef OVERRIDE_METADATALOOKUP #undef OVERRIDE_CASTING +#undef OVERRIDE_DYNAMICCASTING #undef OVERRIDE_OBJC #undef OVERRIDE_FOREIGN #undef OVERRIDE_PROTOCOLCONFORMANCE diff --git a/stdlib/public/runtime/CompatibilityOverride.h b/stdlib/public/runtime/CompatibilityOverride.h index ad79a27273d51..b3b39b2f67c7a 100644 --- a/stdlib/public/runtime/CompatibilityOverride.h +++ b/stdlib/public/runtime/CompatibilityOverride.h @@ -24,6 +24,15 @@ namespace swift { +#ifdef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES + +#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + attrs ccAttrs ret namespace swift_ ## name typedArgs { \ + return swift_ ## name ## Impl namedArgs; \ + } + +#else // #ifdef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES + #define COMPATIBILITY_UNPAREN(...) __VA_ARGS__ #define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ @@ -39,7 +48,7 @@ namespace swift { Override_ ## name getOverride_ ## name(); #include "CompatibilityOverride.def" -#ifndef __wasm__ + /// Used to define an override point. The override point #defines the appropriate /// OVERRIDE macro from CompatibilityOverride.def to this macro, then includes /// the file to generate the override points. The original implementation of the @@ -55,21 +64,9 @@ namespace swift { return Override(COMPATIBILITY_UNPAREN namedArgs, swift_ ## name ## Impl); \ return swift_ ## name ## Impl namedArgs; \ } -#else -// WebAssembly: hack: change to swift_once_real -#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ - attrs ccAttrs ret namespace swift_ ## name typedArgs { \ - static Override_ ## name Override; \ - static swift_once_t Predicate; \ - swift_once_real(&Predicate, [](void *) { \ - Override = getOverride_ ## name(); \ - }, nullptr); \ - if (Override != nullptr) \ - return Override(COMPATIBILITY_UNPAREN namedArgs, swift_ ## name ## Impl); \ - return swift_ ## name ## Impl namedArgs; \ - } -#endif + +#endif // #else SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES } /* end namespace swift */ -#endif /* COMPATIBILITY_OVERRIDE_H */ +#endif /* COMPATIBILITY_OVERRIDE_H */ \ No newline at end of file diff --git a/stdlib/public/runtime/DynamicCast.cpp b/stdlib/public/runtime/DynamicCast.cpp new file mode 100644 index 0000000000000..fa628e296fb2a --- /dev/null +++ b/stdlib/public/runtime/DynamicCast.cpp @@ -0,0 +1,2197 @@ +//===--- DynamicCast.cpp - Swift Language Dynamic Casting Support ---------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Implementations of the dynamic cast runtime functions. +// +//===----------------------------------------------------------------------===// + +#include "CompatibilityOverride.h" +#include "ErrorObject.h" +#include "Private.h" +#include "SwiftHashableSupport.h" +#include "swift/ABI/MetadataValues.h" +#include "swift/Basic/Lazy.h" +#include "swift/Runtime/Casting.h" +#include "swift/Runtime/Config.h" +#include "swift/Runtime/ExistentialContainer.h" +#include "swift/Runtime/HeapObject.h" +#if SWIFT_OBJC_INTEROP +#include "swift/Runtime/ObjCBridge.h" +#include "SwiftObject.h" +#include "SwiftValue.h" +#endif + +using namespace swift; +using namespace hashable_support; + +// +// The top-level driver code directly handles the most general cases +// (identity casts, _ObjectiveCBridgeable, _SwiftValue boxing) and +// recursively unwraps source and/or destination as appropriate. +// It calls "tryCastToXyz" functions to perform tailored operations +// for a particular destination type. +// +// For each kind of destination, there is a "tryCastToXyz" that +// accepts a source value and attempts to fit it into a destination +// storage location. This function should assume that: +// * The source and destination types are _not_ identical. +// * The destination is of the expected type. +// * The source is already fully unwrapped. If the source is an +// Existential or Optional that you cannot handle directly, do _not_ +// try to unwrap it. Just return failure and you will get called +// again with the unwrapped source. +// +// Each such function accepts the following arguments: +// * Destination location and type +// * Source value address and type +// * References to the types that will be used to report failure. +// The function can update these with specific failing types +// to improve the reported failure. +// * Bool indicating whether the compiler has asked us to "take" the +// value instead of copying. +// * Bool indicating whether it's okay to do type checks lazily on later +// access (this is permitted only for unconditional casts that will +// abort the program on failure anyway). +// +// The return value is one of the following: +// * Failure. In this case, the tryCastFunction should do nothing; your +// caller will either try another strategy or report the failure and +// do any necessary cleanup. +// * Success via "copy". You successfully copied the source value. +// * Success via "take". If "take" was requested and you can do so cheaply, +// perform the take and return SuccessViaTake. If "take" is not cheap, you +// should copy and return SuccessViaCopy. Top-level code will detect this +// and take care of destroying the source for you. +// +enum class DynamicCastResult { + Failure, /// The cast attempt "failed" (did nothing). + SuccessViaCopy, /// Cast succeeded, source is still valid. + SuccessViaTake, /// Cast succeeded, source is invalid +}; +static bool isSuccess(DynamicCastResult result) { + return result != DynamicCastResult::Failure; +} + +// All of our `tryCastXyz` functions have the following signature. +typedef DynamicCastResult (tryCastFunctionType)( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks +); + +// Forward-declare the main top-level `tryCast()` function +static tryCastFunctionType tryCast; + +/// Nominal type descriptor for Swift.AnyHashable +extern "C" const StructDescriptor STRUCT_TYPE_DESCR_SYM(s11AnyHashable); + +/// Nominal type descriptor for Swift.__SwiftValue +//extern "C" const StructDescriptor STRUCT_TYPE_DESCR_SYM(s12__SwiftValue); + +/// Nominal type descriptor for Swift.Array. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(Sa); + +/// Nominal type descriptor for Swift.Dictionary. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(SD); + +/// Nominal type descriptor for Swift.Set. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(Sh); + +/// Nominal type descriptor for Swift.String. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(SS); + +static HeapObject * getNonNullSrcObject(OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType) { + auto object = *reinterpret_cast(srcValue); + if (LLVM_LIKELY(object != nullptr)) { + return object; + } + + std::string srcTypeName = nameForMetadata(srcType); + std::string destTypeName = nameForMetadata(destType); + swift::fatalError(/* flags = */ 0, + "Found unexpected null pointer value" + " while trying to cast value of type '%s' (%p)" + " to '%s' (%p)\n", + srcTypeName.c_str(), srcType, + destTypeName.c_str(), destType); +} + +/******************************************************************************/ +/******************************* Bridge Helpers *******************************/ +/******************************************************************************/ + +#define _bridgeAnythingToObjectiveC \ + MANGLE_SYM(s27_bridgeAnythingToObjectiveCyyXlxlF) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API +HeapObject *_bridgeAnythingToObjectiveC( + OpaqueValue *src, const Metadata *srcType); + +#if SWIFT_OBJC_INTEROP +SWIFT_RUNTIME_EXPORT +id swift_dynamicCastMetatypeToObjectConditional(const Metadata *metatype); +#endif + +// protocol _ObjectiveCBridgeable { +struct _ObjectiveCBridgeableWitnessTable : WitnessTable { + static_assert(WitnessTableFirstRequirementOffset == 1, + "Witness table layout changed"); + + // associatedtype _ObjectiveCType : class + void *_ObjectiveCType; + + // func _bridgeToObjectiveC() -> _ObjectiveCType + SWIFT_CC(swift) + HeapObject *(*bridgeToObjectiveC)( + SWIFT_CONTEXT OpaqueValue *self, const Metadata *Self, + const _ObjectiveCBridgeableWitnessTable *witnessTable); + + // class func _forceBridgeFromObjectiveC(x: _ObjectiveCType, + // inout result: Self?) + SWIFT_CC(swift) + void (*forceBridgeFromObjectiveC)( + HeapObject *sourceValue, + OpaqueValue *result, + SWIFT_CONTEXT const Metadata *self, + const Metadata *selfType, + const _ObjectiveCBridgeableWitnessTable *witnessTable); + + // class func _conditionallyBridgeFromObjectiveC(x: _ObjectiveCType, + // inout result: Self?) -> Bool + SWIFT_CC(swift) + bool (*conditionallyBridgeFromObjectiveC)( + HeapObject *sourceValue, + OpaqueValue *result, + SWIFT_CONTEXT const Metadata *self, + const Metadata *selfType, + const _ObjectiveCBridgeableWitnessTable *witnessTable); +}; +// } + +extern "C" const ProtocolDescriptor +PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable); + +static const _ObjectiveCBridgeableWitnessTable * +findBridgeWitness(const Metadata *T) { + static const auto bridgeableProtocol + = &PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable); + auto w = swift_conformsToProtocol(T, bridgeableProtocol); + return reinterpret_cast(w); +} + +/// Retrieve the bridged Objective-C type for the given type that +/// conforms to \c _ObjectiveCBridgeable. +MetadataResponse +_getBridgedObjectiveCType( + MetadataRequest request, + const Metadata *conformingType, + const _ObjectiveCBridgeableWitnessTable *wtable) +{ + // FIXME: Can we directly reference the descriptor somehow? + const ProtocolConformanceDescriptor *conformance = wtable->getDescription(); + const ProtocolDescriptor *protocol = conformance->getProtocol(); + auto assocTypeRequirement = protocol->getRequirements().begin(); + assert(assocTypeRequirement->Flags.getKind() == + ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction); + auto mutableWTable = (WitnessTable *)wtable; + return swift_getAssociatedTypeWitness( + request, mutableWTable, conformingType, + protocol->getRequirementBaseDescriptor(), + assocTypeRequirement); +} + +/// Dynamic cast from a class type to a value type that conforms to the +/// _ObjectiveCBridgeable, first by dynamic casting the object to the +/// class to which the value type is bridged, and then bridging +/// from that object to the value type via the witness table. +/// +/// Caveat: Despite the name, this is also used to bridge pure Swift +/// classes to Swift value types even when Obj-C is not being used. + +static DynamicCastResult +_tryCastFromClassToObjCBridgeable( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, void *srcObject, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks, + const _ObjectiveCBridgeableWitnessTable *destBridgeWitness, + const Metadata *targetBridgeClass) +{ + + // 2. Allocate a T? to receive the bridge result. + + // The extra byte is for the tag. + auto targetSize = destType->getValueWitnesses()->getSize() + 1; + auto targetAlignMask = destType->getValueWitnesses()->getAlignmentMask(); + + // Object that frees a buffer when it goes out of scope. + struct FreeBuffer { + void *Buffer = nullptr; + size_t size, alignMask; + FreeBuffer(size_t size, size_t alignMask) : + size(size), alignMask(alignMask) {} + + ~FreeBuffer() { + if (Buffer) + swift_slowDealloc(Buffer, size, alignMask); + } + } freeBuffer{targetSize, targetAlignMask}; + + // The extra byte is for the tag on the T? + const std::size_t inlineValueSize = 3 * sizeof(void*); + alignas(std::max_align_t) char inlineBuffer[inlineValueSize + 1]; + void *optDestBuffer; + if (destType->getValueWitnesses()->getStride() <= inlineValueSize) { + // Use the inline buffer. + optDestBuffer = inlineBuffer; + } else { + // Allocate a buffer. + optDestBuffer = swift_slowAlloc(targetSize, targetAlignMask); + freeBuffer.Buffer = optDestBuffer; + } + + // Initialize the buffer as an empty optional. + destType->vw_storeEnumTagSinglePayload((OpaqueValue *)optDestBuffer, + 1, 1); + + // 3. Bridge into the T? (Effectively a copy operation.) + bool success; + if (mayDeferChecks) { + destBridgeWitness->forceBridgeFromObjectiveC( + (HeapObject *)srcObject, (OpaqueValue *)optDestBuffer, + destType, destType, destBridgeWitness); + success = true; + } else { + success = destBridgeWitness->conditionallyBridgeFromObjectiveC( + (HeapObject *)srcObject, (OpaqueValue *)optDestBuffer, + destType, destType, destBridgeWitness); + } + + // If we succeeded, then take the value from the temp buffer. + if (success) { + destType->vw_initializeWithTake(destLocation, (OpaqueValue *)optDestBuffer); + // Bridge above is effectively a copy, so overall we're a copy. + return DynamicCastResult::SuccessViaCopy; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastFromClassToObjCBridgeable( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + // We need the _ObjectiveCBridgeable conformance for the target + auto destBridgeWitness = findBridgeWitness(destType); + if (destBridgeWitness == nullptr) { + return DynamicCastResult::Failure; + } + + // 1. Sanity check whether the source object can cast to the + // type expected by the target. + + auto targetBridgedClass = + _getBridgedObjectiveCType(MetadataState::Complete, destType, + destBridgeWitness).Value; + void *srcObject = getNonNullSrcObject(srcValue, srcType, destType); + if (nullptr == swift_dynamicCastUnknownClass(srcObject, targetBridgedClass)) { + destFailureType = targetBridgedClass; + return DynamicCastResult::Failure; + } + + return _tryCastFromClassToObjCBridgeable( + destLocation, destType, + srcValue, srcType, srcObject, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks, + destBridgeWitness, targetBridgedClass); +} + +/// Dynamic cast from a value type that conforms to the +/// _ObjectiveCBridgeable protocol to a class type, first by bridging +/// the value to its Objective-C object representation and then by +/// dynamic casting that object to the resulting target type. +/// +/// Caveat: Despite the name, this is also used to bridge Swift value types +/// to Swift classes even when Obj-C is not being used. +static DynamicCastResult +tryCastFromObjCBridgeableToClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + auto srcBridgeWitness = findBridgeWitness(srcType); + if (srcBridgeWitness == nullptr) { + return DynamicCastResult::Failure; + } + + // Bridge the source value to an object. + auto srcBridgedObject = + srcBridgeWitness->bridgeToObjectiveC(srcValue, srcType, srcBridgeWitness); + + // Dynamic cast the object to the resulting class type. + if (auto cast = swift_dynamicCastUnknownClass(srcBridgedObject, destType)) { + *reinterpret_cast(destLocation) = cast; + return DynamicCastResult::SuccessViaCopy; + } else { + // We don't need the object anymore. + swift_unknownObjectRelease(srcBridgedObject); + return DynamicCastResult::Failure; + } +} + +/******************************************************************************/ +/****************************** SwiftValue Boxing *****************************/ +/******************************************************************************/ + +#if !SWIFT_OBJC_INTEROP // __SwiftValue is a native class +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool swift_unboxFromSwiftValueWithType(OpaqueValue *source, + OpaqueValue *result, + const Metadata *destinationType); + +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool swift_swiftValueConformsTo(const Metadata *, const Metadata *); +#endif + +#if SWIFT_OBJC_INTEROP +// Try unwrapping a source holding an Obj-C SwiftValue container and +// recursively casting the contents. +static DynamicCastResult +tryCastUnwrappingObjCSwiftValueSource( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + id srcObject; + memcpy(&srcObject, srcValue, sizeof(id)); + auto srcSwiftValue = getAsSwiftValue(srcObject); + + if (srcSwiftValue == nullptr) { + return DynamicCastResult::Failure; + } + + const Metadata *srcInnerType; + const OpaqueValue *srcInnerValue; + std::tie(srcInnerType, srcInnerValue) + = getValueFromSwiftValue(srcSwiftValue); + // Note: We never `take` the contents from a SwiftValue box as + // it might have other references. Instead, let our caller + // destroy the reference if necessary. + return tryCast( + destLocation, destType, + const_cast(srcInnerValue), srcInnerType, + destFailureType, srcFailureType, + /*takeOnSuccess=*/ false, mayDeferChecks); +} +#endif + +/******************************************************************************/ +/****************************** Class Destination *****************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToSwiftClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Class); + + auto destClassType = cast(destType); + switch (srcType->getKind()) { + case MetadataKind::Class: // Swift class => Swift class + case MetadataKind::ObjCClassWrapper: { // Obj-C class => Swift class + void *object = getNonNullSrcObject(srcValue, srcType, destType); + if (auto t = swift_dynamicCastClass(object, destClassType)) { + auto castObject = const_cast(t); + *(reinterpret_cast(destLocation)) = castObject; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + swift_unknownObjectRetain(castObject); + return DynamicCastResult::SuccessViaCopy; + } + } else { + srcFailureType = srcType; + destFailureType = destType; + return DynamicCastResult::Failure; + } + } + + case MetadataKind::ForeignClass: // CF class => Swift class + // Top-level code will "unwrap" to an Obj-C class and try again. + return DynamicCastResult::Failure; + + default: + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastToObjectiveCClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::ObjCClassWrapper); +#if SWIFT_OBJC_INTEROP + auto destObjCType = cast(destType); + + switch (srcType->getKind()) { + case MetadataKind::Class: // Swift class => Obj-C class + case MetadataKind::ObjCClassWrapper: // Obj-C class => Obj-C class + case MetadataKind::ForeignClass: { // CF class => Obj-C class + auto srcObject = getNonNullSrcObject(srcValue, srcType, destType); + auto destObjCClass = destObjCType->Class; + if (auto resultObject + = swift_dynamicCastObjCClass(srcObject, destObjCClass)) { + *reinterpret_cast(destLocation) = resultObject; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + objc_retain((id)const_cast(resultObject)); + return DynamicCastResult::SuccessViaCopy; + } + } + break; + } + + default: + break; + } +#endif + + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToForeignClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ +#if SWIFT_OBJC_INTEROP + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::ForeignClass); + auto destClassType = cast(destType); + + switch (srcType->getKind()) { + case MetadataKind::Class: // Swift class => CF class + case MetadataKind::ObjCClassWrapper: // Obj-C class => CF class + case MetadataKind::ForeignClass: { // CF class => CF class + auto srcObject = getNonNullSrcObject(srcValue, srcType, destType); + if (auto resultObject + = swift_dynamicCastForeignClass(srcObject, destClassType)) { + *reinterpret_cast(destLocation) = resultObject; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + objc_retain((id)const_cast(resultObject)); + return DynamicCastResult::SuccessViaCopy; + } + } + break; + } + default: + break; + } +#endif + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/***************************** Enum Destination *******************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToEnum( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + // Note: Optional is handled elsewhere + assert(destType->getKind() == MetadataKind::Enum); + + // Enum has no special cast support at present. + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/**************************** Struct Destination ******************************/ +/******************************************************************************/ + +// internal func _arrayDownCastIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer>) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +void _swift_arrayDownCastIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType); + +// internal func _arrayDownCastConditionalIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer> +// ) -> Bool +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool _swift_arrayDownCastConditionalIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType); + +// internal func _setDownCastIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer>) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +void _swift_setDownCastIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType, + const void *sourceValueHashable, + const void *targetValueHashable); + +// internal func _setDownCastConditionalIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer> +// ) -> Bool +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool _swift_setDownCastConditionalIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType, + const void *sourceValueHashable, + const void *targetValueHashable); + +// internal func _dictionaryDownCastIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer>) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +void _swift_dictionaryDownCastIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceKeyType, + const Metadata *sourceValueType, + const Metadata *targetKeyType, + const Metadata *targetValueType, + const void *sourceKeyHashable, + const void *targetKeyHashable); + +// internal func _dictionaryDownCastConditionalIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer> +// ) -> Bool +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool _swift_dictionaryDownCastConditionalIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceKeyType, + const Metadata *sourceValueType, + const Metadata *targetKeyType, + const Metadata *targetValueType, + const void *sourceKeyHashable, + const void *targetKeyHashable); + +#if SWIFT_OBJC_INTEROP +// Helper to memoize bridging conformance data for a particular +// Swift struct type. This is used to speed up the most common +// ObjC->Swift bridging conversions by eliminating repeeated +// protocol conformance lookups. + +// Currently used only for String, which may be the only +// type used often enough to justify the extra static memory. +struct ObjCBridgeMemo { +#if !NDEBUG + // Used in assert build to verify that we always get called with + // the same destType + const Metadata *destType; +#endif + const _ObjectiveCBridgeableWitnessTable *destBridgeWitness; + const Metadata *targetBridgedType; + Class targetBridgedObjCClass; + swift_once_t fetchWitnessOnce; + + DynamicCastResult tryBridge( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) + { + struct SetupData { + const Metadata *destType; + struct ObjCBridgeMemo *memo; + } setupData { destType, this }; + + swift_once(&fetchWitnessOnce, + [](void *data) { + struct SetupData *setupData = (struct SetupData *)data; + struct ObjCBridgeMemo *memo = setupData->memo; +#if !NDEBUG + memo->destType = setupData->destType; +#endif + memo->destBridgeWitness = findBridgeWitness(setupData->destType); + if (memo->destBridgeWitness == nullptr) { + memo->targetBridgedType = nullptr; + memo->targetBridgedObjCClass = nullptr; + } else { + memo->targetBridgedType = _getBridgedObjectiveCType( + MetadataState::Complete, setupData->destType, memo->destBridgeWitness).Value; + assert(memo->targetBridgedType->getKind() == MetadataKind::ObjCClassWrapper); + memo->targetBridgedObjCClass = memo->targetBridgedType->getObjCClassObject(); + assert(memo->targetBridgedObjCClass != nullptr); + } + }, (void *)&setupData); + + // Check that this always gets called with the same destType. + assert((destType == this->destType) && "ObjC casting memo used inconsistently"); + + // !! If bridging is not usable, stop here. + if (targetBridgedObjCClass == nullptr) { + return DynamicCastResult::Failure; + } + // Use the dynamic ISA type of the object always (Note that this + // also implicitly gives us the ObjC type for a CF object.) + void *srcObject = getNonNullSrcObject(srcValue, srcType, destType); + Class srcObjCType = object_getClass((id)srcObject); + // Fail if the ObjC object is not a subclass of the bridge class. + while (srcObjCType != targetBridgedObjCClass) { + srcObjCType = class_getSuperclass(srcObjCType); + if (srcObjCType == nullptr) { + return DynamicCastResult::Failure; + } + } + // The ObjC object is an acceptable type, so call the bridge function... + return _tryCastFromClassToObjCBridgeable( + destLocation, destType, srcValue, srcType, srcObject, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks, + destBridgeWitness, targetBridgedType); + } +}; +#endif + +static DynamicCastResult +tryCastToAnyHashable( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &STRUCT_TYPE_DESCR_SYM(s11AnyHashable)); + + auto hashableConformance = reinterpret_cast( + swift_conformsToProtocol(srcType, &HashableProtocolDescriptor)); + if (hashableConformance) { + _swift_convertToAnyHashableIndirect(srcValue, destLocation, + srcType, hashableConformance); + return DynamicCastResult::SuccessViaCopy; + } else { + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastToArray( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(Sa)); + + switch (srcType->getKind()) { + case MetadataKind::Struct: { // Struct -> Array + const auto srcStructType = cast(srcType); + if (srcStructType->Description == &NOMINAL_TYPE_DESCR_SYM(Sa)) { // Array -> Array + auto sourceArgs = srcType->getGenericArgs(); + auto destArgs = destType->getGenericArgs(); + if (mayDeferChecks) { + _swift_arrayDownCastIndirect( + srcValue, destLocation, sourceArgs[0], destArgs[0]); + return DynamicCastResult::SuccessViaCopy; + } else { + auto result = _swift_arrayDownCastConditionalIndirect( + srcValue, destLocation, sourceArgs[0], destArgs[0]); + if (result) { + return DynamicCastResult::SuccessViaCopy; + } + } + } + break; + } + + default: + break; + } + + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToDictionary( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(SD)); + + switch (srcType->getKind()) { + case MetadataKind::Struct: { // Struct -> Dictionary + const auto srcStructType = cast(srcType); + if (srcStructType->Description == &NOMINAL_TYPE_DESCR_SYM(SD)) { // Dictionary -> Dictionary + auto sourceArgs = srcType->getGenericArgs(); + auto destArgs = destType->getGenericArgs(); + if (mayDeferChecks) { + _swift_dictionaryDownCastIndirect( + srcValue, destLocation, sourceArgs[0], sourceArgs[1], + destArgs[0], destArgs[1], sourceArgs[2], destArgs[2]); + return DynamicCastResult::SuccessViaCopy; + } else { + auto result = _swift_dictionaryDownCastConditionalIndirect( + srcValue, destLocation, sourceArgs[0], sourceArgs[1], + destArgs[0], destArgs[1], sourceArgs[2], destArgs[2]); + if (result) { + return DynamicCastResult::SuccessViaCopy; + } + } + } + break; + } + + default: + break; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToSet( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(Sh)); + + switch (srcType->getKind()) { + + case MetadataKind::Struct: { // Struct -> Set + const auto srcStructType = cast(srcType); + if (srcStructType->Description == &NOMINAL_TYPE_DESCR_SYM(Sh)) { // Set -> Set + auto sourceArgs = srcType->getGenericArgs(); + auto destArgs = destType->getGenericArgs(); + if (mayDeferChecks) { + _swift_setDownCastIndirect(srcValue, destLocation, + sourceArgs[0], destArgs[0], sourceArgs[1], destArgs[1]); + return DynamicCastResult::SuccessViaCopy; + } else { + auto result = _swift_setDownCastConditionalIndirect( + srcValue, destLocation, + sourceArgs[0], destArgs[0], + sourceArgs[1], destArgs[1]); + if (result) { + return DynamicCastResult::SuccessViaCopy; + } + } + } + break; + } + + default: + break; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToString( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(SS)); + + switch (srcType->getKind()) { + case MetadataKind::ForeignClass: // CF -> String + case MetadataKind::ObjCClassWrapper: { // Obj-C -> String +#if SWIFT_OBJC_INTEROP + static ObjCBridgeMemo memo; + return memo.tryBridge( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks); +#endif + } + default: + return DynamicCastResult::Failure; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToStruct( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + + // There is no special cast handling at present for general Struct types. + + // Special logic for AnyHashable, Set, Dictionary, Array, and String + // is broken out above. See also selectCasterForDest() for the + // logic that chooses one of these functions. + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/*************************** Optional Destination *****************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToOptional( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Optional); + + // Nothing to do for the basic casting operation. + // Unwrapping is handled by top-level tryCast with assistance + // from utility functions below. + + return DynamicCastResult::Failure; +} + +// The nil value `T?.none` can be cast to any optional type. +// When the unwrapper sees a source value that is nil, it calls +// tryCastFromNil() to try to set the target optional to nil. +// +// This is complicated by the desire to preserve the nesting +// as far as possible. For example, we would like: +// Int?.none => Int??.some(.none) +// Int??.none => Any????.some(.some(.none)) +// Of course, if the target is shallower than the source, +// then we have to just set the outermost optional to nil. + +// This helper sets a nested optional to nil at a requested level: +static void +initializeToNilAtDepth(OpaqueValue *destLocation, const Metadata *destType, int depth) { + assert(destType->getKind() == MetadataKind::Optional); + auto destInnerType = cast(destType)->getGenericArgs()[0]; + if (depth > 0) { + initializeToNilAtDepth(destLocation, destInnerType, depth - 1); + // Set .some at each level as we unwind + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, 0, 1); + } else { + // Set .none at the lowest level + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, 1, 1); + } +} + +static void +copyNil(OpaqueValue *destLocation, const Metadata *destType, const Metadata *srcType) +{ + assert(srcType->getKind() == MetadataKind::Optional); + assert(destType->getKind() == MetadataKind::Optional); + + // Measure how deep the source nil is: Is it Int?.none or Int??.none or ... + auto srcInnerType = cast(srcType)->getGenericArgs()[0]; + int srcDepth = 1; + while (srcInnerType->getKind() == MetadataKind::Optional) { + srcInnerType = cast(srcInnerType)->getGenericArgs()[0]; + srcDepth += 1; + } + + // Measure how deep the destination optional is + auto destInnerType = cast(destType)->getGenericArgs()[0]; + int destDepth = 1; + while (destInnerType->getKind() == MetadataKind::Optional) { + destInnerType = cast(destInnerType)->getGenericArgs()[0]; + destDepth += 1; + } + + // Recursively set the destination to .some(.some(... .some(.none))) + auto targetDepth = std::max(destDepth - srcDepth, 0); + initializeToNilAtDepth(destLocation, destType, targetDepth); +} + +// Try unwrapping both source and dest optionals together. +// If the source is nil, then cast that to the destination. +static DynamicCastResult +tryCastUnwrappingOptionalBoth( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(destType->getKind() == MetadataKind::Optional); + assert(srcType->getKind() == MetadataKind::Optional); + + auto srcInnerType = cast(srcType)->getGenericArgs()[0]; + unsigned sourceEnumCase = srcInnerType->vw_getEnumTagSinglePayload( + srcValue, /*emptyCases=*/1); + auto sourceIsNil = (sourceEnumCase != 0); + if (sourceIsNil) { + copyNil(destLocation, destType, srcType); + return DynamicCastResult::SuccessViaCopy; // nil was essentially copied to dest + } else { + auto destEnumType = cast(destType); + const Metadata *destInnerType = destEnumType->getGenericArgs()[0]; + auto destInnerLocation = destLocation; // Single-payload enum layout + auto subcastResult = tryCast( + destInnerLocation, destInnerType, srcValue, srcInnerType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, /*case*/ 0, /*emptyCases*/ 1); + } + return subcastResult; + } + return DynamicCastResult::Failure; +} + +// Try unwrapping just the destination optional. +// Note we do this even if both src and dest are optional. +// For example, Int -> Any? requires unwrapping the destination +// in order to inject the Int into the existential. +static DynamicCastResult +tryCastUnwrappingOptionalDestination( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(destType->getKind() == MetadataKind::Optional); + + auto destEnumType = cast(destType); + const Metadata *destInnerType = destEnumType->getGenericArgs()[0]; + auto destInnerLocation = destLocation; // Single-payload enum layout + auto subcastResult = tryCast( + destInnerLocation, destInnerType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, /*case*/ 0, /*emptyCases*/ 1); + } + return subcastResult; +} + +// Try unwrapping just the source optional. +// Note we do this even if both target and dest are optional. +// For example, this is used when extracting the contents of +// an Optional. +static DynamicCastResult +tryCastUnwrappingOptionalSource( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType->getKind() == MetadataKind::Optional); + + auto srcInnerType = cast(srcType)->getGenericArgs()[0]; + unsigned sourceEnumCase = srcInnerType->vw_getEnumTagSinglePayload( + srcValue, /*emptyCases=*/1); + auto nonNil = (sourceEnumCase == 0); + if (nonNil) { + // Recurse with unwrapped source + return tryCast(destLocation, destType, srcValue, srcInnerType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + } + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/***************************** Tuple Destination ******************************/ +/******************************************************************************/ + +// The only thing that can be legally cast to a tuple is another tuple. +// Most of the logic below is required to handle element-wise casts of +// tuples that are compatible but not of the same type. + +static DynamicCastResult +tryCastToTuple( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Tuple); + const auto destTupleType = cast(destType); + + srcFailureType = srcType; + destFailureType = destType; + + // We cannot cast non-tuple data to a tuple + if (srcType->getKind() != MetadataKind::Tuple) { + return DynamicCastResult::Failure; + } + const auto srcTupleType = cast(srcType); + + // Tuples must have same number of elements + if (srcTupleType->NumElements != destTupleType->NumElements) { + return DynamicCastResult::Failure; + } + + // Common labels must match + const char *srcLabels = srcTupleType->Labels; + const char *destLabels = destTupleType->Labels; + while (srcLabels != nullptr + && destLabels != nullptr + && srcLabels != destLabels) + { + const char *srcSpace = strchr(srcLabels, ' '); + const char *destSpace = strchr(destLabels, ' '); + + // If we've reached the end of either label string, we're done. + if (srcSpace == nullptr || destSpace == nullptr) { + break; + } + + // If both labels are non-empty, and the labels mismatch, we fail. + if (srcSpace != srcLabels && destSpace != destLabels) { + unsigned srcLen = srcSpace - srcLabels; + unsigned destLen = destSpace - destLabels; + if (srcLen != destLen || + strncmp(srcLabels, destLabels, srcLen) != 0) + return DynamicCastResult::Failure; + } + + srcLabels = srcSpace + 1; + destLabels = destSpace + 1; + } + + // Compare the element types to see if they all match. + bool typesMatch = true; + auto numElements = srcTupleType->NumElements; + for (unsigned i = 0; typesMatch && i != numElements; ++i) { + if (srcTupleType->getElement(i).Type != destTupleType->getElement(i).Type) { + typesMatch = false; + } + } + + if (typesMatch) { + // The actual element types are identical, so we can use the + // fast value-witness machinery for the whole tuple. + if (takeOnSuccess) { + srcType->vw_initializeWithTake(destLocation, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + srcType->vw_initializeWithCopy(destLocation, srcValue); + return DynamicCastResult::SuccessViaCopy; + } + } else { + // Slow path casts each item separately. + for (unsigned j = 0, n = srcTupleType->NumElements; j != n; ++j) { + const auto &srcElt = srcTupleType->getElement(j); + const auto &destElt = destTupleType->getElement(j); + auto subcastResult = tryCast(destElt.findIn(destLocation), destElt.Type, + srcElt.findIn(srcValue), srcElt.Type, + destFailureType, srcFailureType, + false, mayDeferChecks); + if (subcastResult == DynamicCastResult::Failure) { + for (unsigned k = 0; k != j; ++k) { + const auto &elt = destTupleType->getElement(k); + elt.Type->vw_destroy(elt.findIn(destLocation)); + } + return DynamicCastResult::Failure; + } + } + // We succeeded by casting each item. + return DynamicCastResult::SuccessViaCopy; + } + +} + +/******************************************************************************/ +/**************************** Function Destination ****************************/ +/******************************************************************************/ + +// The only thing that can be legally cast to a function is another function. + +static DynamicCastResult +tryCastToFunction( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Function); + const auto destFuncType = cast(destType); + + // Function casts succeed on exact matches, or if the target type is + // throwier than the source type. + // + // TODO: We could also allow ABI-compatible variance, such as casting + // a dynamic Base -> Derived to Derived -> Base. We wouldn't be able to + // perform a dynamic cast that required any ABI adjustment without a JIT + // though. + + if (srcType->getKind() != MetadataKind::Function) { + return DynamicCastResult::Failure; + } + auto srcFuncType = cast(srcType); + + // Check that argument counts and convention match (but ignore + // "throws" for now). + if (srcFuncType->Flags.withThrows(false) + != destFuncType->Flags.withThrows(false)) { + return DynamicCastResult::Failure; + } + + // If the target type can't throw, neither can the source. + if (srcFuncType->isThrowing() && !destFuncType->isThrowing()) + return DynamicCastResult::Failure; + + // The result and argument types must match. + if (srcFuncType->ResultType != destFuncType->ResultType) + return DynamicCastResult::Failure; + if (srcFuncType->getNumParameters() != destFuncType->getNumParameters()) + return DynamicCastResult::Failure; + if (srcFuncType->hasParameterFlags() != destFuncType->hasParameterFlags()) + return DynamicCastResult::Failure; + for (unsigned i = 0, e = srcFuncType->getNumParameters(); i < e; ++i) { + if (srcFuncType->getParameter(i) != destFuncType->getParameter(i) || + srcFuncType->getParameterFlags(i) != destFuncType->getParameterFlags(i)) + return DynamicCastResult::Failure; + } + + // Everything matches, so we can take/copy the function reference. + if (takeOnSuccess) { + srcType->vw_initializeWithTake(destLocation, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + srcType->vw_initializeWithCopy(destLocation, srcValue); + return DynamicCastResult::SuccessViaCopy; + } +} + +/******************************************************************************/ +/************************** Existential Destination ***************************/ +/******************************************************************************/ + +/// Check whether a type conforms to the given protocols, filling in a +/// list of conformances. +static bool _conformsToProtocols(const OpaqueValue *value, + const Metadata *type, + const ExistentialTypeMetadata *existentialType, + const WitnessTable **conformances) { + if (auto *superclass = existentialType->getSuperclassConstraint()) { + if (!swift_dynamicCastMetatype(type, superclass)) + return false; + } + + if (existentialType->isClassBounded()) { + if (!Metadata::isAnyKindOfClass(type->getKind())) + return false; + } + + for (auto protocol : existentialType->getProtocols()) { + if (!swift::_conformsToProtocol(value, type, protocol, conformances)) + return false; + if (conformances != nullptr && protocol.needsWitnessTable()) { + assert(*conformances != nullptr); + ++conformances; + } + } + + return true; +} + +// Cast to unconstrained `Any` +static DynamicCastResult +tryCastToUnconstrainedOpaqueExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + assert(cast(destType)->getRepresentation() + == ExistentialTypeRepresentation::Opaque); + auto destExistential + = reinterpret_cast(destLocation); + + // Fill in the type and value. + destExistential->Type = srcType; + auto *destBox = srcType->allocateBoxForExistentialIn(&destExistential->Buffer); + if (takeOnSuccess) { + srcType->vw_initializeWithTake(destBox, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + srcType->vw_initializeWithCopy(destBox, srcValue); + return DynamicCastResult::SuccessViaCopy; + } +} + +// Cast to constrained `Any` +static DynamicCastResult +tryCastToConstrainedOpaqueExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Opaque); + auto destExistential + = reinterpret_cast(destLocation); + + // Check for protocol conformances and fill in the witness tables. + // TODO (rdar://17033499) If the source is an existential, we should + // be able to compare the protocol constraints more efficiently than this. + if (_conformsToProtocols(srcValue, srcType, destExistentialType, + destExistential->getWitnessTables())) { + return tryCastToUnconstrainedOpaqueExistential( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + } else { + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastToClassExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Class); + auto destExistentialLocation + = reinterpret_cast(destLocation); + + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + + case MetadataKind::Metatype: { +#if SWIFT_OBJC_INTEROP + // Get an object reference to the metatype and try fitting that into + // the existential... + auto metatypePtr = reinterpret_cast(srcValue); + auto metatype = *metatypePtr; + if (auto tmp = swift_dynamicCastMetatypeToObjectConditional(metatype)) { + auto value = reinterpret_cast(&tmp); + auto type = reinterpret_cast(tmp); + if (_conformsToProtocols(value, type, destExistentialType, + destExistentialLocation->getWitnessTables())) { + auto object = *(reinterpret_cast(value)); + destExistentialLocation->Value = object; + if (takeOnSuccess) { + // We copied the pointer without retain, so the source is no + // longer valid... + return DynamicCastResult::SuccessViaTake; + } else { + swift_unknownObjectRetain(object); + return DynamicCastResult::SuccessViaCopy; + } + } else { + // We didn't assign to destination, so the source reference + // is still valid and the reference count is still correct. + } + } +#endif + return DynamicCastResult::Failure; + } + + case MetadataKind::ObjCClassWrapper: + case MetadataKind::Class: + case MetadataKind::ForeignClass: { + auto object = getNonNullSrcObject(srcValue, srcType, destType); + if (_conformsToProtocols(srcValue, srcType, + destExistentialType, + destExistentialLocation->getWitnessTables())) { + destExistentialLocation->Value = object; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + swift_unknownObjectRetain(object); + return DynamicCastResult::SuccessViaCopy; + } + } + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } + + return DynamicCastResult::Failure; +} + +// SwiftValue boxing is a failsafe that we only want to invoke +// after other approaches have failed. This is why it's not +// integrated into tryCastToClassExistential() above. +static DynamicCastResult +tryCastToClassExistentialViaSwiftValue( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Class); + auto destExistentialLocation + = reinterpret_cast(destLocation); + + // Fail if the target has constraints that make it unsuitable for + // a __SwiftValue box. + // FIXME: We should not have different checks here for + // Obj-C vs non-Obj-C. The _SwiftValue boxes should conform + // to the exact same protocols on both platforms. + bool destIsConstrained = destExistentialType->NumProtocols != 0; + if (destIsConstrained) { +#if SWIFT_OBJC_INTEROP // __SwiftValue is an Obj-C class + if (!findSwiftValueConformances( + destExistentialType, destExistentialLocation->getWitnessTables())) { + return DynamicCastResult::Failure; + } +#else // __SwiftValue is a native class + if (!swift_swiftValueConformsTo(destType, destType)) { + return DynamicCastResult::Failure; + } +#endif + } + +#if SWIFT_OBJC_INTEROP + auto object = bridgeAnythingToSwiftValueObject( + srcValue, srcType, takeOnSuccess); + destExistentialLocation->Value = object; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + return DynamicCastResult::SuccessViaCopy; + } +# else + // Note: Code below works correctly on both Obj-C and non-Obj-C platforms, + // but the code above is slightly faster on Obj-C platforms. + auto object = _bridgeAnythingToObjectiveC(srcValue, srcType); + destExistentialLocation->Value = object; + return DynamicCastResult::SuccessViaCopy; +#endif +} + +static DynamicCastResult +tryCastToErrorExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Error); + auto destBoxAddr = reinterpret_cast(destLocation); + + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + case MetadataKind::ForeignClass: // CF object => Error + case MetadataKind::ObjCClassWrapper: // Obj-C object => Error + case MetadataKind::Struct: // Struct => Error + case MetadataKind::Enum: // Enum => Error + case MetadataKind::Class: { // Class => Error + assert(destExistentialType->NumProtocols == 1); + const WitnessTable *errorWitness; + if (_conformsToProtocols( + srcValue, srcType, destExistentialType, &errorWitness)) { +#if SWIFT_OBJC_INTEROP + // If it already holds an NSError, just use that. + if (auto embedded = getErrorEmbeddedNSErrorIndirect( + srcValue, srcType, errorWitness)) { + *destBoxAddr = reinterpret_cast(embedded); + return DynamicCastResult::SuccessViaCopy; + } +#endif + + BoxPair destBox = swift_allocError( + srcType, errorWitness, srcValue, takeOnSuccess); + *destBoxAddr = reinterpret_cast(destBox.object); + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + return DynamicCastResult::SuccessViaCopy; + } + } + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastUnwrappingExistentialSource( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + auto srcExistentialType = cast(srcType); + + // Unpack the existential content + const Metadata *srcInnerType; + OpaqueValue *srcInnerValue; + switch (srcExistentialType->getRepresentation()) { + case ExistentialTypeRepresentation::Class: { + auto classContainer + = reinterpret_cast(srcValue); + srcInnerType = swift_getObjectType((HeapObject *)classContainer->Value); + srcInnerValue = reinterpret_cast(&classContainer->Value); + break; + } + case ExistentialTypeRepresentation::Opaque: { + auto opaqueContainer + = reinterpret_cast(srcValue); + srcInnerType = opaqueContainer->Type; + srcInnerValue = srcExistentialType->projectValue(srcValue); + break; + } + case ExistentialTypeRepresentation::Error: { + const SwiftError *errorBox + = *reinterpret_cast(srcValue); + auto srcErrorValue + = errorBox->isPureNSError() ? srcValue : errorBox->getValue(); + srcInnerType = errorBox->getType(); + srcInnerValue = const_cast(srcErrorValue); + break; + } + } + + srcFailureType = srcInnerType; + return tryCast(destLocation, destType, + srcInnerValue, srcInnerType, + destFailureType, srcFailureType, + takeOnSuccess & (srcInnerValue == srcValue), + mayDeferChecks); +} + +/******************************************************************************/ +/**************************** Opaque Destination ******************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToOpaque( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Opaque); + + // There's nothing special we can do here, but we have to have this + // empty function in order for the general casting logic to run + // for these types. + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/**************************** Metatype Destination ****************************/ +/******************************************************************************/ + +#if SWIFT_OBJC_INTEROP +/// Check whether an unknown class instance is actually a type/metatype object. +static const Metadata *_getUnknownClassAsMetatype(void *object) { + // Objective-C class metadata are objects, so an AnyObject (or + // NSObject) may refer to a class object. + + // Test whether the object's isa is a metaclass, which indicates that + // the object is a class. + + Class isa = object_getClass((id)object); + if (class_isMetaClass(isa)) { + return swift_getObjCClassMetadata((const ClassMetadata *)object); + } + + return nullptr; +} +#endif + +static DynamicCastResult +tryCastToMetatype( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Metatype); + + const MetatypeMetadata *destMetatypeType = cast(destType); + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + case MetadataKind::Metatype: + case MetadataKind::ExistentialMetatype: { + const Metadata *srcMetatype = *(const Metadata * const *) srcValue; + if (auto result = swift_dynamicCastMetatype( + srcMetatype, destMetatypeType->InstanceType)) { + *((const Metadata **) destLocation) = result; + return DynamicCastResult::SuccessViaCopy; + } + return DynamicCastResult::Failure; + } + + case MetadataKind::Class: + case MetadataKind::ObjCClassWrapper: { +#if SWIFT_OBJC_INTEROP + // Some classes are actually metatypes + void *object = getNonNullSrcObject(srcValue, srcType, destType); + if (auto metatype = _getUnknownClassAsMetatype(object)) { + auto srcInnerValue = reinterpret_cast(&metatype); + auto srcInnerType = swift_getMetatypeMetadata(metatype); + return tryCast(destLocation, destType, srcInnerValue, srcInnerType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + } +#endif + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } +} + +/// Perform a dynamic cast of a metatype to an existential metatype type. +static DynamicCastResult +_dynamicCastMetatypeToExistentialMetatype( + OpaqueValue *destLocation, const ExistentialMetatypeMetadata *destType, + const Metadata *srcMetatype, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + // The instance type of an existential metatype must be either an + // existential or an existential metatype. + auto destMetatype + = reinterpret_cast(destLocation); + + // If it's an existential, we need to check for conformances. + auto targetInstanceType = destType->InstanceType; + if (auto targetInstanceTypeAsExistential = + dyn_cast(targetInstanceType)) { + // Check for conformance to all the protocols. + // TODO: collect the witness tables. + const WitnessTable **conformance + = destMetatype ? destMetatype->getWitnessTables() : nullptr; + if (!_conformsToProtocols(nullptr, srcMetatype, + targetInstanceTypeAsExistential, + conformance)) { + return DynamicCastResult::Failure; + } + + if (destMetatype) + destMetatype->Value = srcMetatype; + return DynamicCastResult::SuccessViaCopy; + } + + // Otherwise, we're casting to SomeProtocol.Type.Type. + auto targetInstanceTypeAsMetatype = + cast(targetInstanceType); + + // If the source type isn't a metatype, the cast fails. + auto srcMetatypeMetatype = dyn_cast(srcMetatype); + if (!srcMetatypeMetatype) { + return DynamicCastResult::Failure; + } + + // The representation of an existential metatype remains consistent + // arbitrarily deep: a metatype, followed by some protocols. The + // protocols are the same at every level, so we can just set the + // metatype correctly and then recurse, letting the recursive call + // fill in the conformance information correctly. + + // Proactively set the destination metatype so that we can tail-recur, + // unless we've already done so. There's no harm in doing this even if + // the cast fails. + if (destLocation) + *((const Metadata **) destLocation) = srcMetatype; + + // Recurse. + auto srcInstanceType = srcMetatypeMetatype->InstanceType; + return _dynamicCastMetatypeToExistentialMetatype( + nullptr, + targetInstanceTypeAsMetatype, + srcInstanceType, + destFailureType, + srcFailureType, + takeOnSuccess, mayDeferChecks); +} + +// "ExistentialMetatype" is the metatype for an existential type. +static DynamicCastResult +tryCastToExistentialMetatype( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::ExistentialMetatype); + + auto destExistentialMetatypeType + = cast(destType); + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + case MetadataKind::Metatype: // Metatype => ExistentialMetatype + case MetadataKind::ExistentialMetatype: { // ExistentialMetatype => ExistentialMetatype + const Metadata *srcMetatype = *(const Metadata * const *) srcValue; + return _dynamicCastMetatypeToExistentialMetatype( + destLocation, + destExistentialMetatypeType, + srcMetatype, + destFailureType, + srcFailureType, + takeOnSuccess, mayDeferChecks); + } + + case MetadataKind::ObjCClassWrapper: { + // Some Obj-C classes are actually metatypes +#if SWIFT_OBJC_INTEROP + void *srcObject = getNonNullSrcObject(srcValue, srcType, destType); + if (auto metatype = _getUnknownClassAsMetatype(srcObject)) { + return _dynamicCastMetatypeToExistentialMetatype( + destLocation, + destExistentialMetatypeType, + metatype, + destFailureType, + srcFailureType, + takeOnSuccess, mayDeferChecks); + } +#endif + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } +} + +/******************************************************************************/ +/********************************** Dispatch **********************************/ +/******************************************************************************/ + +// A layer of functions that evaluate the source and/or destination types +// in order to invoke a tailored casting operation above. +// +// This layer also deals with general issues of unwrapping box types +// and invoking bridging conversions defined via the _ObjectiveCBridgeable +// protocol. +// +// Most of the caster functions above should be fairly simple: +// * They should deal with a single target type, +// * They should assume the source is fully unwrapped, +// * They should not try to report or cleanup failure, +// * If they can take, they should report the source was destroyed. + +// Based on the destination type alone, select a targeted casting function. +// This design avoids some redundant inspection of the destination type +// data, for example, when we unwrap source boxes. +static tryCastFunctionType *selectCasterForDest(const Metadata *destType) { + auto destKind = destType->getKind(); + switch (destKind) { + case MetadataKind::Class: + return tryCastToSwiftClass; + case MetadataKind::Struct: { + const auto targetDescriptor = cast(destType)->Description; + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(SS)) { + return tryCastToString; + } + if (targetDescriptor == &STRUCT_TYPE_DESCR_SYM(s11AnyHashable)) { + return tryCastToAnyHashable; + } + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(Sa)) { + return tryCastToArray; + } + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(SD)) { + return tryCastToDictionary; + } + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(Sh)) { + return tryCastToSet; + } + return tryCastToStruct; + } + case MetadataKind::Enum: + return tryCastToEnum; + case MetadataKind::Optional: + return tryCastToOptional; + case MetadataKind::ForeignClass: + return tryCastToForeignClass; + case MetadataKind::Opaque: + return tryCastToOpaque; + case MetadataKind::Tuple: + return tryCastToTuple; + case MetadataKind::Function: + return tryCastToFunction; + case MetadataKind::Existential: { + auto existentialType = cast(destType); + switch (existentialType->getRepresentation()) { + case ExistentialTypeRepresentation::Opaque: + if (existentialType->NumProtocols == 0) { + return tryCastToUnconstrainedOpaqueExistential; // => Unconstrained Any + } else { + return tryCastToConstrainedOpaqueExistential; // => Non-class-constrained protocol + } + case ExistentialTypeRepresentation::Class: + return tryCastToClassExistential; // => AnyObject, with or without protocol constraints + case ExistentialTypeRepresentation::Error: // => Error existential + return tryCastToErrorExistential; + } + swift_runtime_unreachable( + "Unknown existential type representation in dynamic cast dispatch"); + } + case MetadataKind::Metatype: + return tryCastToMetatype; + case MetadataKind::ObjCClassWrapper: + return tryCastToObjectiveCClass; + case MetadataKind::ExistentialMetatype: + return tryCastToExistentialMetatype; + case MetadataKind::HeapLocalVariable: + case MetadataKind::HeapGenericLocalVariable: + case MetadataKind::ErrorObject: + // These are internal details of runtime-only structures, + // so will never appear in compiler-generated types. + // As such, they don't need support here. + swift_runtime_unreachable( + "Unexpected MetadataKind in dynamic cast dispatch"); + return nullptr; + default: + // If you see this message, then there is a new MetadataKind that I didn't + // know about when I wrote this code. Please figure out what it is, how to + // handle it, and add a case for it. + swift_runtime_unreachable( + "Unknown MetadataKind in dynamic cast dispatch"); + } +} + +// This top-level driver provides the general flow for all casting +// operations. It recursively unwraps source and destination as it +// searches for a suitable conversion. +static DynamicCastResult +tryCast( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + destFailureType = destType; + srcFailureType = srcType; + + //////////////////////////////////////////////////////////////////////// + // + // 1. If types match exactly, we can just move/copy the data. + // (The tryCastToXyz functions never see this trivial case.) + // + if (srcType == destType) { + if (takeOnSuccess) { + destType->vw_initializeWithTake(destLocation, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + destType->vw_initializeWithCopy(destLocation, srcValue); + return DynamicCastResult::SuccessViaCopy; + } + } + + auto destKind = destType->getKind(); + auto srcKind = srcType->getKind(); + + //////////////////////////////////////////////////////////////////////// + // + // 2. Try directly casting the current srcValue to the target type. + // (If the dynamic type is different, try that too.) + // + auto tryCastToDestType = selectCasterForDest(destType); + if (tryCastToDestType == nullptr) { + return DynamicCastResult::Failure; + } + auto castResult = tryCastToDestType(destLocation, destType, srcValue, + srcType, destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(castResult)) { + return castResult; + } + if (srcKind == MetadataKind::Class + || srcKind == MetadataKind::ObjCClassWrapper + || srcKind == MetadataKind::ForeignClass) { + auto srcObject = getNonNullSrcObject(srcValue, srcType, destType); + auto srcDynamicType = swift_getObjectType(srcObject); + if (srcDynamicType != srcType) { + srcFailureType = srcDynamicType; + auto castResult = tryCastToDestType( + destLocation, destType, srcValue, srcDynamicType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(castResult)) { + return castResult; + } + } + } + + //////////////////////////////////////////////////////////////////////// + // + // 3. Try recursively unwrapping _source_ boxes, including + // existentials, AnyHashable, SwiftValue, and Error. + // + switch (srcKind) { + + case MetadataKind::Class: { +#if !SWIFT_OBJC_INTEROP + // Try unwrapping native __SwiftValue implementation + if (swift_unboxFromSwiftValueWithType(srcValue, destLocation, destType)) { + return DynamicCastResult::SuccessViaCopy; + } +#endif + break; + } + + case MetadataKind::ObjCClassWrapper: { +#if SWIFT_OBJC_INTEROP + // Try unwrapping Obj-C __SwiftValue implementation + auto subcastResult = tryCastUnwrappingObjCSwiftValueSource( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } +#endif + +#if SWIFT_OBJC_INTEROP + // Try unwrapping Obj-C NSError container + auto innerFlags = DynamicCastFlags::Default; + if (tryDynamicCastNSErrorToValue( + destLocation, srcValue, srcType, destType, innerFlags)) { + return DynamicCastResult::SuccessViaCopy; + } +#endif + break; + } + + case MetadataKind::Struct: { + auto srcStructType = cast(srcType); + auto srcStructDescription = srcStructType->getDescription(); + + // Try unwrapping AnyHashable container + if (srcStructDescription == &STRUCT_TYPE_DESCR_SYM(s11AnyHashable)) { + if (_swift_anyHashableDownCastConditionalIndirect( + srcValue, destLocation, destType)) { + return DynamicCastResult::SuccessViaCopy; + } + } + break; + } + + case MetadataKind::Existential: { + auto subcastResult = tryCastUnwrappingExistentialSource( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + break; + } + + default: + break; + } + + //////////////////////////////////////////////////////////////////////// + // + // 4. Try recursively unwrapping Optionals. First try jointly unwrapping + // both source and destination, then just destination, then just source. + // Note that if both are optional, we try all three of these! + // For example, consider casting an Optional to + // Optional. If T conforms, we need to + // unwrap both. But if it doesn't, we unwrap just the destination + // in order to cast Optional to the protocol directly. + // + if (destKind == MetadataKind::Optional) { + if (srcKind == MetadataKind::Optional) { + auto subcastResult = tryCastUnwrappingOptionalBoth( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + auto subcastResult = tryCastUnwrappingOptionalDestination( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + + if (srcKind == MetadataKind::Optional) { + auto subcastResult = tryCastUnwrappingOptionalSource( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + + //////////////////////////////////////////////////////////////////////// + // + // 5. Finally, explore bridging conversions via ObjectiveCBridgeable, + // Error, and __SwiftValue boxing. + // + switch (destKind) { + + case MetadataKind::Optional: { + // Optional supports _ObjectiveCBridgeable from an unconstrained AnyObject + if (srcType->getKind() == MetadataKind::Existential) { + auto srcExistentialType = cast(srcType); + if ((srcExistentialType->getRepresentation() == ExistentialTypeRepresentation::Class) + && (srcExistentialType->NumProtocols == 0) + && (srcExistentialType->getSuperclassConstraint() == nullptr) + && (srcExistentialType->isClassBounded())) { + auto toObjCResult = tryCastFromClassToObjCBridgeable( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, false); + if (isSuccess(toObjCResult)) { + return toObjCResult; + } + } + } + + break; + } + + case MetadataKind::Existential: { + // Try general machinery for stuffing values into AnyObject: + auto destExistentialType = cast(destType); + if (destExistentialType->getRepresentation() == ExistentialTypeRepresentation::Class) { + // Some types have custom Objective-C bridging support... + auto subcastResult = tryCastFromObjCBridgeableToClass( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + + // Other types can be boxed into a __SwiftValue container... + auto swiftValueCastResult = tryCastToClassExistentialViaSwiftValue( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(swiftValueCastResult)) { + return swiftValueCastResult; + } + } + break; + } + + case MetadataKind::Class: + case MetadataKind::ObjCClassWrapper: + case MetadataKind::ForeignClass: { + // Try _ObjectiveCBridgeable to bridge _to_ a class type _from_ a + // struct/enum type. Note: Despite the name, this is used for both + // Swift-Swift and Swift-ObjC bridging + if (srcKind == MetadataKind::Struct || srcKind == MetadataKind::Enum) { + auto subcastResult = tryCastFromObjCBridgeableToClass( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + +#if SWIFT_OBJC_INTEROP + if (destKind == MetadataKind::ObjCClassWrapper) { + // If the destination type is an NSError or NSObject, and the source type + // is an Error, then the cast might succeed by NSError bridging. + if (auto srcErrorWitness = findErrorWitness(srcType)) { + if (destType == getNSErrorMetadata() + || destType == getNSObjectMetadata()) { + auto flags = DynamicCastFlags::Default; + auto error = dynamicCastValueToNSError(srcValue, srcType, + srcErrorWitness, flags); + *reinterpret_cast(destLocation) = error; + return DynamicCastResult::SuccessViaCopy; + } + } + } +#endif + + break; + } + + case MetadataKind::Struct: + case MetadataKind::Enum: { + // Use _ObjectiveCBridgeable to bridge _from_ a class type _to_ a + // struct/enum type. Note: Despite the name, this is used for both + // Swift-Swift and ObjC-Swift bridging + if (srcKind == MetadataKind::Class + || srcKind == MetadataKind::ObjCClassWrapper + || srcKind == MetadataKind::ForeignClass) { + auto subcastResult = tryCastFromClassToObjCBridgeable( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + + // Note: In theory, if src and dest are both struct/enum types, we could see + // if the ObjC bridgeable class types matched and then do a two-step + // conversion from src -> bridge class -> dest. Such ambitious conversions + // might cause more harm than good, though. In particular, it could + // undermine code that uses a series of `as?` to quickly determine how to + // handle a particular object. + break; + } + + default: + break; + } + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/****************************** Main Entrypoint *******************************/ +/******************************************************************************/ + +// XXX REMOVE ME XXX TODO XXX +// Declare the old entrypoint +SWIFT_RUNTIME_EXPORT +bool +swift_dynamicCast_OLD(OpaqueValue *destLocation, + OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType, + DynamicCastFlags flags); +// XXX REMOVE ME XXX TODO XXX + +/// ABI: Perform a dynamic cast to an arbitrary type. +static bool +swift_dynamicCastImpl(OpaqueValue *destLocation, + OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType, + DynamicCastFlags flags) +{ + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + // Support switching to the old implementation while the new one + // is still settling. Once the new implementation is stable, + // I'll rip the old one entirely out. + static bool useOldImplementation = false; // Default: NEW Implementation + static swift_once_t Predicate; + swift_once( + &Predicate, + [](void *) { + // Define SWIFT_OLD_DYNAMIC_CAST_RUNTIME=1 to use the old runtime + // dynamic cast logic. + auto useOld = getenv("SWIFT_OLD_DYNAMIC_CAST_RUNTIME"); + if (useOld) { + useOldImplementation = true; + } + }, nullptr); + if (useOldImplementation) { + return swift_dynamicCast_OLD(destLocation, srcValue, + srcType, destType, flags); + } + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + + // If the compiler has asked for a "take", we can + // move pointers without ref-counting overhead. + bool takeOnSuccess = flags & DynamicCastFlags::TakeOnSuccess; + // Unconditional casts are allowed to crash the program on failure. + // We can exploit that for performance: return a partial conversion + // immediately and do additional checks lazily when the results are + // actually accessed. + bool mayDeferChecks = flags & DynamicCastFlags::Unconditional; + + // Attempt the cast... + const Metadata *destFailureType = destType; + const Metadata *srcFailureType = srcType; + auto result = tryCast( + destLocation, destType, + srcValue, srcType, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks); + + switch (result) { + case DynamicCastResult::Failure: + if (flags & DynamicCastFlags::Unconditional) { + swift_dynamicCastFailure(srcFailureType, destFailureType); + } + if (flags & DynamicCastFlags::DestroyOnFailure) { + srcType->vw_destroy(srcValue); + } + return false; + case DynamicCastResult::SuccessViaCopy: + if (takeOnSuccess) { // We copied, but compiler asked for take. + srcType->vw_destroy(srcValue); + } + return true; + case DynamicCastResult::SuccessViaTake: + return true; + } +} + +#define OVERRIDE_DYNAMICCASTING COMPATIBILITY_OVERRIDE +#include "CompatibilityOverride.def" diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index 6e0dd53758bc9..b5a5e467388cb 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -137,7 +137,7 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName, void swift::dumpStackTraceEntry(unsigned index, void *framePC, bool shortOutput) { -#if SWIFT_SUPPORTS_BACKTRACE_REPORTING +#if SWIFT_SUPPORTS_BACKTRACE_REPORTING && !defined(SWIFT_RUNTIME_MACHO_NO_DYLD) SymbolInfo syminfo; // 0 is failure for lookupSymbol diff --git a/stdlib/public/runtime/Exclusivity.cpp b/stdlib/public/runtime/Exclusivity.cpp index f2a6a6e98522b..13ace8a514835 100644 --- a/stdlib/public/runtime/Exclusivity.cpp +++ b/stdlib/public/runtime/Exclusivity.cpp @@ -252,7 +252,14 @@ class SwiftTLSContext { // Each of these cases should define a function with this prototype: // AccessSets &getAllSets(); -#if SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + +static SwiftTLSContext &getTLSContext() { + static SwiftTLSContext TLSContext; + return TLSContext; +} + +#elif SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC // Use the reserved TSD key if possible. static SwiftTLSContext &getTLSContext() { diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index 50177c633e933..b7f739061a8b9 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -171,13 +171,7 @@ swift::swift_initStaticObject(HeapMetadata const *metadata, // refcount to 1 while another thread already incremented it - and would // decrement it to 0 afterwards. InitStaticObjectContext Ctx = { object, metadata }; -#ifdef __wasm__ - // WebAssembly: hack: swift_once has been modified to take a function pointer without a parameter. - // so use the _real version that does have a parameter - swift_once_real(token, initStaticObjectWithContext, &Ctx); -#else swift_once(token, initStaticObjectWithContext, &Ctx); -#endif return object; } @@ -344,7 +338,11 @@ static HeapObject *_swift_retain_(HeapObject *object) { } HeapObject *swift::swift_retain(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_retain(object); +#else CALL_IMPL(swift_retain, (object)); +#endif } SWIFT_RUNTIME_EXPORT @@ -366,7 +364,11 @@ static HeapObject *_swift_retain_n_(HeapObject *object, uint32_t n) { } HeapObject *swift::swift_retain_n(HeapObject *object, uint32_t n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_retain_n(object, n); +#else CALL_IMPL(swift_retain_n, (object, n)); +#endif } SWIFT_RUNTIME_EXPORT @@ -387,7 +389,11 @@ static void _swift_release_(HeapObject *object) { } void swift::swift_release(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_release(object); +#else CALL_IMPL(swift_release, (object)); +#endif } SWIFT_RUNTIME_EXPORT @@ -407,7 +413,11 @@ static void _swift_release_n_(HeapObject *object, uint32_t n) { } void swift::swift_release_n(HeapObject *object, uint32_t n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_release_n(object, n); +#else CALL_IMPL(swift_release_n, (object, n)); +#endif } SWIFT_RUNTIME_EXPORT @@ -438,15 +448,22 @@ size_t swift::swift_weakRetainCount(HeapObject *object) { } HeapObject *swift::swift_unownedRetain(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return static_cast(swift_nonatomic_unownedRetain(object)); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetain); if (!isValidPointerForNativeRetain(object)) return object; object->refCounts.incrementUnowned(1); return object; +#endif } void swift::swift_unownedRelease(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_unownedRelease(object); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRelease); if (!isValidPointerForNativeRetain(object)) return; @@ -461,6 +478,7 @@ void swift::swift_unownedRelease(HeapObject *object) { swift_slowDealloc(object, classMetadata->getInstanceSize(), classMetadata->getInstanceAlignMask()); } +#endif } void *swift::swift_nonatomic_unownedRetain(HeapObject *object) { @@ -490,15 +508,22 @@ void swift::swift_nonatomic_unownedRelease(HeapObject *object) { } HeapObject *swift::swift_unownedRetain_n(HeapObject *object, int n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_unownedRetain_n(object, n); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetain_n); if (!isValidPointerForNativeRetain(object)) return object; object->refCounts.incrementUnowned(n); return object; +#endif } void swift::swift_unownedRelease_n(HeapObject *object, int n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_unownedRelease_n(object, n); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRelease_n); if (!isValidPointerForNativeRetain(object)) return; @@ -512,6 +537,7 @@ void swift::swift_unownedRelease_n(HeapObject *object, int n) { swift_slowDealloc(object, classMetadata->getInstanceSize(), classMetadata->getInstanceAlignMask()); } +#endif } HeapObject *swift::swift_nonatomic_unownedRetain_n(HeapObject *object, int n) { @@ -544,8 +570,13 @@ static HeapObject *_swift_tryRetain_(HeapObject *object) { if (!isValidPointerForNativeRetain(object)) return nullptr; +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + if (object->refCounts.tryIncrementNonAtomic()) return object; + else return nullptr; +#else if (object->refCounts.tryIncrement()) return object; else return nullptr; +#endif } HeapObject *swift::swift_tryRetain(HeapObject *object) { @@ -568,6 +599,9 @@ void swift::swift_setDeallocating(HeapObject *object) { } HeapObject *swift::swift_unownedRetainStrong(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_unownedRetainStrong(object); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetainStrong); if (!isValidPointerForNativeRetain(object)) return object; @@ -577,6 +611,7 @@ HeapObject *swift::swift_unownedRetainStrong(HeapObject *object) { if (! object->refCounts.tryIncrement()) swift::swift_abortRetainUnowned(object); return object; +#endif } HeapObject *swift::swift_nonatomic_unownedRetainStrong(HeapObject *object) { @@ -592,6 +627,9 @@ HeapObject *swift::swift_nonatomic_unownedRetainStrong(HeapObject *object) { } void swift::swift_unownedRetainStrongAndRelease(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_unownedRetainStrongAndRelease(object); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetainStrongAndRelease); if (!isValidPointerForNativeRetain(object)) return; @@ -605,6 +643,7 @@ void swift::swift_unownedRetainStrongAndRelease(HeapObject *object) { bool dealloc = object->refCounts.decrementUnownedShouldFree(1); assert(!dealloc && "retain-strong-and-release caused dealloc?"); (void) dealloc; +#endif } void swift::swift_nonatomic_unownedRetainStrongAndRelease(HeapObject *object) { diff --git a/stdlib/public/runtime/ImageInspectionCommon.h b/stdlib/public/runtime/ImageInspectionCommon.h index c2004270b3969..eae0ef0f39df5 100644 --- a/stdlib/public/runtime/ImageInspectionCommon.h +++ b/stdlib/public/runtime/ImageInspectionCommon.h @@ -19,7 +19,27 @@ #ifndef SWIFT_RUNTIME_IMAGEINSPECTIONCOMMON_H #define SWIFT_RUNTIME_IMAGEINSPECTIONCOMMON_H -#if !defined(__MACH__) +#if defined(__MACH__) + +#include + +/// The Mach-O section name for the section containing protocol descriptor +/// references. This lives within SEG_TEXT. +#define MachOProtocolsSection "__swift5_protos" +/// The Mach-O section name for the section containing protocol conformances. +/// This lives within SEG_TEXT. +#define MachOProtocolConformancesSection "__swift5_proto" +/// The Mach-O section name for the section containing type references. +/// This lives within SEG_TEXT. +#define MachOTypeMetadataRecordSection "__swift5_types" +/// The Mach-O section name for the section containing dynamic replacements. +/// This lives within SEG_TEXT. +#define MachODynamicReplacementSection "__swift5_replace" +#define MachODynamicReplacementSomeSection "__swift5_replac2" + +#define MachOTextSegment "__TEXT" + +#else #if defined(__ELF__) || defined(__wasm__) #define SWIFT_REFLECTION_METADATA_ELF_NOTE_MAGIC_STRING "swift_reflection_metadata_magic_string" diff --git a/stdlib/public/runtime/ImageInspectionMachO.cpp b/stdlib/public/runtime/ImageInspectionMachO.cpp index 81ee6ed3079da..54c4d17a52a5e 100644 --- a/stdlib/public/runtime/ImageInspectionMachO.cpp +++ b/stdlib/public/runtime/ImageInspectionMachO.cpp @@ -18,9 +18,12 @@ /// //===----------------------------------------------------------------------===// -#if defined(__APPLE__) && defined(__MACH__) +#if defined(__APPLE__) && defined(__MACH__) && \ + !defined(SWIFT_RUNTIME_MACHO_NO_DYLD) #include "ImageInspection.h" +#include "ImageInspectionCommon.h" +#include "swift/Runtime/Config.h" #include #include #include @@ -30,21 +33,17 @@ using namespace swift; namespace { -/// The Mach-O section name for the section containing protocol descriptor -/// references. This lives within SEG_TEXT. -constexpr const char ProtocolsSection[] = "__swift5_protos"; -/// The Mach-O section name for the section containing protocol conformances. -/// This lives within SEG_TEXT. -constexpr const char ProtocolConformancesSection[] = "__swift5_proto"; -/// The Mach-O section name for the section containing type references. -/// This lives within SEG_TEXT. -constexpr const char TypeMetadataRecordSection[] = "__swift5_types"; -/// The Mach-O section name for the section containing dynamic replacements. -/// This lives within SEG_TEXT. -constexpr const char DynamicReplacementSection[] = "__swift5_replace"; -constexpr const char DynamicReplacementSomeSection[] = "__swift5_replac2"; - -constexpr const char TextSegment[] = SEG_TEXT; + +constexpr const char ProtocolsSection[] = MachOProtocolsSection; +constexpr const char ProtocolConformancesSection[] = + MachOProtocolConformancesSection; +constexpr const char TypeMetadataRecordSection[] = + MachOTypeMetadataRecordSection; +constexpr const char DynamicReplacementSection[] = + MachODynamicReplacementSection; +constexpr const char DynamicReplacementSomeSection[] = + MachODynamicReplacementSomeSection; +constexpr const char TextSegment[] = MachOTextSegment; #if __POINTER_WIDTH__ == 64 using mach_header_platform = mach_header_64; @@ -121,7 +120,7 @@ void addImageCallback2Sections(const mach_header *mh, intptr_t vmaddr_slide) { } // end anonymous namespace -#if OBJC_ADDLOADIMAGEFUNC_DEFINED +#if OBJC_ADDLOADIMAGEFUNC_DEFINED && SWIFT_OBJC_INTEROP #define REGISTER_FUNC(...) \ if (__builtin_available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)) { \ objc_addLoadImageFunc(__VA_ARGS__); \ @@ -168,6 +167,8 @@ int swift::lookupSymbol(const void *address, SymbolInfo *info) { return 1; } +#ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES + void *swift::lookupSection(const char *segment, const char *section, size_t *outSize) { unsigned long size; auto *executableHeader = static_cast(_NSGetMachExecuteHeader()); @@ -177,4 +178,7 @@ void *swift::lookupSection(const char *segment, const char *section, size_t *out return static_cast(data); } -#endif // defined(__APPLE__) && defined(__MACH__) +#endif // #ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES + +#endif // defined(__APPLE__) && defined(__MACH__) && + // !defined(SWIFT_RUNTIME_MACHO_NO_DYLD) diff --git a/stdlib/public/runtime/ImageInspectionStatic.cpp b/stdlib/public/runtime/ImageInspectionStatic.cpp new file mode 100644 index 0000000000000..8b95ca01d38b4 --- /dev/null +++ b/stdlib/public/runtime/ImageInspectionStatic.cpp @@ -0,0 +1,78 @@ +//===--- ImageInspectionStatic.cpp - image inspection for static stdlib ---===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Implementation of ImageInspection for static stdlib (no dynamic loader +/// present) environments. Assumes that only a single image exists in memory. +/// +//===----------------------------------------------------------------------===// + +#if defined(__MACH__) && defined(SWIFT_RUNTIME_MACHO_NO_DYLD) + +#include "ImageInspection.h" +#include "ImageInspectionCommon.h" + +using namespace swift; + +#define GET_SECTION_START_AND_SIZE(start, size, _seg, _sec) \ + extern void *__s##_seg##_sec __asm("section$start$" _seg "$" _sec); \ + extern void *__e##_seg##_sec __asm("section$end$" _seg "$" _sec); \ + start = &__s##_seg##_sec; \ + size = (char *)&__e##_seg##_sec - (char *)&__s##_seg##_sec; + +void swift::initializeProtocolLookup() { + void *start; + uintptr_t size; + GET_SECTION_START_AND_SIZE(start, size, MachOTextSegment, + MachOProtocolsSection); + if (start == nullptr || size == 0) + return; + addImageProtocolsBlockCallbackUnsafe(start, size); +} + +void swift::initializeProtocolConformanceLookup() { + void *start; + uintptr_t size; + GET_SECTION_START_AND_SIZE(start, size, MachOTextSegment, + MachOProtocolConformancesSection); + if (start == nullptr || size == 0) + return; + addImageProtocolConformanceBlockCallbackUnsafe(start, size); +} +void swift::initializeTypeMetadataRecordLookup() { + void *start; + uintptr_t size; + GET_SECTION_START_AND_SIZE(start, size, MachOTextSegment, + MachOTypeMetadataRecordSection); + if (start == nullptr || size == 0) + return; + addImageTypeMetadataRecordBlockCallbackUnsafe(start, size); +} + +void swift::initializeDynamicReplacementLookup() { + void *start1; + uintptr_t size1; + GET_SECTION_START_AND_SIZE(start1, size1, MachOTextSegment, + MachODynamicReplacementSection); + if (start1 == nullptr || size1 == 0) + return; + void *start2; + uintptr_t size2; + GET_SECTION_START_AND_SIZE(start2, size2, MachOTextSegment, + MachODynamicReplacementSection); + if (start2 == nullptr || size2 == 0) + return; + addImageDynamicReplacementBlockCallback(start1, size1, start2, size2); +} + +#endif // defined(__MACH__) && defined(SWIFT_RUNTIME_MACHO_NO_DYLD) diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index a756dc847d56d..a8e9f2a1b81eb 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -49,6 +49,8 @@ #endif #if SWIFT_PTRAUTH #include +#endif +#if SWIFT_OBJC_INTEROP extern "C" void _objc_setClassCopyFixupHandler(void (* _Nonnull newFixupHandler) (Class _Nonnull oldClass, Class _Nonnull newClass)); #endif @@ -395,7 +397,7 @@ static GenericMetadataCache &unsafeGetInitializedCache( return lazyCache->unsafeGetAlreadyInitialized(); } -#if SWIFT_PTRAUTH +#if SWIFT_PTRAUTH && SWIFT_OBJC_INTEROP static void swift_objc_classCopyFixupHandler(Class oldClass, Class newClass) { auto oldClassMetadata = reinterpret_cast(oldClass); @@ -720,26 +722,89 @@ MetadataResponse swift::swift_getCanonicalSpecializedMetadata( auto &cache = getCache(*description); assert(description->getFullGenericContextHeader().Base.NumKeyArguments == cache.NumKeyParameters + cache.NumWitnessTables); + if (auto *classDescription = dyn_cast(description)) { + auto canonicalMetadataAccessors = classDescription->getCanonicalMetadataPrespecializationAccessors(); + for (auto &canonicalMetadataAccessorPtr : canonicalMetadataAccessors) { + auto *canonicalMetadataAccessor = canonicalMetadataAccessorPtr.get(); + auto response = canonicalMetadataAccessor(request); + auto *canonicalMetadata = response.Value; + const void *const *arguments = + reinterpret_cast(canonicalMetadata->getGenericArgs()); + auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables, + arguments); + auto result = cache.getOrInsert(key, MetadataRequest(MetadataState::Complete, /*isNonBlocking*/true), canonicalMetadata); + assert(result.second.Value == canonicalMetadata); + } + } else { + auto canonicalMetadatas = description->getCanonicicalMetadataPrespecializations(); + for (auto &canonicalMetadataPtr : canonicalMetadatas) { + Metadata *canonicalMetadata = canonicalMetadataPtr.get(); + const void *const *arguments = + reinterpret_cast(canonicalMetadata->getGenericArgs()); + auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables, + arguments); + auto result = cache.getOrInsert(key, MetadataRequest(MetadataState::Complete, /*isNonBlocking*/true), canonicalMetadata); + assert(result.second.Value == canonicalMetadata); + } + } const void *const *arguments = reinterpret_cast(candidate->getGenericArgs()); auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables, arguments); auto result = cache.getOrInsert(key, request, candidate); - assert( - !result.second.Value->isCanonicalStaticallySpecializedGenericMetadata()); - cachedMetadataAddr->store(result.second.Value, std::memory_order_release); return result.second; } +// Look into the canonical prespecialized metadata attached to the type +// descriptor and return matching records, if any. +static Metadata * +findCanonicalSpecializedMetadata(MetadataRequest request, + const void *const *arguments, + const TypeContextDescriptor *description) { + auto &cache = getCache(*description); + auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables, + arguments); + auto prespecializedMetadatas = + description->getCanonicicalMetadataPrespecializations(); + int index = 0; + for (auto &prespecializedMetadataPtr : prespecializedMetadatas) { + Metadata *prespecializationMetadata = prespecializedMetadataPtr.get(); + const void *const *prespecializationArguments = + reinterpret_cast( + prespecializationMetadata->getGenericArgs()); + auto prespecializationKey = + MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables, + prespecializationArguments); + if (key == prespecializationKey) { + if (auto *classDescription = dyn_cast(description)) { + auto canonicalMetadataAccessors = + classDescription->getCanonicalMetadataPrespecializationAccessors(); + auto &canonicalMetadataAccessorPtr = canonicalMetadataAccessors[index]; + auto *canonicalMetadataAccessor = canonicalMetadataAccessorPtr.get(); + auto response = canonicalMetadataAccessor(request); + return const_cast(response.Value); + } else { + return prespecializationMetadata; + } + } + ++index; + } + return nullptr; +} + /// The primary entrypoint. MetadataResponse swift::swift_getGenericMetadata(MetadataRequest request, const void * const *arguments, const TypeContextDescriptor *description) { description = swift_auth_data_non_address(description, SpecialPointerAuthDiscriminators::TypeDescriptor); + if (auto *prespecialization = + findCanonicalSpecializedMetadata(request, arguments, description)) { + return {prespecialization, MetadataState::Complete}; + } auto &cache = getCache(*description); assert(description->getFullGenericContextHeader().Base.NumKeyArguments == cache.NumKeyParameters + cache.NumWitnessTables); @@ -2851,24 +2916,22 @@ getSuperclassMetadata(MetadataRequest request, const ClassMetadata *self) { StringRef superclassName = Demangle::makeSymbolicMangledNameStringRef(superclassNameBase); SubstGenericParametersFromMetadata substitutions(self); - MetadataResponse response = - swift_getTypeByMangledName(request, superclassName, - substitutions.getGenericArgs(), + auto result = swift_getTypeByMangledName( + request, superclassName, substitutions.getGenericArgs(), [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index); }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getResponse(); - auto superclass = response.Value; - if (!superclass) { - fatalError(0, - "failed to demangle superclass of %s from mangled name '%s'\n", - self->getDescription()->Name.get(), - superclassName.str().c_str()); + }); + if (auto *error = result.getError()) { + fatalError( + 0, "failed to demangle superclass of %s from mangled name '%s': %s\n", + self->getDescription()->Name.get(), superclassName.str().c_str(), + error->copyErrorString()); } - return response; + return result.getType().getResponse(); } else { return MetadataResponse(); } @@ -4863,12 +4926,12 @@ swift_getAssociatedTypeWitnessSlowImpl( Demangle::makeSymbolicMangledNameStringRef(mangledNameBase); // Demangle the associated type. - MetadataResponse response; + TypeLookupErrorOr result = TypeInfo(); if (inProtocolContext) { // The protocol's Self is the only generic parameter that can occur in the // type. - response = - swift_getTypeByMangledName(request, mangledName, nullptr, + result = swift_getTypeByMangledName( + request, mangledName, nullptr, [conformingType](unsigned depth, unsigned index) -> const Metadata * { if (depth == 0 && index == 0) return conformingType; @@ -4885,7 +4948,7 @@ swift_getAssociatedTypeWitnessSlowImpl( return swift_getAssociatedConformanceWitness(wtable, conformingType, type, reqBase, dependentDescriptor); - }).getResponse(); + }); } else { // The generic parameters in the associated type name are those of the // conforming type. @@ -4895,29 +4958,30 @@ swift_getAssociatedTypeWitnessSlowImpl( auto originalConformingType = findConformingSuperclass(conformingType, conformance); SubstGenericParametersFromMetadata substitutions(originalConformingType); - response = swift_getTypeByMangledName(request, mangledName, - substitutions.getGenericArgs(), - [&substitutions](unsigned depth, unsigned index) { - return substitutions.getMetadata(depth, index); - }, - [&substitutions](const Metadata *type, unsigned index) { - return substitutions.getWitnessTable(type, index); - }).getResponse(); + result = swift_getTypeByMangledName( + request, mangledName, substitutions.getGenericArgs(), + [&substitutions](unsigned depth, unsigned index) { + return substitutions.getMetadata(depth, index); + }, + [&substitutions](const Metadata *type, unsigned index) { + return substitutions.getWitnessTable(type, index); + }); } + auto *error = result.getError(); + MetadataResponse response = result.getType().getResponse(); auto assocTypeMetadata = response.Value; - - if (!assocTypeMetadata) { + if (error || !assocTypeMetadata) { + const char *errStr = error ? error->copyErrorString() + : "NULL metadata but no error was provided"; auto conformingTypeNameInfo = swift_getTypeName(conformingType, true); StringRef conformingTypeName(conformingTypeNameInfo.data, conformingTypeNameInfo.length); StringRef assocTypeName = findAssociatedTypeName(protocol, assocType); fatalError(0, "failed to demangle witness for associated type '%s' in " - "conformance '%s: %s' from mangled name '%s'\n", - assocTypeName.str().c_str(), - conformingTypeName.str().c_str(), - protocol->Name.get(), - mangledName.str().c_str()); + "conformance '%s: %s' from mangled name '%s' - %s\n", + assocTypeName.str().c_str(), conformingTypeName.str().c_str(), + protocol->Name.get(), mangledName.str().c_str(), errStr); } assert((uintptr_t(assocTypeMetadata) & @@ -5870,7 +5934,7 @@ void swift::verifyMangledNameRoundtrip(const Metadata *metadata) { nullptr, [](unsigned, unsigned){ return nullptr; }, [](const Metadata *, unsigned) { return nullptr; }) - .getMetadata(); + .getType().getMetadata(); if (metadata != result) swift::warning(RuntimeErrorFlagNone, "Metadata mangled name failed to roundtrip: %p -> %s -> %p\n", diff --git a/stdlib/public/runtime/MetadataCache.h b/stdlib/public/runtime/MetadataCache.h index 6e471273e4702..d6f188f971e3c 100644 --- a/stdlib/public/runtime/MetadataCache.h +++ b/stdlib/public/runtime/MetadataCache.h @@ -775,10 +775,22 @@ class MetadataCacheEntryBase using super::asImpl; private: + #ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + using ThreadID = int; + static ThreadID CurrentThreadID() { + return 0; + } + #else + using ThreadID = std::thread::id; + static ThreadID CurrentThreadID() { + return std::this_thread::get_id(); + } + #endif + /// Additional storage that is only ever accessed under the lock. union LockedStorage_t { /// The thread that is allocating the entry. - std::thread::id AllocatingThread; + ThreadID AllocatingThread; /// The completion queue. MetadataCompletionQueueEntry *CompletionQueue; @@ -837,7 +849,7 @@ class MetadataCacheEntryBase MetadataCacheEntryBase() : LockedStorageKind(LSK::AllocatingThread), TrackingInfo(PrivateMetadataTrackingInfo::initial().getRawValue()) { - LockedStorage.AllocatingThread = std::this_thread::get_id(); + LockedStorage.AllocatingThread = CurrentThreadID(); } // Note that having an explicit destructor here is important to make this @@ -850,7 +862,7 @@ class MetadataCacheEntryBase bool isBeingAllocatedByCurrentThread() const { return LockedStorageKind == LSK::AllocatingThread && - LockedStorage.AllocatingThread == std::this_thread::get_id(); + LockedStorage.AllocatingThread == CurrentThreadID(); } /// Given that this thread doesn't own the right to initialize the diff --git a/stdlib/public/runtime/MetadataImpl.h b/stdlib/public/runtime/MetadataImpl.h index 1b12fc1000f26..ac455a8cc9938 100644 --- a/stdlib/public/runtime/MetadataImpl.h +++ b/stdlib/public/runtime/MetadataImpl.h @@ -136,7 +136,7 @@ template struct RetainableBoxBase { static constexpr size_t stride = sizeof(T); static constexpr bool isPOD = false; static constexpr bool isBitwiseTakable = true; -#ifdef SWIFT_STDLIB_USE_NONATOMIC_RC +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME static constexpr bool isAtomic = false; #else static constexpr bool isAtomic = true; diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 93ed4227928eb..fef3ff3f82e76 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -961,13 +961,56 @@ getLocalGenericParams(const ContextDescriptor *context) { return genericContext->getGenericParams().slice(startParamIndex); } -static bool +static llvm::Optional _gatherGenericParameters(const ContextDescriptor *context, llvm::ArrayRef genericArgs, const Metadata *parent, llvm::SmallVectorImpl &genericParamCounts, llvm::SmallVectorImpl &allGenericArgsVec, Demangler &demangler) { + auto makeCommonErrorStringGetter = [&] { + auto metadataVector = genericArgs.vec(); + return [=] { + std::string str; + + str += "_gatherGenericParameters: context: "; + +#if !defined(SWIFT_RUNTIME_MACHO_NO_DYLD) + SymbolInfo contextInfo; + if (lookupSymbol(context, &contextInfo)) { + str += contextInfo.symbolName.get(); + str += " "; + } +#endif + + char *contextStr; + swift_asprintf(&contextStr, "%p", context); + str += contextStr; + free(contextStr); + + str += " <"; + + bool first = true; + for (const Metadata *metadata : genericArgs) { + if (!first) + str += ", "; + first = false; + str += nameForMetadata(metadata); + } + + str += "> "; + + str += "parent: "; + if (parent) + str += nameForMetadata(parent); + else + str += ""; + str += " - "; + + return str; + }; + }; + // Figure out the various levels of generic parameters we have in // this type. (void)_gatherGenericParameterCounts(context, @@ -981,7 +1024,15 @@ _gatherGenericParameters(const ContextDescriptor *context, } else if (genericArgs.size() == numTotalGenericParams && !parent) { // Okay: genericArgs is the complete set of generic arguments. } else { - return false; + auto commonString = makeCommonErrorStringGetter(); + auto genericArgsSize = genericArgs.size(); + return TypeLookupError([=] { + return commonString() + "incorrect number of generic args (" + + std::to_string(genericArgsSize) + "), " + + std::to_string(getLocalGenericParams(context).size()) + + " local params, " + std::to_string(numTotalGenericParams) + + " total params"; + }); } // If there are generic parameters at any level, check the generic @@ -1008,15 +1059,30 @@ _gatherGenericParameters(const ContextDescriptor *context, auto genericParams = generics->getGenericParams(); unsigned n = genericParams.size(); if (allGenericArgs.size() != n) { - return false; + auto commonString = makeCommonErrorStringGetter(); + auto argsVecSize = allGenericArgsVec.size(); + return TypeLookupError([=] { + return commonString() + "have " + std::to_string(argsVecSize) + + "generic args, expected " + std::to_string(n); + }); } for (unsigned i = 0; i != n; ++i) { const auto ¶m = genericParams[i]; - if (param.getKind() != GenericParamKind::Type) - return false; - if (param.hasExtraArgument()) - return false; - + if (param.getKind() != GenericParamKind::Type) { + auto commonString = makeCommonErrorStringGetter(); + return TypeLookupError([=] { + return commonString() + "param " + std::to_string(i) + + " has unexpected kind " + + std::to_string(static_cast(param.getKind())); + }); + } + if (param.hasExtraArgument()) { + auto commonString = makeCommonErrorStringGetter(); + return TypeLookupError([=] { + return commonString() + "param " + std::to_string(i) + + "has extra argument"; + }); + } if (param.hasKeyArgument()) allGenericArgsVec.push_back(allGenericArgs[i]); } @@ -1028,26 +1094,33 @@ _gatherGenericParameters(const ContextDescriptor *context, // any extra arguments we need for the instantiation function. SubstGenericParametersFromWrittenArgs substitutions(allGenericArgs, genericParamCounts); - bool failed = - _checkGenericRequirements(generics->getGenericRequirements(), - allGenericArgsVec, + auto error = _checkGenericRequirements( + generics->getGenericRequirements(), allGenericArgsVec, [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index); }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); }); - if (failed) - return false; + if (error) + return *error; // If we still have the wrong number of generic arguments, this is // some kind of metadata mismatch. if (generics->getGenericContextHeader().getNumArguments() != - allGenericArgsVec.size()) - return false; + allGenericArgsVec.size()) { + auto commonString = makeCommonErrorStringGetter(); + auto argsVecSize = allGenericArgsVec.size(); + return TypeLookupError([=] { + return commonString() + "generic argument count mismatch, expected " + + std::to_string( + generics->getGenericContextHeader().getNumArguments()) + + ", have " + std::to_string(argsVecSize); + }); + } } - return true; + return llvm::None; } namespace { @@ -1175,7 +1248,7 @@ class DecodedMetadataBuilder { Demangle::NodeFactory &getNodeFactory() { return demangler; } - BuiltType + TypeLookupErrorOr resolveOpaqueType(NodePointer opaqueDecl, llvm::ArrayRef> genericArgs, unsigned ordinal) { @@ -1193,12 +1266,10 @@ class DecodedMetadataBuilder { llvm::SmallVector genericParamCounts; llvm::SmallVector allGenericArgsVec; - if (!_gatherGenericParameters(outerContext, - allGenericArgs, - BuiltType(), /* no parent */ - genericParamCounts, allGenericArgsVec, - demangler)) - return BuiltType(); + if (auto error = _gatherGenericParameters( + outerContext, allGenericArgs, BuiltType(), /* no parent */ + genericParamCounts, allGenericArgsVec, demangler)) + return *error; auto mangledName = descriptor->getUnderlyingTypeArgument(ordinal); SubstGenericParametersFromMetadata substitutions(descriptor, @@ -1210,7 +1281,7 @@ class DecodedMetadataBuilder { }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } BuiltTypeDecl createTypeDecl(NodePointer node, @@ -1245,8 +1316,9 @@ class DecodedMetadataBuilder { return ProtocolDescriptorRef(); #endif } - - BuiltType createObjCClassType(const std::string &mangledName) const { + + TypeLookupErrorOr + createObjCClassType(const std::string &mangledName) const { #if SWIFT_OBJC_INTEROP auto objcClass = objc_getClass(mangledName.c_str()); return swift_getObjCClassMetadata((const ClassMetadata *)objcClass); @@ -1255,7 +1327,7 @@ class DecodedMetadataBuilder { #endif } - BuiltType + TypeLookupErrorOr createBoundGenericObjCClassType(const std::string &mangledName, llvm::ArrayRef args) const { // Generic arguments of lightweight Objective-C generic classes are not @@ -1263,24 +1335,25 @@ class DecodedMetadataBuilder { return createObjCClassType(mangledName); } - BuiltType createNominalType(BuiltTypeDecl metadataOrTypeDecl, - BuiltType parent) const { + TypeLookupErrorOr + createNominalType(BuiltTypeDecl metadataOrTypeDecl, BuiltType parent) const { // Treat nominal type creation the same way as generic type creation, // but with no generic arguments at this level. return createBoundGenericType(metadataOrTypeDecl, { }, parent); } - BuiltType createTypeAliasType(BuiltTypeDecl typeAliasDecl, - BuiltType parent) const { + TypeLookupErrorOr createTypeAliasType(BuiltTypeDecl typeAliasDecl, + BuiltType parent) const { // We can't support sugared types here since we have no way to // resolve the underlying type of the type alias. However, some // CF types are mangled as type aliases. return createNominalType(typeAliasDecl, parent); } - BuiltType createBoundGenericType(BuiltTypeDecl anyTypeDecl, - llvm::ArrayRef genericArgs, - BuiltType parent) const { + TypeLookupErrorOr + createBoundGenericType(BuiltTypeDecl anyTypeDecl, + llvm::ArrayRef genericArgs, + BuiltType parent) const { auto typeDecl = dyn_cast(anyTypeDecl); if (!typeDecl) { if (auto protocol = dyn_cast(anyTypeDecl)) @@ -1294,13 +1367,11 @@ class DecodedMetadataBuilder { llvm::SmallVector genericParamCounts; llvm::SmallVector allGenericArgsVec; - if (!_gatherGenericParameters(typeDecl, - genericArgs, - parent, - genericParamCounts, allGenericArgsVec, - demangler)) - return BuiltType(); - + if (auto error = _gatherGenericParameters(typeDecl, genericArgs, parent, + genericParamCounts, + allGenericArgsVec, demangler)) + return *error; + // Call the access function. auto accessFunction = typeDecl->getAccessFunction(); if (!accessFunction) return BuiltType(); @@ -1308,8 +1379,8 @@ class DecodedMetadataBuilder { return accessFunction(MetadataState::Abstract, allGenericArgsVec).Value; } - BuiltType createBuiltinType(StringRef builtinName, - StringRef mangledName) const { + TypeLookupErrorOr createBuiltinType(StringRef builtinName, + StringRef mangledName) const { #define BUILTIN_TYPE(Symbol, _) \ if (mangledName.equals(#Symbol)) \ return &METADATA_SYM(Symbol).base; @@ -1317,19 +1388,19 @@ class DecodedMetadataBuilder { return BuiltType(); } - BuiltType createMetatypeType( + TypeLookupErrorOr createMetatypeType( BuiltType instance, llvm::Optional repr = None) const { return swift_getMetatypeMetadata(instance); } - BuiltType createExistentialMetatypeType( + TypeLookupErrorOr createExistentialMetatypeType( BuiltType instance, llvm::Optional repr = None) const { return swift_getExistentialMetatypeMetadata(instance); } - BuiltType + TypeLookupErrorOr createProtocolCompositionType(llvm::ArrayRef protocols, BuiltType superclass, bool isClassBound) const { // Determine whether we have a class bound. @@ -1349,13 +1420,13 @@ class DecodedMetadataBuilder { protocols.size(), protocols.data()); } - BuiltType createDynamicSelfType(BuiltType selfType) const { + TypeLookupErrorOr createDynamicSelfType(BuiltType selfType) const { // Free-standing mangled type strings should not contain DynamicSelfType. return BuiltType(); } - BuiltType createGenericTypeParameterType(unsigned depth, - unsigned index) const { + TypeLookupErrorOr + createGenericTypeParameterType(unsigned depth, unsigned index) const { // Use the callback, when provided. if (substGenericParameter) return substGenericParameter(depth, index); @@ -1363,7 +1434,7 @@ class DecodedMetadataBuilder { return BuiltType(); } - BuiltType + TypeLookupErrorOr createFunctionType(llvm::ArrayRef> params, BuiltType result, FunctionTypeFlags flags) const { llvm::SmallVector paramTypes; @@ -1386,7 +1457,7 @@ class DecodedMetadataBuilder { result); } - BuiltType createImplFunctionType( + TypeLookupErrorOr createImplFunctionType( Demangle::ImplParameterConvention calleeConvention, llvm::ArrayRef> params, llvm::ArrayRef> results, @@ -1396,8 +1467,9 @@ class DecodedMetadataBuilder { return BuiltType(); } - BuiltType createTupleType(llvm::ArrayRef elements, - std::string labels) const { + TypeLookupErrorOr + createTupleType(llvm::ArrayRef elements, + std::string labels) const { auto flags = TupleTypeFlags().withNumElements(elements.size()); if (!labels.empty()) flags = flags.withNonConstantLabels(true); @@ -1408,13 +1480,15 @@ class DecodedMetadataBuilder { .Value; } - BuiltType createDependentMemberType(StringRef name, BuiltType base) const { + TypeLookupErrorOr createDependentMemberType(StringRef name, + BuiltType base) const { // Should not have unresolved dependent member types here. return BuiltType(); } - BuiltType createDependentMemberType(StringRef name, BuiltType base, - BuiltProtocolDecl protocol) const { + TypeLookupErrorOr + createDependentMemberType(StringRef name, BuiltType base, + BuiltProtocolDecl protocol) const { #if SWIFT_OBJC_INTEROP if (protocol.isObjC()) return BuiltType(); @@ -1438,14 +1512,14 @@ class DecodedMetadataBuilder { *assocType).Value; } -#define REF_STORAGE(Name, ...) \ - BuiltType create##Name##StorageType(BuiltType base) { \ - ReferenceOwnership.set##Name(); \ - return base; \ +#define REF_STORAGE(Name, ...) \ + TypeLookupErrorOr create##Name##StorageType(BuiltType base) { \ + ReferenceOwnership.set##Name(); \ + return base; \ } #include "swift/AST/ReferenceStorage.def" - BuiltType createSILBoxType(BuiltType base) const { + TypeLookupErrorOr createSILBoxType(BuiltType base) const { // FIXME: Implement. return BuiltType(); } @@ -1454,22 +1528,23 @@ class DecodedMetadataBuilder { return ReferenceOwnership; } - BuiltType createOptionalType(BuiltType base) { + TypeLookupErrorOr createOptionalType(BuiltType base) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } - BuiltType createArrayType(BuiltType base) { + TypeLookupErrorOr createArrayType(BuiltType base) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } - BuiltType createDictionaryType(BuiltType key, BuiltType value) { + TypeLookupErrorOr createDictionaryType(BuiltType key, + BuiltType value) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } - BuiltType createParenType(BuiltType base) { + TypeLookupErrorOr createParenType(BuiltType base) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } @@ -1478,13 +1553,12 @@ class DecodedMetadataBuilder { } SWIFT_CC(swift) -static TypeInfo swift_getTypeByMangledNodeImpl( - MetadataRequest request, - Demangler &demangler, - Demangle::NodePointer node, - const void * const *origArgumentVector, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable) { +static TypeLookupErrorOr +swift_getTypeByMangledNodeImpl(MetadataRequest request, Demangler &demangler, + Demangle::NodePointer node, + const void *const *origArgumentVector, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable) { // Simply call an accessor function if that's all we got. if (node->getKind() == Node::Kind::AccessorFunctionReference) { // The accessor function is passed the pointer to the original argument @@ -1504,22 +1578,23 @@ static TypeInfo swift_getTypeByMangledNodeImpl( DecodedMetadataBuilder builder(demangler, substGenericParam, substWitnessTable); auto type = Demangle::decodeMangledType(builder, node); - if (!type) { - return {MetadataResponse{nullptr, MetadataState::Complete}, - TypeReferenceOwnership()}; + if (type.isError()) { + return *type.getError(); + } + if (!type.getType()) { + return TypeLookupError("NULL type but no error provided"); } - return {swift_checkMetadataState(request, type), - builder.getReferenceOwnership()}; + return TypeInfo{swift_checkMetadataState(request, type.getType()), + builder.getReferenceOwnership()}; } SWIFT_CC(swift) -static TypeInfo swift_getTypeByMangledNameImpl( - MetadataRequest request, - StringRef typeName, - const void * const *origArgumentVector, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable) { +static TypeLookupErrorOr +swift_getTypeByMangledNameImpl(MetadataRequest request, StringRef typeName, + const void *const *origArgumentVector, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable) { DemanglerForRuntimeTypeResolution> demangler; NodePointer node; @@ -1587,7 +1662,7 @@ swift_getTypeByMangledNameInEnvironment( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1607,7 +1682,7 @@ swift_getTypeByMangledNameInEnvironmentInMetadataState( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1626,7 +1701,7 @@ swift_getTypeByMangledNameInContext( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1646,7 +1721,7 @@ swift_getTypeByMangledNameInContextInMetadataState( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } /// Demangle a mangled name, but don't allow symbolic references. @@ -1661,7 +1736,7 @@ swift_stdlib_getTypeByMangledNameUntrusted(const char *typeNameStart, } return swift_getTypeByMangledName(MetadataState::Complete, typeName, nullptr, - {}, {}).getMetadata(); + {}, {}).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1680,7 +1755,7 @@ swift_getOpaqueTypeMetadata(MetadataRequest request, }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getResponse(); + }).getType().getResponse(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1735,7 +1810,7 @@ getObjCClassByMangledName(const char * _Nonnull typeName, }, [&](const Metadata *type, unsigned index) { return nullptr; - }).getMetadata(); + }).getType().getMetadata(); } else { metadata = swift_stdlib_getTypeByMangledNameUntrusted(typeStr.data(), typeStr.size()); @@ -2068,7 +2143,7 @@ void swift::gatherWrittenGenericArgs( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); continue; } diff --git a/stdlib/public/runtime/MutexPThread.cpp b/stdlib/public/runtime/MutexPThread.cpp index 92db58226cd09..ac7f93a5a0ed8 100644 --- a/stdlib/public/runtime/MutexPThread.cpp +++ b/stdlib/public/runtime/MutexPThread.cpp @@ -15,7 +15,11 @@ // //===----------------------------------------------------------------------===// -#if !defined(_WIN32) && !defined(__wasi__) +#if __has_include() +#include +#endif + +#if defined(_POSIX_THREADS) && !defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) #include "swift/Runtime/Mutex.h" #include "swift/Runtime/Debug.h" diff --git a/stdlib/public/runtime/MutexWASI.cpp b/stdlib/public/runtime/MutexWASI.cpp deleted file mode 100644 index 6288ecce03449..0000000000000 --- a/stdlib/public/runtime/MutexWASI.cpp +++ /dev/null @@ -1,25 +0,0 @@ -//===--- MutexWin32.cpp - -------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// Mutex, ConditionVariable, Read/Write lock, and Scoped lock implementations -// using Windows Slim Reader/Writer Locks and Conditional Variables. -// -//===----------------------------------------------------------------------===// - -#if defined(__wasi__) -#include "swift/Runtime/Mutex.h" - -using namespace swift; - -void ConditionPlatformHelper::wait(void* &condition, - void* &mutex) {} -#endif diff --git a/stdlib/public/runtime/Once.cpp b/stdlib/public/runtime/Once.cpp index 7554d5d4ae751..1460b0603ef17 100644 --- a/stdlib/public/runtime/Once.cpp +++ b/stdlib/public/runtime/Once.cpp @@ -21,7 +21,11 @@ using namespace swift; -#ifdef __APPLE__ +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + +// No dependencies on single-threaded environments. + +#elif defined(__APPLE__) // On macOS and iOS, swift_once is implemented using GCD. // The compiler emits an inline check matching the barrier-free inline fast @@ -48,27 +52,12 @@ static_assert(sizeof(swift_once_t) <= sizeof(void*), /// extent of type swift_once_t. void swift::swift_once(swift_once_t *predicate, void (*fn)(void *), void *context) { -#if defined(__APPLE__) - dispatch_once_f(predicate, context, fn); -#elif defined(__CYGWIN__) - _swift_once_f(predicate, context, fn); -#elif defined(__wasm__) - // WebAssembly: hack: Swift compiler passes in a fn that doesn't take a parameter, - // which is invalid in WebAssembly. So swift_once casts the function. - // The correct way to fix this is to change - // SILGenModule::emitLazyGlobalInitializer - // but this is OK as a proof of concept. - // Keep a copy of the unmodified swift_once function below. - std::call_once(*predicate, [fn, context]() { ((void (*)())fn)(); }); -#else - std::call_once(*predicate, [fn, context]() { fn(context); }); -#endif -} - -#ifdef __wasm__ -void swift::swift_once_real(swift_once_t *predicate, void (*fn)(void *), - void *context) { -#if defined(__APPLE__) +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + if (! *predicate) { + *predicate = true; + fn(context); + } +#elif defined(__APPLE__) dispatch_once_f(predicate, context, fn); #elif defined(__CYGWIN__) _swift_once_f(predicate, context, fn); @@ -76,4 +65,3 @@ void swift::swift_once_real(swift_once_t *predicate, void (*fn)(void *), std::call_once(*predicate, [fn, context]() { fn(context); }); #endif } -#endif diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h index 4be3fb6bdb025..2f5e7232cc55d 100644 --- a/stdlib/public/runtime/Private.h +++ b/stdlib/public/runtime/Private.h @@ -17,7 +17,10 @@ #ifndef SWIFT_RUNTIME_PRIVATE_H #define SWIFT_RUNTIME_PRIVATE_H +#include + #include "swift/Demangling/Demangler.h" +#include "swift/Demangling/TypeLookupError.h" #include "swift/Runtime/Config.h" #include "swift/Runtime/Metadata.h" @@ -77,6 +80,8 @@ class TypeInfo { const Metadata *getMetadata() const { return Response.Value; } MetadataResponse getResponse() const { return Response; } + operator bool() const { return getMetadata(); } + #define REF_STORAGE(Name, ...) \ bool is##Name() const { return ReferenceOwnership.is##Name(); } #include "swift/AST/ReferenceStorage.def" @@ -211,7 +216,7 @@ class TypeInfo { static inline bool objectUsesNativeSwiftReferenceCounting(const void *object) { assert(!isObjCTaggedPointerOrNull(object)); -#if SWIFT_HAS_OPAQUE_ISAS +#if SWIFT_OBJC_INTEROP && SWIFT_HAS_OPAQUE_ISAS // Fast path for opaque ISAs. We don't want to call // _swift_getClassOfAllocated as that will call object_getClass. // Instead we can look at the bits in the ISA and tell if its a @@ -369,7 +374,7 @@ class TypeInfo { /// \p substWitnessTable Function that provides witness tables given a /// particular dependent conformance index. SWIFT_CC(swift) - TypeInfo swift_getTypeByMangledNode( + TypeLookupErrorOr swift_getTypeByMangledNode( MetadataRequest request, Demangler &demangler, Demangle::NodePointer node, @@ -384,7 +389,7 @@ class TypeInfo { /// \p substWitnessTable Function that provides witness tables given a /// particular dependent conformance index. SWIFT_CC(swift) - TypeInfo swift_getTypeByMangledName( + TypeLookupErrorOr swift_getTypeByMangledName( MetadataRequest request, StringRef typeName, const void * const *arguments, @@ -447,12 +452,12 @@ class TypeInfo { /// generic requirements (e.g., those that need to be /// passed to an instantiation function) will be added to this vector. /// - /// \returns true if an error occurred, false otherwise. - bool _checkGenericRequirements( - llvm::ArrayRef requirements, - llvm::SmallVectorImpl &extraArguments, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable); + /// \returns the error if an error occurred, None otherwise. + llvm::Optional _checkGenericRequirements( + llvm::ArrayRef requirements, + llvm::SmallVectorImpl &extraArguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable); /// A helper function which avoids performing a store if the destination /// address already contains the source value. This is useful when diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp index 1a80b2e08e039..c434011faea85 100644 --- a/stdlib/public/runtime/ProtocolConformance.cpp +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -165,15 +165,16 @@ ProtocolConformanceDescriptor::getWitnessTable(const Metadata *type) const { llvm::SmallVector conditionalArgs; if (hasConditionalRequirements()) { SubstGenericParametersFromMetadata substitutions(type); - bool failed = - _checkGenericRequirements(getConditionalRequirements(), conditionalArgs, + auto error = _checkGenericRequirements( + getConditionalRequirements(), conditionalArgs, [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index); }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); }); - if (failed) return nullptr; + if (error) + return nullptr; } return swift_getWitnessTable(this, type, conditionalArgs.data()); @@ -198,31 +199,27 @@ namespace { : Type(type), Proto(proto) { assert(type); } + + friend llvm::hash_code hash_value(const ConformanceCacheKey &key) { + return llvm::hash_combine(key.Type, key.Proto); + } }; struct ConformanceCacheEntry { private: - const Metadata *Type; - const ProtocolDescriptor *Proto; - std::atomic Description; - std::atomic FailureGeneration; + ConformanceCacheKey Key; + const WitnessTable *Witness; public: - ConformanceCacheEntry(ConformanceCacheKey key, - const ProtocolConformanceDescriptor *description, - size_t failureGeneration) - : Type(key.Type), Proto(key.Proto), Description(description), - FailureGeneration(failureGeneration) { + ConformanceCacheEntry(ConformanceCacheKey key, const WitnessTable *witness) + : Key(key), Witness(witness) {} + + bool matchesKey(const ConformanceCacheKey &key) const { + return Key.Type == key.Type && Key.Proto == key.Proto; } - int compareWithKey(const ConformanceCacheKey &key) const { - if (key.Type != Type) { - return (uintptr_t(key.Type) < uintptr_t(Type) ? -1 : 1); - } else if (key.Proto != Proto) { - return (uintptr_t(key.Proto) < uintptr_t(Proto) ? -1 : 1); - } else { - return 0; - } + friend llvm::hash_code hash_value(const ConformanceCacheEntry &entry) { + return hash_value(entry.Key); } template @@ -230,69 +227,54 @@ namespace { return 0; } - bool isSuccessful() const { - return Description.load(std::memory_order_relaxed) != nullptr; - } - - void makeSuccessful(const ProtocolConformanceDescriptor *description) { - Description.store(description, std::memory_order_release); - } - - void updateFailureGeneration(size_t failureGeneration) { - assert(!isSuccessful()); - FailureGeneration.store(failureGeneration, std::memory_order_relaxed); - } - - /// Get the cached conformance descriptor, if successful. - const ProtocolConformanceDescriptor *getDescription() const { - assert(isSuccessful()); - return Description.load(std::memory_order_acquire); - } - - /// Get the generation in which this lookup failed. - size_t getFailureGeneration() const { - assert(!isSuccessful()); - return FailureGeneration.load(std::memory_order_relaxed); + /// Get the cached witness table, or null if we cached failure. + const WitnessTable *getWitnessTable() const { + return Witness; } }; } // end anonymous namespace // Conformance Cache. struct ConformanceState { - ConcurrentMap Cache; + ConcurrentReadableHashMap Cache; ConcurrentReadableArray SectionsToScan; ConformanceState() { initializeProtocolConformanceLookup(); } - void cacheSuccess(const Metadata *type, const ProtocolDescriptor *proto, - const ProtocolConformanceDescriptor *description) { - auto result = Cache.getOrInsert(ConformanceCacheKey(type, proto), - description, 0); - - // If the entry was already present, we may need to update it. - if (!result.second) { - result.first->makeSuccessful(description); - } - } - - void cacheFailure(const Metadata *type, const ProtocolDescriptor *proto, - size_t failureGeneration) { - auto result = - Cache.getOrInsert(ConformanceCacheKey(type, proto), - (const ProtocolConformanceDescriptor *) nullptr, - failureGeneration); - - // If the entry was already present, we may need to update it. - if (!result.second) { - result.first->updateFailureGeneration(failureGeneration); - } - } - - ConformanceCacheEntry *findCached(const Metadata *type, - const ProtocolDescriptor *proto) { - return Cache.find(ConformanceCacheKey(type, proto)); + void cacheResult(const Metadata *type, const ProtocolDescriptor *proto, + const WitnessTable *witness, size_t sectionsCount) { + Cache.getOrInsert(ConformanceCacheKey(type, proto), + [&](ConformanceCacheEntry *entry, bool created) { + // Create the entry if needed. If it already exists, + // we're done. + if (!created) + return false; + + // Check the current sections count against what was + // passed in. If a section count was passed in and they + // don't match, then this is not an authoritative entry + // and it may have been obsoleted, because the new + // sections could contain a conformance in a more + // specific type. + // + // If they DO match, then we can safely add. Another + // thread might be adding new sections at this point, + // but we will not race with them. That other thread + // will add the new sections, then clear the cache. When + // it clears the cache, it will block waiting for this + // code to complete and relinquish Cache's writer lock. + // If we cache a stale entry, it will be immediately + // cleared. + if (sectionsCount > 0 && + SectionsToScan.snapshot().count() != sectionsCount) + return false; // abandon the new entry + + new (entry) ConformanceCacheEntry( + ConformanceCacheKey(type, proto), witness); + return true; // keep the new entry + }); } #ifndef NDEBUG @@ -323,6 +305,10 @@ _registerProtocolConformances(ConformanceState &C, const ProtocolConformanceRecord *begin, const ProtocolConformanceRecord *end) { C.SectionsToScan.push_back(ConformanceSection{begin, end}); + + // Blow away the conformances cache to get rid of any negative entries that + // may now be obsolete. + C.Cache.clear(); } void swift::addImageProtocolConformanceBlockCallbackUnsafe( @@ -357,98 +343,29 @@ swift::swift_registerProtocolConformances(const ProtocolConformanceRecord *begin _registerProtocolConformances(C, begin, end); } - -struct ConformanceCacheResult { - // true if description is an authoritative result as-is. - // false if more searching is required (for example, because a cached - // failure was returned in failureEntry but it is out-of-date. - bool isAuthoritative; - - // The matching conformance descriptor, or null if no cached conformance - // was found. - const ProtocolConformanceDescriptor *description; - - // If the search fails, this may be the negative cache entry for the - // queried type itself. This entry may be null or out-of-date. - ConformanceCacheEntry *failureEntry; - - static ConformanceCacheResult - cachedSuccess(const ProtocolConformanceDescriptor *description) { - return ConformanceCacheResult { true, description, nullptr }; - } - - static ConformanceCacheResult - cachedFailure(ConformanceCacheEntry *entry, bool auth) { - return ConformanceCacheResult { auth, nullptr, entry }; - } - - static ConformanceCacheResult - cacheMiss() { - return ConformanceCacheResult { false, nullptr, nullptr }; - } -}; - /// Search for a conformance descriptor in the ConformanceCache. -static -ConformanceCacheResult +/// First element of the return value is `true` if the result is authoritative +/// i.e. the result is for the type itself and not a superclass. If `false` +/// then we cached a conformance on a superclass, but that may be overridden. +/// A return value of `{ false, nullptr }` indicates nothing was cached. +static std::pair searchInConformanceCache(const Metadata *type, const ProtocolDescriptor *protocol) { auto &C = Conformances.get(); auto origType = type; - ConformanceCacheEntry *failureEntry = nullptr; - -recur: - { - // Try the specific type first. - if (auto *Value = C.findCached(type, protocol)) { - if (Value->isSuccessful()) { - // Found a conformance on the type or some superclass. Return it. - return ConformanceCacheResult::cachedSuccess(Value->getDescription()); - } - - // Found a negative cache entry. - - bool isAuthoritative; - if (type == origType) { - // This negative cache entry is for the original query type. - // Remember it so it can be returned later. - failureEntry = Value; - // An up-to-date entry for the original type is authoritative. - isAuthoritative = true; - } else { - // An up-to-date cached failure for a superclass of the type is not - // authoritative: there may be a still-undiscovered conformance - // for the original query type. - isAuthoritative = false; - } + auto snapshot = C.Cache.snapshot(); - // Check if the negative cache entry is up-to-date. - if (Value->getFailureGeneration() == C.SectionsToScan.snapshot().count()) { - // Negative cache entry is up-to-date. Return failure along with - // the original query type's own cache entry, if we found one. - // (That entry may be out of date but the caller still has use for it.) - return ConformanceCacheResult::cachedFailure(failureEntry, - isAuthoritative); - } - - // Negative cache entry is out-of-date. - // Continue searching for a better result. + while (type) { + if (auto *Value = snapshot.find(ConformanceCacheKey(type, protocol))) { + return {type == origType, Value->getWitnessTable()}; } - } - // If there is a superclass, look there. - if (auto superclass = _swift_class_getSuperclass(type)) { - type = superclass; - goto recur; + // If there is a superclass, look there. + type = _swift_class_getSuperclass(type); } - // We did not find an up-to-date cache entry. - // If we found an out-of-date entry for the original query type then - // return it (non-authoritatively). Otherwise return a cache miss. - if (failureEntry) - return ConformanceCacheResult::cachedFailure(failureEntry, false); - else - return ConformanceCacheResult::cacheMiss(); + // We did not find a cache entry. + return {false, nullptr}; } namespace { @@ -477,14 +394,6 @@ namespace { } } - /// Retrieve the conforming type as metadata, or NULL if the candidate's - /// conforming type is described in another way (e.g., a nominal type - /// descriptor). - const Metadata *getConformingTypeAsMetadata() const { - return candidateIsMetadata ? static_cast(candidate) - : nullptr; - } - const ContextDescriptor * getContextDescriptor(const Metadata *conformingType) const { const auto *description = conformingType->getTypeContextDescriptor(); @@ -544,40 +453,21 @@ namespace { }; } -static const ProtocolConformanceDescriptor * -swift_conformsToSwiftProtocolImpl(const Metadata * const type, - const ProtocolDescriptor *protocol, - StringRef module) { +static const WitnessTable * +swift_conformsToProtocolImpl(const Metadata *const type, + const ProtocolDescriptor *protocol) { auto &C = Conformances.get(); - // See if we have a cached conformance. The ConcurrentMap data structure - // allows us to insert and search the map concurrently without locking. - auto FoundConformance = searchInConformanceCache(type, protocol); - // If the result (positive or negative) is authoritative, return it. - if (FoundConformance.isAuthoritative) - return FoundConformance.description; - - auto failureEntry = FoundConformance.failureEntry; + // See if we have an authoritative cached conformance. The + // ConcurrentReadableHashMap data structure allows us to search the map + // concurrently without locking. + auto found = searchInConformanceCache(type, protocol); + if (found.first) + return found.second; - // Prepare to scan conformance records. + // Scan conformance records. auto snapshot = C.SectionsToScan.snapshot(); - - // Scan only sections that were not scanned yet. - // If we found an out-of-date negative cache entry, - // we need not to re-scan the sections that it covers. - auto startIndex = failureEntry ? failureEntry->getFailureGeneration() : 0; - auto endIndex = snapshot.count(); - - // If there are no unscanned sections outstanding - // then we can cache failure and give up now. - if (startIndex == endIndex) { - C.cacheFailure(type, protocol, snapshot.count()); - return nullptr; - } - - // Really scan conformance records. - for (size_t i = startIndex; i < endIndex; ++i) { - auto §ion = snapshot.Start[i]; + for (auto §ion : snapshot) { // Eagerly pull records for nondependent witnesses into our cache. for (const auto &record : section) { auto &descriptor = *record.get(); @@ -586,40 +476,25 @@ swift_conformsToSwiftProtocolImpl(const Metadata * const type, if (descriptor.getProtocol() != protocol) continue; - // If there's a matching type, record the positive result. + // If there's a matching type, record the positive result and return it. + // The matching type is exact, so they can't go stale, and we should + // always cache them. ConformanceCandidate candidate(descriptor); - if (candidate.getMatchingType(type)) { - const Metadata *matchingType = candidate.getConformingTypeAsMetadata(); - if (!matchingType) - matchingType = type; - - C.cacheSuccess(matchingType, protocol, &descriptor); + if (auto *matchingType = candidate.getMatchingType(type)) { + auto witness = descriptor.getWitnessTable(matchingType); + C.cacheResult(matchingType, protocol, witness, /*always cache*/ 0); } } } - - // Conformance scan is complete. - - // Search the cache once more, and this time update the cache if necessary. - FoundConformance = searchInConformanceCache(type, protocol); - if (FoundConformance.isAuthoritative) { - return FoundConformance.description; - } else { - C.cacheFailure(type, protocol, snapshot.count()); - return nullptr; - } -} -static const WitnessTable * -swift_conformsToProtocolImpl(const Metadata * const type, - const ProtocolDescriptor *protocol) { - auto description = - swift_conformsToSwiftProtocol(type, protocol, StringRef()); - if (!description) - return nullptr; + // Try the search again to look for the most specific cached conformance. + found = searchInConformanceCache(type, protocol); + + // If it's not authoritative, then add an authoritative entry for this type. + if (!found.first) + C.cacheResult(type, protocol, found.second, snapshot.count()); - return description->getWitnessTable( - findConformingSuperclass(type, description)); + return found.second; } const ContextDescriptor * @@ -768,31 +643,36 @@ static bool isSubclass(const Metadata *subclass, const Metadata *superclass) { }); } -bool swift::_checkGenericRequirements( - llvm::ArrayRef requirements, - llvm::SmallVectorImpl &extraArguments, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable) { +llvm::Optional swift::_checkGenericRequirements( + llvm::ArrayRef requirements, + llvm::SmallVectorImpl &extraArguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable) { for (const auto &req : requirements) { // Make sure we understand the requirement we're dealing with. - if (!req.hasKnownKind()) return true; + if (!req.hasKnownKind()) + return TypeLookupError("unknown kind"); // Resolve the subject generic parameter. - const Metadata *subjectType = - swift_getTypeByMangledName(MetadataState::Abstract, - req.getParam(), - extraArguments.data(), - substGenericParam, substWitnessTable).getMetadata(); - if (!subjectType) - return true; + auto result = swift_getTypeByMangledName( + MetadataState::Abstract, req.getParam(), extraArguments.data(), + substGenericParam, substWitnessTable); + if (result.getError()) + return *result.getError(); + const Metadata *subjectType = result.getType().getMetadata(); // Check the requirement. switch (req.getKind()) { case GenericRequirementKind::Protocol: { const WitnessTable *witnessTable = nullptr; if (!_conformsToProtocol(nullptr, subjectType, req.getProtocol(), - &witnessTable)) - return true; + &witnessTable)) { + const char *protoName = + req.getProtocol() ? req.getProtocol().getName() : ""; + return TypeLookupError( + "subject type %s does not conform to protocol %s", req.getParam(), + protoName); + } // If we need a witness table, add it. if (req.getProtocol().needsWitnessTable()) { @@ -805,17 +685,19 @@ bool swift::_checkGenericRequirements( case GenericRequirementKind::SameType: { // Demangle the second type under the given substitutions. - auto otherType = - swift_getTypeByMangledName(MetadataState::Abstract, - req.getMangledTypeName(), - extraArguments.data(), - substGenericParam, substWitnessTable).getMetadata(); - if (!otherType) return true; + auto result = swift_getTypeByMangledName( + MetadataState::Abstract, req.getMangledTypeName(), + extraArguments.data(), substGenericParam, substWitnessTable); + if (result.getError()) + return *result.getError(); + auto otherType = result.getType().getMetadata(); assert(!req.getFlags().hasExtraArgument()); // Check that the types are equivalent. - if (subjectType != otherType) return true; + if (subjectType != otherType) + return TypeLookupError("subject type %s does not match %s", + req.getParam(), req.getMangledTypeName()); continue; } @@ -824,22 +706,24 @@ bool swift::_checkGenericRequirements( switch (req.getLayout()) { case GenericRequirementLayoutKind::Class: if (!subjectType->satisfiesClassConstraint()) - return true; + return TypeLookupError( + "subject type %s does not satisfy class constraint", + req.getParam()); continue; } // Unknown layout. - return true; + return TypeLookupError("unknown layout kind %u", req.getLayout()); } case GenericRequirementKind::BaseClass: { // Demangle the base type under the given substitutions. - auto baseType = - swift_getTypeByMangledName(MetadataState::Abstract, - req.getMangledTypeName(), - extraArguments.data(), - substGenericParam, substWitnessTable).getMetadata(); - if (!baseType) return true; + auto result = swift_getTypeByMangledName( + MetadataState::Abstract, req.getMangledTypeName(), + extraArguments.data(), substGenericParam, substWitnessTable); + if (result.getError()) + return *result.getError(); + auto baseType = result.getType().getMetadata(); // If the type which is constrained to a base class is an existential // type, and if that existential type includes a superclass constraint, @@ -851,7 +735,8 @@ bool swift::_checkGenericRequirements( } if (!isSubclass(subjectType, baseType)) - return true; + return TypeLookupError("%s is not subclass of %s", req.getParam(), + req.getMangledTypeName()); continue; } @@ -863,11 +748,12 @@ bool swift::_checkGenericRequirements( } // Unknown generic requirement kind. - return true; + return TypeLookupError("unknown generic requirement kind %u", + req.getKind()); } // Success! - return false; + return llvm::None; } const Metadata *swift::findConformingSuperclass( diff --git a/stdlib/public/runtime/ReflectionMirror.mm b/stdlib/public/runtime/ReflectionMirror.mm index 61593760d31fd..0206237d2b44b 100644 --- a/stdlib/public/runtime/ReflectionMirror.mm +++ b/stdlib/public/runtime/ReflectionMirror.mm @@ -247,16 +247,16 @@ virtual const FieldType recursiveChildMetadata(intptr_t index, // Implementation for tuples. struct TupleImpl : ReflectionMirrorImpl { - char displayStyle() { + char displayStyle() override { return 't'; } - intptr_t count() { + intptr_t count() override { auto *Tuple = static_cast(type); return Tuple->NumElements; } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { auto *Tuple = static_cast(type); if (i < 0 || (size_t)i > Tuple->NumElements) @@ -268,7 +268,7 @@ intptr_t childOffset(intptr_t i) { } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { auto *Tuple = static_cast(type); if (i < 0 || (size_t)i > Tuple->NumElements) @@ -306,7 +306,7 @@ const FieldType childMetadata(intptr_t i, const char **outName, } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { auto eltOffset = childOffset(i); auto fieldType = childMetadata(i, outName, outFreeFunc); @@ -400,27 +400,33 @@ static bool _shouldReportMissingReflectionMetadataWarnings() { auto typeName = field.getMangledTypeName(); SubstGenericParametersFromMetadata substitutions(base); - auto typeInfo = swift_getTypeByMangledName(MetadataState::Complete, - typeName, - substitutions.getGenericArgs(), - [&substitutions](unsigned depth, unsigned index) { - return substitutions.getMetadata(depth, index); - }, - [&substitutions](const Metadata *type, unsigned index) { - return substitutions.getWitnessTable(type, index); - }); + auto result = swift_getTypeByMangledName( + MetadataState::Complete, typeName, substitutions.getGenericArgs(), + [&substitutions](unsigned depth, unsigned index) { + return substitutions.getMetadata(depth, index); + }, + [&substitutions](const Metadata *type, unsigned index) { + return substitutions.getWitnessTable(type, index); + }); // If demangling the type failed, pretend it's an empty type instead with // a log message. - if (!typeInfo.getMetadata()) { + TypeInfo typeInfo; + if (result.isError()) { typeInfo = TypeInfo({&METADATA_SYM(EMPTY_TUPLE_MANGLING), MetadataState::Complete}, {}); + + auto *error = result.getError(); + char *str = error->copyErrorString(); missing_reflection_metadata_warning( - "warning: the Swift runtime was unable to demangle the type " - "of field '%*s'. the mangled type name is '%*s'. this field will " - "show up as an empty tuple in Mirrors\n", - (int)name.size(), name.data(), - (int)typeName.size(), typeName.data()); + "warning: the Swift runtime was unable to demangle the type " + "of field '%*s'. the mangled type name is '%*s': %s. this field will " + "show up as an empty tuple in Mirrors\n", + (int)name.size(), name.data(), (int)typeName.size(), typeName.data(), + str); + error->freeErrorString(str); + } else { + typeInfo = result.getType(); } auto fieldType = FieldType(typeInfo.getMetadata()); @@ -437,11 +443,11 @@ bool isReflectable() { return Description->isReflectable(); } - char displayStyle() { + char displayStyle() override { return 's'; } - intptr_t count() { + intptr_t count() override { if (!isReflectable()) { return 0; } @@ -450,7 +456,7 @@ intptr_t count() { return Struct->getDescription()->NumFields; } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { auto *Struct = static_cast(type); if (i < 0 || (size_t)i > Struct->getDescription()->NumFields) @@ -461,7 +467,7 @@ intptr_t childOffset(intptr_t i) { } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { StringRef name; FieldType fieldInfo; std::tie(name, fieldInfo) = getFieldAt(type, i); @@ -474,7 +480,7 @@ const FieldType childMetadata(intptr_t i, const char **outName, } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { auto fieldInfo = childMetadata(i, outName, outFreeFunc); auto *bytes = reinterpret_cast(value); @@ -516,11 +522,11 @@ bool isReflectable() { return name.data(); } - char displayStyle() { + char displayStyle() override { return 'e'; } - intptr_t count() { + intptr_t count() override { if (!isReflectable()) { return 0; } @@ -535,17 +541,17 @@ intptr_t count() { return (payloadType != nullptr) ? 1 : 0; } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { return 0; } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { return FieldType(); } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { unsigned tag; const Metadata *payloadType; bool indirect; @@ -589,7 +595,7 @@ AnyReturn subscript(intptr_t i, const char **outName, return AnyReturn(result); } - const char *enumCaseName() { + const char *enumCaseName() override { if (!isReflectable()) { return nullptr; } @@ -607,7 +613,7 @@ bool isReflectable() { return Description->isReflectable(); } - char displayStyle() { + char displayStyle() override { return 'c'; } @@ -635,7 +641,7 @@ ClassImpl superclassMirror() { swift::crash("No superclass mirror found"); } - intptr_t count() { + intptr_t count() override { if (!isReflectable()) return 0; @@ -646,7 +652,7 @@ intptr_t count() { return count; } - intptr_t recursiveCount() { + intptr_t recursiveCount() override { if (hasSuperclassMirror()) { return superclassMirror().recursiveCount() + count(); } @@ -654,7 +660,7 @@ intptr_t recursiveCount() { return count(); } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { auto *Clas = static_cast(type); auto description = Clas->getDescription(); @@ -679,7 +685,7 @@ intptr_t childOffset(intptr_t i) { return (intptr_t)fieldOffset; } - intptr_t recursiveChildOffset(intptr_t i) { + intptr_t recursiveChildOffset(intptr_t i) override { if (hasSuperclassMirror()) { auto superMirror = superclassMirror(); auto superclassFieldCount = superMirror.recursiveCount(); @@ -695,7 +701,7 @@ intptr_t recursiveChildOffset(intptr_t i) { } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { StringRef name; FieldType fieldInfo; std::tie(name, fieldInfo) = getFieldAt(type, i); @@ -709,8 +715,7 @@ const FieldType childMetadata(intptr_t i, const char **outName, const FieldType recursiveChildMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) - { + void (**outFreeFunc)(const char *)) override { if (hasSuperclassMirror()) { auto superMirror = superclassMirror(); auto superclassFieldCount = superMirror.recursiveCount(); @@ -726,7 +731,7 @@ const FieldType recursiveChildMetadata(intptr_t i, } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { auto fieldInfo = childMetadata(i, outName, outFreeFunc); auto *bytes = *reinterpret_cast(value); @@ -794,25 +799,25 @@ virtual const FieldType recursiveChildMetadata(intptr_t index, // Implementation for metatypes. struct MetatypeImpl : ReflectionMirrorImpl { - char displayStyle() { + char displayStyle() override { return '\0'; } - intptr_t count() { + intptr_t count() override { return 0; } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { swift::crash("Metatypes have no children."); } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { swift::crash("Metatypes have no children."); } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { swift::crash("Metatypes have no children."); } }; @@ -820,25 +825,25 @@ AnyReturn subscript(intptr_t i, const char **outName, // Implementation for opaque types. struct OpaqueImpl : ReflectionMirrorImpl { - char displayStyle() { + char displayStyle() override { return '\0'; } - intptr_t count() { + intptr_t count() override { return 0; } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { swift::crash("Opaque types have no children."); } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { swift::crash("Opaque types have no children."); } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { swift::crash("Opaque types have no children."); } }; diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm index f377a77d6f106..ba33dd19abd69 100644 --- a/stdlib/public/runtime/SwiftObject.mm +++ b/stdlib/public/runtime/SwiftObject.mm @@ -26,11 +26,13 @@ #include "llvm/ADT/StringRef.h" #include "swift/Basic/Lazy.h" #include "swift/Runtime/Casting.h" +#include "swift/Runtime/Debug.h" #include "swift/Runtime/EnvironmentVariables.h" #include "swift/Runtime/Heap.h" #include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Metadata.h" #include "swift/Runtime/ObjCBridge.h" +#include "swift/Runtime/Portability.h" #include "swift/Strings.h" #include "../SwiftShims/RuntimeShims.h" #include "../SwiftShims/AssertionReporting.h" @@ -39,7 +41,6 @@ #include "Private.h" #include "SwiftObject.h" #include "WeakReference.h" -#include "swift/Runtime/Debug.h" #if SWIFT_OBJC_INTEROP #include #endif diff --git a/stdlib/public/stubs/Assert.cpp b/stdlib/public/stubs/Assert.cpp index 62135b2312b1c..fa0169a5ad6b8 100644 --- a/stdlib/public/stubs/Assert.cpp +++ b/stdlib/public/stubs/Assert.cpp @@ -12,6 +12,7 @@ #include "swift/Runtime/Config.h" #include "swift/Runtime/Debug.h" +#include "swift/Runtime/Portability.h" #include "../SwiftShims/AssertionReporting.h" #include #include diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index 949dca892d81f..15338277fb1d2 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -510,5 +510,9 @@ int _swift_stdlib_putc_stderr(int C) { } size_t _swift_stdlib_getHardwareConcurrency() { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return 1; +#else return std::thread::hardware_concurrency(); +#endif } diff --git a/stdlib/public/stubs/ThreadLocalStorage.cpp b/stdlib/public/stubs/ThreadLocalStorage.cpp index 1238504a2b6af..0f0c23e6c1d79 100644 --- a/stdlib/public/stubs/ThreadLocalStorage.cpp +++ b/stdlib/public/stubs/ThreadLocalStorage.cpp @@ -54,43 +54,19 @@ _stdlib_thread_key_create(__swift_thread_key_t * _Nonnull key, #endif -#if defined(__wasi__) -#include -using __swift_thread_key_destructor = void (*)(void *); - -struct _stdlib_tls_element_t { - const void *value; - __swift_thread_key_destructor destructor; -}; - -using _stdlib_tls_map_t = std::map<__swift_thread_key_t, _stdlib_tls_element_t>; -static void *_stdlib_tls_map; - -static inline int _stdlib_thread_key_create(__swift_thread_key_t *key, - __swift_thread_key_destructor destructor) { - if (!_stdlib_tls_map) - _stdlib_tls_map = new _stdlib_tls_map_t(); - auto *map = (_stdlib_tls_map_t *)_stdlib_tls_map; - *key = map->size(); - _stdlib_tls_element_t element = { nullptr, destructor }; - map->insert(std::make_pair(*key, element)); - return 0; -} - -static inline void *_stdlib_thread_getspecific(__swift_thread_key_t key) { - auto *map = (_stdlib_tls_map_t *)_stdlib_tls_map; - return const_cast(map->operator[](key).value); -} +#if defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) -static inline int _stdlib_thread_setspecific(__swift_thread_key_t key, const void *value) { - auto *map = (_stdlib_tls_map_t *)_stdlib_tls_map; - map->operator[](key).value = value; - return 0; +SWIFT_RUNTIME_STDLIB_INTERNAL +void * +_swift_stdlib_threadLocalStorageGet(void) { + static void *value; + if (!value) { + value = _stdlib_createTLS(); + } + return value; } -#endif - -#if SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC +#elif SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC SWIFT_RUNTIME_STDLIB_INTERNAL void * diff --git a/stdlib/toolchain/Compatibility50/CompatibilityOverride.def b/stdlib/toolchain/Compatibility50/CompatibilityOverride.def new file mode 100644 index 0000000000000..06ee84685dc35 --- /dev/null +++ b/stdlib/toolchain/Compatibility50/CompatibilityOverride.def @@ -0,0 +1,226 @@ +//===--- CompatibilityOverrides.def - Compatibility Overrides Database -*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines x-macros used for metaprogramming with the set of +// compatibility override functions. +// +//===----------------------------------------------------------------------===// + +/// #define OVERRIDE(name, ret, attrs, namespace, typedArgs, namedArgs) +/// Provides information about an overridable function. +/// - name is the name of the function, without any leading swift_ or +/// namespace. +/// - ret is the return type of the function. +/// - attrs is the attributes, if any, applied to the function definition. +/// - namespace is the namespace, if any, the function is in, including a +/// trailing :: +/// - typedArgs is the argument list, including types, surrounded by +/// parentheses +/// - namedArgs is the list of argument names, with no types, surrounded by +/// parentheses +/// +/// The entries are organized by group. A user may define OVERRIDE to get all +/// entries, or define one or more of OVERRIDE_METADATALOOKUP, OVERRIDE_CASTING, +/// OVERRIDE_OBJC, OVERRIDE_FOREIGN, OVERRIDE_PROTOCOLCONFORMANCE, +/// and OVERRIDE_KEYPATH to get only those entries. + +// NOTE: this file is used to build the definition of OverrideSection in +// CompatibilityOverride.cpp, which is part of the ABI. Do not move or remove entries +// in this file after ABI stability. Additional entries can be added to the end. + +#ifdef OVERRIDE +# define OVERRIDE_METADATALOOKUP OVERRIDE +# define OVERRIDE_CASTING OVERRIDE +# define OVERRIDE_OBJC OVERRIDE +# define OVERRIDE_FOREIGN OVERRIDE +# define OVERRIDE_PROTOCOLCONFORMANCE OVERRIDE +# define OVERRIDE_KEYPATH OVERRIDE +# define OVERRIDE_WITNESSTABLE OVERRIDE +#else +# ifndef OVERRIDE_METADATALOOKUP +# define OVERRIDE_METADATALOOKUP(...) +# endif +# ifndef OVERRIDE_CASTING +# define OVERRIDE_CASTING(...) +# endif +# ifndef OVERRIDE_OBJC +# define OVERRIDE_OBJC(...) +# endif +# ifndef OVERRIDE_FOREIGN +# define OVERRIDE_FOREIGN(...) +# endif +# ifndef OVERRIDE_PROTOCOLCONFORMANCE +# define OVERRIDE_PROTOCOLCONFORMANCE(...) +# endif +# ifndef OVERRIDE_KEYPATH +# define OVERRIDE_KEYPATH(...) +# endif +# ifndef OVERRIDE_WITNESSTABLE +# define OVERRIDE_WITNESSTABLE(...) +# endif +#endif + +OVERRIDE_CASTING(dynamicCast, bool, , , swift::, + (OpaqueValue *dest, OpaqueValue *src, + const Metadata *srcType, + const Metadata *targetType, + DynamicCastFlags flags), + (dest, src, srcType, targetType, flags)) + + +OVERRIDE_CASTING(dynamicCastClass, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_CASTING(dynamicCastClassUnconditional, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + + + +OVERRIDE_CASTING(dynamicCastUnknownClass, const void *, , , swift::, + (const void *object, const Metadata *targetType), + (object, targetType)) + + +OVERRIDE_CASTING(dynamicCastUnknownClassUnconditional, const void *, , , swift::, + (const void *object, const Metadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + + +OVERRIDE_CASTING(dynamicCastMetatype, const Metadata *, , , swift::, + (const Metadata *sourceType, + const Metadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_CASTING(dynamicCastMetatypeUnconditional, const Metadata *, , , swift::, + (const Metadata *sourceType, + const Metadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassMetatype, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassMetatypeUnconditional, + const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_PROTOCOLCONFORMANCE(conformsToProtocol, const WitnessTable *, , , swift::, + (const Metadata * const type, + const ProtocolDescriptor *protocol), + (type, protocol)) + +OVERRIDE_PROTOCOLCONFORMANCE(conformsToSwiftProtocol, + const ProtocolConformanceDescriptor *, , , swift::, + (const Metadata * const type, + const ProtocolDescriptor *protocol, + StringRef moduleName), + (type, protocol, moduleName)) + +OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , , swift::, + (const void *pattern, const void *arguments), + (pattern, arguments)) + +OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeInfo, , SWIFT_CC(swift), swift::, + (MetadataRequest request, + Demangler &demangler, + Demangle::NodePointer node, + const void * const *arguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable), + (request, demangler, node, arguments, substGenericParam, substWitnessTable)) +OVERRIDE_METADATALOOKUP(getTypeByMangledName, TypeInfo, , SWIFT_CC(swift), swift::, + (MetadataRequest request, + StringRef typeName, + const void * const *arguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable), + (request, typeName, arguments, substGenericParam, substWitnessTable)) + +OVERRIDE_WITNESSTABLE(getAssociatedTypeWitnessSlow, MetadataResponse, + SWIFT_RUNTIME_STDLIB_INTERNAL, SWIFT_CC(swift), swift::, + (MetadataRequest request, WitnessTable *wtable, + const Metadata *conformingType, + const ProtocolRequirement *reqBase, + const ProtocolRequirement *assocType), + (request, wtable, conformingType, reqBase, assocType)) + +OVERRIDE_WITNESSTABLE(getAssociatedConformanceWitnessSlow, const WitnessTable *, + SWIFT_RUNTIME_STDLIB_INTERNAL, SWIFT_CC(swift), swift::, + (WitnessTable *wtable, const Metadata *conformingType, + const Metadata *assocType, + const ProtocolRequirement *reqBase, + const ProtocolRequirement *assocConformance), + (wtable, conformingType, assocType, reqBase, + assocConformance)) +#if SWIFT_OBJC_INTEROP + +OVERRIDE_OBJC(dynamicCastObjCClass, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_OBJC(dynamicCastObjCClassUnconditional, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + +OVERRIDE_OBJC(dynamicCastObjCClassMetatype, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_OBJC(dynamicCastObjCClassMetatypeUnconditional, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClass, const void *, , , swift::, + (const void *object, + const ForeignClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassUnconditional, const void *, , , swift::, + (const void *object, const ForeignClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + +#endif + +#undef OVERRIDE +#undef OVERRIDE_METADATALOOKUP +#undef OVERRIDE_CASTING +#undef OVERRIDE_OBJC +#undef OVERRIDE_FOREIGN +#undef OVERRIDE_PROTOCOLCONFORMANCE +#undef OVERRIDE_KEYPATH +#undef OVERRIDE_WITNESSTABLE diff --git a/stdlib/toolchain/Compatibility50/CompatibilityOverride.h b/stdlib/toolchain/Compatibility50/CompatibilityOverride.h new file mode 100644 index 0000000000000..e726e41958f50 --- /dev/null +++ b/stdlib/toolchain/Compatibility50/CompatibilityOverride.h @@ -0,0 +1,61 @@ +//===--- CompatibiltyOverride.h - Back-deploying compatibility fixes --*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Support back-deploying compatibility fixes for newer apps running on older runtimes. +// +//===----------------------------------------------------------------------===// + +#ifndef COMPATIBILITY_OVERRIDE_H +#define COMPATIBILITY_OVERRIDE_H + +#include "../../public/runtime/Private.h" +#include "swift/Runtime/Metadata.h" +#include "swift/Runtime/Once.h" +#include + +namespace swift { + +#define COMPATIBILITY_UNPAREN(...) __VA_ARGS__ + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + ccAttrs typedef ret (*Original_ ## name) typedArgs; +#include "CompatibilityOverride.def" + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + ccAttrs typedef ret (*Override_ ## name)(COMPATIBILITY_UNPAREN typedArgs, \ + Original_ ## name originalImpl); +#include "CompatibilityOverride.def" + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + Override_ ## name getOverride_ ## name(); +#include "CompatibilityOverride.def" + + +/// Used to define an override point. The override point #defines the appropriate +/// OVERRIDE macro from CompatibilityOverride.def to this macro, then includes +/// the file to generate the override points. The original implementation of the +/// functionality must be available as swift_funcNameHereImpl. +#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + attrs ccAttrs ret namespace swift_ ## name typedArgs { \ + static Override_ ## name Override; \ + static swift_once_t Predicate; \ + swift_once(&Predicate, [](void *) { \ + Override = getOverride_ ## name(); \ + }, nullptr); \ + if (Override != nullptr) \ + return Override(COMPATIBILITY_UNPAREN namedArgs, swift_ ## name ## Impl); \ + return swift_ ## name ## Impl namedArgs; \ + } + +} /* end namespace swift */ + +#endif /* COMPATIBILITY_OVERRIDE_H */ diff --git a/stdlib/toolchain/Compatibility50/Overrides.cpp b/stdlib/toolchain/Compatibility50/Overrides.cpp index bc6f88625256b..fcaccf3b0fb4d 100644 --- a/stdlib/toolchain/Compatibility50/Overrides.cpp +++ b/stdlib/toolchain/Compatibility50/Overrides.cpp @@ -16,7 +16,7 @@ #include "Overrides.h" #include "../Compatibility51/Overrides.h" -#include "../../public/runtime/CompatibilityOverride.h" +#include "CompatibilityOverride.h" #include #include @@ -28,7 +28,7 @@ struct OverrideSection { uintptr_t version; #define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ Override_ ## name name; -#include "../../public/runtime/CompatibilityOverride.def" +#include "CompatibilityOverride.def" }; OverrideSection Swift50Overrides diff --git a/stdlib/toolchain/Compatibility51/CompatibilityOverride.def b/stdlib/toolchain/Compatibility51/CompatibilityOverride.def new file mode 100644 index 0000000000000..06ee84685dc35 --- /dev/null +++ b/stdlib/toolchain/Compatibility51/CompatibilityOverride.def @@ -0,0 +1,226 @@ +//===--- CompatibilityOverrides.def - Compatibility Overrides Database -*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines x-macros used for metaprogramming with the set of +// compatibility override functions. +// +//===----------------------------------------------------------------------===// + +/// #define OVERRIDE(name, ret, attrs, namespace, typedArgs, namedArgs) +/// Provides information about an overridable function. +/// - name is the name of the function, without any leading swift_ or +/// namespace. +/// - ret is the return type of the function. +/// - attrs is the attributes, if any, applied to the function definition. +/// - namespace is the namespace, if any, the function is in, including a +/// trailing :: +/// - typedArgs is the argument list, including types, surrounded by +/// parentheses +/// - namedArgs is the list of argument names, with no types, surrounded by +/// parentheses +/// +/// The entries are organized by group. A user may define OVERRIDE to get all +/// entries, or define one or more of OVERRIDE_METADATALOOKUP, OVERRIDE_CASTING, +/// OVERRIDE_OBJC, OVERRIDE_FOREIGN, OVERRIDE_PROTOCOLCONFORMANCE, +/// and OVERRIDE_KEYPATH to get only those entries. + +// NOTE: this file is used to build the definition of OverrideSection in +// CompatibilityOverride.cpp, which is part of the ABI. Do not move or remove entries +// in this file after ABI stability. Additional entries can be added to the end. + +#ifdef OVERRIDE +# define OVERRIDE_METADATALOOKUP OVERRIDE +# define OVERRIDE_CASTING OVERRIDE +# define OVERRIDE_OBJC OVERRIDE +# define OVERRIDE_FOREIGN OVERRIDE +# define OVERRIDE_PROTOCOLCONFORMANCE OVERRIDE +# define OVERRIDE_KEYPATH OVERRIDE +# define OVERRIDE_WITNESSTABLE OVERRIDE +#else +# ifndef OVERRIDE_METADATALOOKUP +# define OVERRIDE_METADATALOOKUP(...) +# endif +# ifndef OVERRIDE_CASTING +# define OVERRIDE_CASTING(...) +# endif +# ifndef OVERRIDE_OBJC +# define OVERRIDE_OBJC(...) +# endif +# ifndef OVERRIDE_FOREIGN +# define OVERRIDE_FOREIGN(...) +# endif +# ifndef OVERRIDE_PROTOCOLCONFORMANCE +# define OVERRIDE_PROTOCOLCONFORMANCE(...) +# endif +# ifndef OVERRIDE_KEYPATH +# define OVERRIDE_KEYPATH(...) +# endif +# ifndef OVERRIDE_WITNESSTABLE +# define OVERRIDE_WITNESSTABLE(...) +# endif +#endif + +OVERRIDE_CASTING(dynamicCast, bool, , , swift::, + (OpaqueValue *dest, OpaqueValue *src, + const Metadata *srcType, + const Metadata *targetType, + DynamicCastFlags flags), + (dest, src, srcType, targetType, flags)) + + +OVERRIDE_CASTING(dynamicCastClass, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_CASTING(dynamicCastClassUnconditional, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + + + +OVERRIDE_CASTING(dynamicCastUnknownClass, const void *, , , swift::, + (const void *object, const Metadata *targetType), + (object, targetType)) + + +OVERRIDE_CASTING(dynamicCastUnknownClassUnconditional, const void *, , , swift::, + (const void *object, const Metadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + + +OVERRIDE_CASTING(dynamicCastMetatype, const Metadata *, , , swift::, + (const Metadata *sourceType, + const Metadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_CASTING(dynamicCastMetatypeUnconditional, const Metadata *, , , swift::, + (const Metadata *sourceType, + const Metadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassMetatype, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassMetatypeUnconditional, + const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_PROTOCOLCONFORMANCE(conformsToProtocol, const WitnessTable *, , , swift::, + (const Metadata * const type, + const ProtocolDescriptor *protocol), + (type, protocol)) + +OVERRIDE_PROTOCOLCONFORMANCE(conformsToSwiftProtocol, + const ProtocolConformanceDescriptor *, , , swift::, + (const Metadata * const type, + const ProtocolDescriptor *protocol, + StringRef moduleName), + (type, protocol, moduleName)) + +OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , , swift::, + (const void *pattern, const void *arguments), + (pattern, arguments)) + +OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeInfo, , SWIFT_CC(swift), swift::, + (MetadataRequest request, + Demangler &demangler, + Demangle::NodePointer node, + const void * const *arguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable), + (request, demangler, node, arguments, substGenericParam, substWitnessTable)) +OVERRIDE_METADATALOOKUP(getTypeByMangledName, TypeInfo, , SWIFT_CC(swift), swift::, + (MetadataRequest request, + StringRef typeName, + const void * const *arguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable), + (request, typeName, arguments, substGenericParam, substWitnessTable)) + +OVERRIDE_WITNESSTABLE(getAssociatedTypeWitnessSlow, MetadataResponse, + SWIFT_RUNTIME_STDLIB_INTERNAL, SWIFT_CC(swift), swift::, + (MetadataRequest request, WitnessTable *wtable, + const Metadata *conformingType, + const ProtocolRequirement *reqBase, + const ProtocolRequirement *assocType), + (request, wtable, conformingType, reqBase, assocType)) + +OVERRIDE_WITNESSTABLE(getAssociatedConformanceWitnessSlow, const WitnessTable *, + SWIFT_RUNTIME_STDLIB_INTERNAL, SWIFT_CC(swift), swift::, + (WitnessTable *wtable, const Metadata *conformingType, + const Metadata *assocType, + const ProtocolRequirement *reqBase, + const ProtocolRequirement *assocConformance), + (wtable, conformingType, assocType, reqBase, + assocConformance)) +#if SWIFT_OBJC_INTEROP + +OVERRIDE_OBJC(dynamicCastObjCClass, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_OBJC(dynamicCastObjCClassUnconditional, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + +OVERRIDE_OBJC(dynamicCastObjCClassMetatype, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_OBJC(dynamicCastObjCClassMetatypeUnconditional, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClass, const void *, , , swift::, + (const void *object, + const ForeignClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassUnconditional, const void *, , , swift::, + (const void *object, const ForeignClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + +#endif + +#undef OVERRIDE +#undef OVERRIDE_METADATALOOKUP +#undef OVERRIDE_CASTING +#undef OVERRIDE_OBJC +#undef OVERRIDE_FOREIGN +#undef OVERRIDE_PROTOCOLCONFORMANCE +#undef OVERRIDE_KEYPATH +#undef OVERRIDE_WITNESSTABLE diff --git a/stdlib/toolchain/Compatibility51/CompatibilityOverride.h b/stdlib/toolchain/Compatibility51/CompatibilityOverride.h new file mode 100644 index 0000000000000..e726e41958f50 --- /dev/null +++ b/stdlib/toolchain/Compatibility51/CompatibilityOverride.h @@ -0,0 +1,61 @@ +//===--- CompatibiltyOverride.h - Back-deploying compatibility fixes --*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Support back-deploying compatibility fixes for newer apps running on older runtimes. +// +//===----------------------------------------------------------------------===// + +#ifndef COMPATIBILITY_OVERRIDE_H +#define COMPATIBILITY_OVERRIDE_H + +#include "../../public/runtime/Private.h" +#include "swift/Runtime/Metadata.h" +#include "swift/Runtime/Once.h" +#include + +namespace swift { + +#define COMPATIBILITY_UNPAREN(...) __VA_ARGS__ + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + ccAttrs typedef ret (*Original_ ## name) typedArgs; +#include "CompatibilityOverride.def" + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + ccAttrs typedef ret (*Override_ ## name)(COMPATIBILITY_UNPAREN typedArgs, \ + Original_ ## name originalImpl); +#include "CompatibilityOverride.def" + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + Override_ ## name getOverride_ ## name(); +#include "CompatibilityOverride.def" + + +/// Used to define an override point. The override point #defines the appropriate +/// OVERRIDE macro from CompatibilityOverride.def to this macro, then includes +/// the file to generate the override points. The original implementation of the +/// functionality must be available as swift_funcNameHereImpl. +#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + attrs ccAttrs ret namespace swift_ ## name typedArgs { \ + static Override_ ## name Override; \ + static swift_once_t Predicate; \ + swift_once(&Predicate, [](void *) { \ + Override = getOverride_ ## name(); \ + }, nullptr); \ + if (Override != nullptr) \ + return Override(COMPATIBILITY_UNPAREN namedArgs, swift_ ## name ## Impl); \ + return swift_ ## name ## Impl namedArgs; \ + } + +} /* end namespace swift */ + +#endif /* COMPATIBILITY_OVERRIDE_H */ diff --git a/stdlib/toolchain/Compatibility51/Overrides.cpp b/stdlib/toolchain/Compatibility51/Overrides.cpp index 5e1eb78f3ab37..f9a89ec39e115 100644 --- a/stdlib/toolchain/Compatibility51/Overrides.cpp +++ b/stdlib/toolchain/Compatibility51/Overrides.cpp @@ -14,7 +14,7 @@ // //===----------------------------------------------------------------------===// -#include "../../public/runtime/CompatibilityOverride.h" +#include "CompatibilityOverride.h" #include "Overrides.h" #include @@ -27,7 +27,7 @@ struct OverrideSection { uintptr_t version; #define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ Override_ ## name name; -#include "../../public/runtime/CompatibilityOverride.def" +#include "CompatibilityOverride.def" }; OverrideSection Swift51Overrides diff --git a/test/AutoDiff/SILOptimizer/activity_analysis.swift b/test/AutoDiff/SILOptimizer/activity_analysis.swift index fe8fd1a7785c1..2a2fdcca7f650 100644 --- a/test/AutoDiff/SILOptimizer/activity_analysis.swift +++ b/test/AutoDiff/SILOptimizer/activity_analysis.swift @@ -543,17 +543,25 @@ func activeInoutArgNonactiveInitialResult(_ x: Float) -> Float { func rethrowing(_ x: () throws -> Void) rethrows -> Void {} -// expected-error @+1 {{function is not differentiable}} @differentiable -// expected-note @+1 {{when differentiating this function definition}} func testTryApply(_ x: Float) -> Float { - // expected-note @+1 {{cannot differentiate unsupported control flow}} rethrowing({}) return x } // TF-433: differentiation diagnoses `try_apply` before activity info is printed. -// CHECK-NOT: [AD] Activity info for ${{.*}}testTryApply{{.*}} at (parameters=(0) results=(0)) +// CHECK-LABEL: [AD] Activity info for ${{.*}}testTryApply{{.*}} at (parameters=(0) results=(0)) +// CHECK: bb0: +// CHECK: [ACTIVE] %0 = argument of bb0 : $Float +// CHECK: [NONE] // function_ref closure #1 in testTryApply(_:) +// CHECK: [NONE] %3 = convert_function %2 : $@convention(thin) () -> () to $@convention(thin) @noescape () -> () +// CHECK: [NONE] %4 = thin_to_thick_function %3 : $@convention(thin) @noescape () -> () to $@noescape @callee_guaranteed () -> () +// CHECK: [NONE] %5 = convert_function %4 : $@noescape @callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> @error Error +// CHECK: [NONE] // function_ref rethrowing(_:) +// CHECK: bb1: +// CHECK: [NONE] %8 = argument of bb1 : $() +// CHECK: bb2: +// CHECK: [NONE] %10 = argument of bb2 : $Error //===----------------------------------------------------------------------===// // Coroutine differentiation (`begin_apply`) diff --git a/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift b/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift index 6bc8cda64005f..5248811b04aa0 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift @@ -78,11 +78,8 @@ func nested_loop(_ x: Float) -> Float { func rethrowing(_ x: () throws -> Void) rethrows -> Void {} -// expected-error @+1 {{function is not differentiable}} @differentiable -// expected-note @+1 {{when differentiating this function definition}} func testTryApply(_ x: Float) -> Float { - // expected-note @+1 {{cannot differentiate unsupported control flow}} rethrowing({}) return x } @@ -93,10 +90,19 @@ func testTryApply(_ x: Float) -> Float { func withoutDerivative( at x: T, in body: (T) throws -> R ) rethrows -> R { - // expected-note @+1 {{cannot differentiate unsupported control flow}} + // expected-note @+1 {{expression is not differentiable}} try body(x) } +// Tests active `try_apply`. +// expected-error @+1 {{function is not differentiable}} +@differentiable +// expected-note @+1 {{when differentiating this function definition}} +func testNilCoalescing(_ maybeX: Float?) -> Float { + // expected-note @+1 {{expression is not differentiable}} + return maybeX ?? 10 +} + // Test unsupported differentiation of active enum values. // expected-error @+1 {{function is not differentiable}} @@ -165,7 +171,7 @@ func loop_array(_ array: [Float]) -> Float { var result: Float = 1 // TODO(TF-957): Improve non-differentiability errors for for-in loops // (`Collection.makeIterator` and `IteratorProtocol.next`). - // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} {{12-12=withoutDerivative(at: }} {{17-17=)}} for x in array { result = result * x } diff --git a/test/AutoDiff/SILOptimizer/differentiation_control_flow_sil.swift b/test/AutoDiff/SILOptimizer/differentiation_control_flow_sil.swift index 4b30bd64cd358..2778a4d849cd3 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_control_flow_sil.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_control_flow_sil.swift @@ -68,29 +68,30 @@ func cond(_ x: Float) -> Float { // CHECK-SIL: [[PB:%.*]] = partial_apply [callee_guaranteed] [[PULLBACK_REF]]([[BB3_PB_STRUCT]]) // CHECK-SIL: [[VJP_RESULT:%.*]] = tuple ([[ORIG_RES]] : $Float, [[PB]] : $@callee_guaranteed (Float) -> Float) // CHECK-SIL: return [[VJP_RESULT]] +// CHECK-SIL-LABEL: } // end sil function 'AD__cond__vjp_src_0_wrt_0' // CHECK-SIL-LABEL: sil private [ossa] @AD__cond__pullback_src_0_wrt_0 : $@convention(thin) (Float, @owned _AD__cond_bb3__PB__src_0_wrt_0) -> Float { // CHECK-SIL: bb0([[SEED:%.*]] : $Float, [[BB3_PB_STRUCT:%.*]] : @owned $_AD__cond_bb3__PB__src_0_wrt_0): // CHECK-SIL: [[BB3_PRED:%.*]] = destructure_struct [[BB3_PB_STRUCT]] : $_AD__cond_bb3__PB__src_0_wrt_0 -// CHECK-SIL: switch_enum [[BB3_PRED]] : $_AD__cond_bb3__Pred__src_0_wrt_0, case #_AD__cond_bb3__Pred__src_0_wrt_0.bb2!enumelt: bb3, case #_AD__cond_bb3__Pred__src_0_wrt_0.bb1!enumelt: bb1 +// CHECK-SIL: switch_enum [[BB3_PRED]] : $_AD__cond_bb3__Pred__src_0_wrt_0, case #_AD__cond_bb3__Pred__src_0_wrt_0.bb2!enumelt: bb1, case #_AD__cond_bb3__Pred__src_0_wrt_0.bb1!enumelt: bb3 -// CHECK-SIL: bb1([[BB3_PRED1_TRAMP_PB_STRUCT:%.*]] : @owned $_AD__cond_bb1__PB__src_0_wrt_0): -// CHECK-SIL: br bb2({{%.*}} : $Float, {{%.*}}: $Float, [[BB3_PRED1_TRAMP_PB_STRUCT]] : $_AD__cond_bb1__PB__src_0_wrt_0) +// CHECK-SIL: bb1([[BB3_PRED2_TRAMP_PB_STRUCT:%.*]] : @owned $_AD__cond_bb2__PB__src_0_wrt_0): +// CHECK-SIL: br bb2({{%.*}} : $Float, {{%.*}}: $Float, [[BB3_PRED2_TRAMP_PB_STRUCT]] : $_AD__cond_bb2__PB__src_0_wrt_0) -// CHECK-SIL: bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB1_PB_STRUCT:%.*]] : @owned $_AD__cond_bb1__PB__src_0_wrt_0): -// CHECK-SIL: ([[BB1_PRED:%.*]], [[BB1_PB:%.*]]) = destructure_struct [[BB1_PB_STRUCT]] -// CHECK-SIL: [[BB1_ADJVALS:%.*]] = apply [[BB1_PB]]([[SEED]]) : $@callee_guaranteed (Float) -> (Float, Float) -// CHECK-SIL: switch_enum [[BB1_PRED]] : $_AD__cond_bb1__Pred__src_0_wrt_0, case #_AD__cond_bb1__Pred__src_0_wrt_0.bb0!enumelt: bb5 - -// CHECK-SIL: bb3([[BB3_PRED2_TRAMP_PB_STRUCT:%.*]] : @owned $_AD__cond_bb2__PB__src_0_wrt_0): -// CHECK-SIL: br bb4({{%.*}} : $Float, {{%.*}}: $Float, [[BB3_PRED2_TRAMP_PB_STRUCT]] : $_AD__cond_bb2__PB__src_0_wrt_0) - -// CHECK-SIL: bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB2_PB_STRUCT:%.*]] : @owned $_AD__cond_bb2__PB__src_0_wrt_0): +// CHECK-SIL: bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB2_PB_STRUCT:%.*]] : @owned $_AD__cond_bb2__PB__src_0_wrt_0): // CHECK-SIL: ([[BB2_PRED:%.*]], [[BB2_PB:%.*]]) = destructure_struct [[BB2_PB_STRUCT]] // CHECK-SIL: [[BB2_ADJVALS:%.*]] = apply [[BB2_PB]]([[SEED]]) : $@callee_guaranteed (Float) -> (Float, Float) // CHECK-SIL: switch_enum [[BB2_PRED]] : $_AD__cond_bb2__Pred__src_0_wrt_0, case #_AD__cond_bb2__Pred__src_0_wrt_0.bb0!enumelt: bb6 +// CHECK-SIL: bb3([[BB3_PRED1_TRAMP_PB_STRUCT:%.*]] : @owned $_AD__cond_bb1__PB__src_0_wrt_0): +// CHECK-SIL: br bb4({{%.*}} : $Float, {{%.*}}: $Float, [[BB3_PRED1_TRAMP_PB_STRUCT]] : $_AD__cond_bb1__PB__src_0_wrt_0) + +// CHECK-SIL: bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB1_PB_STRUCT:%.*]] : @owned $_AD__cond_bb1__PB__src_0_wrt_0): +// CHECK-SIL: ([[BB1_PRED:%.*]], [[BB1_PB:%.*]]) = destructure_struct [[BB1_PB_STRUCT]] +// CHECK-SIL: [[BB1_ADJVALS:%.*]] = apply [[BB1_PB]]([[SEED]]) : $@callee_guaranteed (Float) -> (Float, Float) +// CHECK-SIL: switch_enum [[BB1_PRED]] : $_AD__cond_bb1__Pred__src_0_wrt_0, case #_AD__cond_bb1__Pred__src_0_wrt_0.bb0!enumelt: bb5 + // CHECK-SIL: bb5([[BB1_PRED0_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_bb0__PB__src_0_wrt_0): // CHECK-SIL: br bb7({{%.*}} : $Float, [[BB1_PRED0_TRAMP_PB_STRUCT]] : $_AD__cond_bb0__PB__src_0_wrt_0) @@ -99,6 +100,7 @@ func cond(_ x: Float) -> Float { // CHECK-SIL: bb7({{%.*}} : $Float, [[BB0_PB_STRUCT:%.*]] : $_AD__cond_bb0__PB__src_0_wrt_0): // CHECK-SIL: return {{%.*}} : $Float +// CHECK-SIL-LABEL: } // end sil function 'AD__cond__pullback_src_0_wrt_0' @differentiable @_silgen_name("nested_cond") @@ -178,7 +180,7 @@ func enum_notactive(_ e: Enum, _ x: Float) -> Float { // CHECK-SIL: [[PB:%.*]] = partial_apply [callee_guaranteed] [[PULLBACK_REF]]([[BB3_PB_STRUCT]]) // CHECK-SIL: [[VJP_RESULT:%.*]] = tuple ([[ORIG_RES]] : $Float, [[PB]] : $@callee_guaranteed (Float) -> Float) // CHECK-SIL: return [[VJP_RESULT]] -// CHECK-SIL: } +// CHECK-SIL-LABEL: } // end sil function 'AD__enum_notactive__vjp_src_0_wrt_1' // Test `switch_enum_addr`. @@ -227,7 +229,7 @@ func enum_addr_notactive(_ e: AddressOnlyEnum, _ x: Float) -> Float { // CHECK-SIL: [[PB:%.*]] = partial_apply [callee_guaranteed] [[PB_FNREF]]<τ_0_0>([[BB3_PB_STRUCT]]) : $@convention(thin) <τ_0_0> (Float, @owned _AD__enum_addr_notactive_bb3__PB__src_0_wrt_1_l<τ_0_0>) -> Float // CHECK-SIL: [[VJP_RESULT:%.*]] = tuple ([[X_ARG]] : $Float, [[PB]] : $@callee_guaranteed (Float) -> Float) // CHECK-SIL: return [[VJP_RESULT]] : $(Float, @callee_guaranteed (Float) -> Float) -// CHECK-SIL: } +// CHECK-SIL-LABEL: } // end sil function 'AD__enum_addr_notactive__vjp_src_0_wrt_1_l' // Test control flow + tuple buffer. // Verify that pullback buffers are not allocated for address projections. @@ -248,25 +250,25 @@ func cond_tuple_var(_ x: Float) -> Float { // CHECK-SIL: [[BB3_PRED:%.*]] = destructure_struct [[BB3_PB_STRUCT]] : $_AD__cond_tuple_var_bb3__PB__src_0_wrt_0 // CHECK-SIL: copy_addr {{%.*}} to {{%.*}} : $*(Float, Float) // CHECK-SIL-NOT: copy_addr {{%.*}} to {{%.*}} : $*Float -// CHECK-SIL: switch_enum [[BB3_PRED]] : $_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0.bb2!enumelt: bb3, case #_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0.bb1!enumelt: bb1 +// CHECK-SIL: switch_enum [[BB3_PRED]] : $_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0.bb2!enumelt: bb1, case #_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0.bb1!enumelt: bb3 -// CHECK-SIL: bb1([[BB3_PRED1_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0): -// CHECK-SIL: br bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB3_PRED1_TRAMP_PB_STRUCT]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0) +// CHECK-SIL: bb1([[BB3_PRED2_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0): +// CHECK-SIL: br bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB3_PRED2_TRAMP_PB_STRUCT]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0) -// CHECK-SIL: bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB1_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0): -// CHECK-SIL: [[BB1_PRED:%.*]] = destructure_struct [[BB1_PB_STRUCT]] +// CHECK-SIL: bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB2_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0): +// CHECK-SIL: [[BB2_PRED:%.*]] = destructure_struct [[BB2_PB_STRUCT]] // CHECK-SIL: copy_addr {{%.*}} to {{%.*}} : $*(Float, Float) // CHECK-SIL-NOT: copy_addr {{%.*}} to {{%.*}} : $*Float -// CHECK-SIL: switch_enum [[BB1_PRED]] : $_AD__cond_tuple_var_bb1__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb1__Pred__src_0_wrt_0.bb0!enumelt: bb5 +// CHECK-SIL: switch_enum [[BB2_PRED]] : $_AD__cond_tuple_var_bb2__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb2__Pred__src_0_wrt_0.bb0!enumelt: bb6 -// CHECK-SIL: bb3([[BB3_PRED2_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0): -// CHECK-SIL: br bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB3_PRED2_TRAMP_PB_STRUCT]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0) +// CHECK-SIL: bb3([[BB3_PRED1_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0): +// CHECK-SIL: br bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB3_PRED1_TRAMP_PB_STRUCT]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0) -// CHECK-SIL: bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB2_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0): -// CHECK-SIL: [[BB2_PRED:%.*]] = destructure_struct [[BB2_PB_STRUCT]] +// CHECK-SIL: bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB1_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0): +// CHECK-SIL: [[BB1_PRED:%.*]] = destructure_struct [[BB1_PB_STRUCT]] // CHECK-SIL: copy_addr {{%.*}} to {{%.*}} : $*(Float, Float) // CHECK-SIL-NOT: copy_addr {{%.*}} to {{%.*}} : $*Float -// CHECK-SIL: switch_enum [[BB2_PRED]] : $_AD__cond_tuple_var_bb2__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb2__Pred__src_0_wrt_0.bb0!enumelt: bb6 +// CHECK-SIL: switch_enum [[BB1_PRED]] : $_AD__cond_tuple_var_bb1__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb1__Pred__src_0_wrt_0.bb0!enumelt: bb5 // CHECK-SIL: bb5([[BB1_PRED0_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb0__PB__src_0_wrt_0): // CHECK-SIL: br bb7({{%.*}} : $Float, [[BB1_PRED0_TRAMP_PB_STRUCT]] : $_AD__cond_tuple_var_bb0__PB__src_0_wrt_0) @@ -276,3 +278,4 @@ func cond_tuple_var(_ x: Float) -> Float { // CHECK-SIL: bb7({{%.*}} : $Float, [[BB0_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb0__PB__src_0_wrt_0): // CHECK-SIL: return {{%.*}} : $Float +// CHECK-SIL-LABEL: } // end sil function 'AD__cond_tuple_var__pullback_src_0_wrt_0' diff --git a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift index 9473311a62247..22d3fca6a17c3 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift @@ -32,22 +32,16 @@ func conditional(_ x: Float, _ flag: Bool) -> Float { func throwing() throws -> Void {} -// expected-error @+2 {{function is not differentiable}} -// expected-note @+2 {{when differentiating this function definition}} @differentiable func try_apply(_ x: Float) -> Float { - // expected-note @+1 {{cannot differentiate unsupported control flow}} try! throwing() return x } func rethrowing(_ x: () throws -> Void) rethrows -> Void {} -// expected-error @+2 {{function is not differentiable}} -// expected-note @+2 {{when differentiating this function definition}} @differentiable func try_apply_rethrows(_ x: Float) -> Float { - // expected-note @+1 {{cannot differentiate unsupported control flow}} rethrowing({}) return x } @@ -307,14 +301,14 @@ struct TF_687 : Differentiable { } } // expected-error @+2 {{function is not differentiable}} -// expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} +// expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{78-78=withoutDerivative(at: }} {{79-79=)}} let _: @differentiable (Float) -> TF_687 = { x in TF_687(x, dummy: x) } // expected-error @+1 {{function is not differentiable}} @differentiable // expected-note @+1 {{when differentiating this function definition}} func roundingGivesError(x: Float) -> Float { - // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} {{16-16=withoutDerivative(at: }} {{22-22=)}} return Float(Int(x)) } @@ -694,7 +688,7 @@ func differentiableProjectedValueAccess(_ s: Struct) -> Float { // expected-note @+2 {{when differentiating this function definition}} @differentiable func projectedValueAccess(_ s: Struct) -> Float { - // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} {{3-3=withoutDerivative(at: }} {{7-7=)}} s.$y.wrappedValue } @@ -720,7 +714,7 @@ func modify(_ s: Struct, _ x: Float) -> Float { func tupleArrayLiteralInitialization(_ x: Float, _ y: Float) -> Float { // `Array<(Float, Float)>` does not conform to `Differentiable`. let array = [(x * y, x * y)] - // expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{10-10=withoutDerivative(at: }} {{15-15=)}} return array[0].0 } diff --git a/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift b/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift index f028db4baca4f..3abe2229ea33f 100644 --- a/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -enable-experimental-forward-mode-differentiation -emit-sil -verify %s +// RUN: %target-swift-frontend -emit-sil -enable-experimental-forward-mode-differentiation -verify %s // Test forward-mode differentiation transform diagnostics. @@ -6,6 +6,7 @@ // forward mode reaches feature parity with reverse mode. import _Differentiation +import DifferentiationUnittest //===----------------------------------------------------------------------===// // Basic function @@ -46,8 +47,6 @@ func nonVariedResult(_ x: Float) -> Float { // Multiple results //===----------------------------------------------------------------------===// -// TODO(TF-983): Support differentiation of multiple results. -/* func multipleResults(_ x: Float) -> (Float, Float) { return (x, x) } @@ -56,28 +55,21 @@ func usesMultipleResults(_ x: Float) -> Float { let tuple = multipleResults(x) return tuple.0 + tuple.1 } -*/ //===----------------------------------------------------------------------===// // `inout` parameter differentiation //===----------------------------------------------------------------------===// -// expected-error @+1 {{function is not differentiable}} @differentiable -// expected-note @+1 {{when differentiating this function definition}} func activeInoutParamNonactiveInitialResult(_ x: Float) -> Float { var result: Float = 1 - // expected-note @+1 {{cannot differentiate through 'inout' arguments}} result += x return result } -// expected-error @+1 {{function is not differentiable}} @differentiable -// expected-note @+1 {{when differentiating this function definition}} func activeInoutParamTuple(_ x: Float) -> Float { var tuple = (x, x) - // expected-note @+1 {{cannot differentiate through 'inout' arguments}} tuple.0 *= x return x * tuple.0 } @@ -94,49 +86,34 @@ func activeInoutParamControlFlow(_ array: [Float]) -> Float { return result } +struct X: Differentiable { + var x: Float + + @differentiable(wrt: y) + mutating func mutate(_ y: X) { self.x = y.x } +} + +@differentiable +func activeMutatingMethod(_ x: Float) -> Float { + let x1 = X.init(x: x) + var x2 = X.init(x: 0) + x2.mutate(x1) + return x1.x +} + + struct Mut: Differentiable {} extension Mut { @differentiable(wrt: x) mutating func mutatingMethod(_ x: Mut) {} } -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. -/* -@differentiable(wrt: x) -func nonActiveInoutParam(_ nonactive: inout Mut, _ x: Mut) -> Mut { - return nonactive.mutatingMethod(x) -} -*/ - -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. -/* @differentiable(wrt: x) func activeInoutParamMutatingMethod(_ x: Mut) -> Mut { var result = x - result = result.mutatingMethod(result) + result.mutatingMethod(result) return result } -*/ - -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. -/* -@differentiable(wrt: x) -func activeInoutParamMutatingMethodVar(_ nonactive: inout Mut, _ x: Mut) -> Mut { - var result = nonactive - result = result.mutatingMethod(x) - return result -} -*/ - -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. -/* -@differentiable(wrt: x) -func activeInoutParamMutatingMethodTuple(_ nonactive: inout Mut, _ x: Mut) -> Mut { - var result = (nonactive, x) - let result2 = result.0.mutatingMethod(result.0) - return result2 -} -*/ //===----------------------------------------------------------------------===// // Subset parameter differentiation thunks @@ -261,12 +238,16 @@ final class ClassTangentPropertyWrongType: Differentiable { func move(along direction: TangentVector) {} } -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. +// SR-13464: Missing support for classes in forward-mode AD /* +// xpected-error @+2 {{function is not differentiable}} +// xpected-note @+3 {{when differentiating this function definition}} @differentiable @_silgen_name("test_class_tangent_property_wrong_type") func testClassTangentPropertyWrongType(_ c: ClassTangentPropertyWrongType) -> Float { + // xpected-warning @+1 {{variable 'tmp' was never mutated}} var tmp = c + // xpected-note @+1 {{cannot differentiate access to property 'ClassTangentPropertyWrongType.x' because 'ClassTangentPropertyWrongType.TangentVector.x' does not have expected type 'Float.TangentVector' (aka 'Float')}} return tmp.x } */ @@ -306,12 +287,16 @@ final class ClassTangentPropertyNotStored: Differentiable { func move(along direction: TangentVector) {} } -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. +// SR-13464: Missing support for classes in forward-mode AD /* +// xpected-error @+2 {{function is not differentiable}} +// xpected-note @+3 {{when differentiating this function definition}} @differentiable @_silgen_name("test_class_tangent_property_not_stored") func testClassTangentPropertyNotStored(_ c: ClassTangentPropertyNotStored) -> Float { + // xpected-warning @+1 {{variable 'tmp' was never mutated}} var tmp = c + // xpected-note @+1 {{cannot differentiate access to property 'ClassTangentPropertyNotStored.x' because 'ClassTangentPropertyNotStored.TangentVector.x' is not a stored property}} return tmp.x } */ diff --git a/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift b/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift index 4b1110b39636e..228c782375eba 100644 --- a/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift +++ b/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift @@ -29,26 +29,62 @@ func testEmpty() { assertConformsToAdditiveArithmetic(Empty.TangentVector.self) } +protocol DifferentiableWithNonmutatingMoveAlong: Differentiable {} +extension DifferentiableWithNonmutatingMoveAlong { + func move(along _: TangentVector) {} +} + +class EmptyWithInheritedNonmutatingMoveAlong: DifferentiableWithNonmutatingMoveAlong { + typealias TangentVector = Empty.TangentVector + var zeroTangentVectorInitializer: () -> TangentVector { { .init() } } + static func proof_that_i_have_nonmutating_move_along() { + let empty = EmptyWithInheritedNonmutatingMoveAlong() + empty.move(along: .init()) + } +} + +class EmptyWrapper: Differentiable {} +func testEmptyWrapper() { + assertConformsToAdditiveArithmetic(Empty.TangentVector.self) + assertConformsToAdditiveArithmetic(EmptyWrapper.TangentVector.self) +} + // Test structs with `let` stored properties. // Derived conformances fail because `mutating func move` requires all stored // properties to be mutable. -class ImmutableStoredProperties: Differentiable { +class ImmutableStoredProperties: Differentiable { var okay: Float // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Int' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let nondiff: Int - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties not marked with `@noDerivative` to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties not marked with `@noDerivative` to be mutable or have a non-mutating 'move(along:)'; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let diff: Float - init() { + let letClass: Empty // No error on class-bound differentiable `let` with a non-mutating 'move(along:)'. + + let letClassWithInheritedNonmutatingMoveAlong: EmptyWithInheritedNonmutatingMoveAlong + + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties not marked with `@noDerivative` to be mutable or have a non-mutating 'move(along:)'; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + let letClassGeneric: T // Error due to lack of non-mutating 'move(along:)'. + + let letClassWrappingGeneric: EmptyWrapper // No error on class-bound differentiable `let` with a non-mutating 'move(along:)'. + + init(letClassGeneric: T) { okay = 0 nondiff = 0 diff = 0 + letClass = Empty() + self.letClassGeneric = letClassGeneric + self.letClassWrappingGeneric = EmptyWrapper() } } func testImmutableStoredProperties() { - _ = ImmutableStoredProperties.TangentVector(okay: 1) + _ = ImmutableStoredProperties.TangentVector( + okay: 1, + letClass: Empty.TangentVector(), + letClassWithInheritedNonmutatingMoveAlong: Empty.TangentVector(), + letClassWrappingGeneric: EmptyWrapper.TangentVector()) } class MutableStoredPropertiesWithInitialValue: Differentiable { var x = Float(1) @@ -56,7 +92,7 @@ class MutableStoredPropertiesWithInitialValue: Differentiable { } // Test class with both an empty constructor and memberwise initializer. class AllMixedStoredPropertiesHaveInitialValue: Differentiable { - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'AllMixedStoredPropertiesHaveInitialValue' requires all stored properties not marked with `@noDerivative` to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'AllMixedStoredPropertiesHaveInitialValue' requires all stored properties not marked with `@noDerivative` to be mutable or have a non-mutating 'move(along:)'; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let x = Float(1) var y = Float(1) // Memberwise initializer should be `init(y:)` since `x` is immutable. @@ -550,7 +586,7 @@ struct Generic {} extension Generic: Differentiable where T: Differentiable {} class WrappedProperties: Differentiable { - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'WrappedProperties' requires 'wrappedValue' in property wrapper 'ImmutableWrapper' to be mutable; add an explicit '@noDerivative' attribute}} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'WrappedProperties' requires 'wrappedValue' in property wrapper 'ImmutableWrapper' to be mutable or have a non-mutating 'move(along:)'; add an explicit '@noDerivative' attribute}} @ImmutableWrapper var immutableInt: Generic = Generic() // expected-warning @+1 {{stored property 'mutableInt' has no derivative because 'Generic' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} @@ -570,8 +606,10 @@ class WrappedProperties: Differentiable { // Test derived conformances in disallowed contexts. -// expected-error @+1 2 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} extension OtherFileNonconforming: Differentiable {} +// expected-error @-1 {{extension outside of file declaring class 'OtherFileNonconforming' prevents automatic synthesis of 'move(along:)' for protocol 'Differentiable'}} +// expected-error @-2 {{extension outside of file declaring class 'OtherFileNonconforming' prevents automatic synthesis of 'zeroTangentVectorInitializer' for protocol 'Differentiable'}} -// expected-error @+1 2 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} extension GenericOtherFileNonconforming: Differentiable {} +// expected-error @-1 {{extension outside of file declaring generic class 'GenericOtherFileNonconforming' prevents automatic synthesis of 'move(along:)' for protocol 'Differentiable'}} +// expected-error @-2 {{extension outside of file declaring generic class 'GenericOtherFileNonconforming' prevents automatic synthesis of 'zeroTangentVectorInitializer' for protocol 'Differentiable'}} diff --git a/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift b/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift index f6958318df05e..993be5409c16f 100644 --- a/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift +++ b/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift @@ -113,8 +113,12 @@ where T: AdditiveArithmetic {} // Test derived conformances in disallowed contexts. -// expected-error @+1 3 {{implementation of 'AdditiveArithmetic' cannot be automatically synthesized in an extension in a different file to the type}} extension OtherFileNonconforming: AdditiveArithmetic {} +// expected-error @-1 {{extension outside of file declaring struct 'OtherFileNonconforming' prevents automatic synthesis of 'zero' for protocol 'AdditiveArithmetic'}} +// expected-error @-2 {{extension outside of file declaring struct 'OtherFileNonconforming' prevents automatic synthesis of '+' for protocol 'AdditiveArithmetic'}} +// expected-error @-3 {{extension outside of file declaring struct 'OtherFileNonconforming' prevents automatic synthesis of '-' for protocol 'AdditiveArithmetic'}} -// expected-error @+1 3 {{implementation of 'AdditiveArithmetic' cannot be automatically synthesized in an extension in a different file to the type}} extension GenericOtherFileNonconforming: AdditiveArithmetic {} +// expected-error @-1 {{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of 'zero' for protocol 'AdditiveArithmetic'}} +// expected-error @-2 {{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of '+' for protocol 'AdditiveArithmetic'}} +// expected-error @-3 {{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of '-' for protocol 'AdditiveArithmetic'}} diff --git a/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift b/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift index 02f9154426cf4..d8ec6e56c588f 100644 --- a/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift +++ b/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift @@ -11,6 +11,35 @@ func testEmpty() { assertConformsToAdditiveArithmetic(Empty.TangentVector.self) } +struct EmptyWithConcreteNonmutatingMoveAlong: Differentiable { + typealias TangentVector = Empty.TangentVector + var zeroTangentVectorInitializer: () -> TangentVector { { .init() } } + func move(along _: TangentVector) {} + static func proof_that_i_have_nonmutating_move_along() { + let empty = Self() + empty.move(along: .init()) + } +} + +protocol DifferentiableWithNonmutatingMoveAlong: Differentiable {} +extension DifferentiableWithNonmutatingMoveAlong { + func move(along _: TangentVector) {} +} + +struct EmptyWithInheritedNonmutatingMoveAlong: DifferentiableWithNonmutatingMoveAlong { + typealias TangentVector = Empty.TangentVector + var zeroTangentVectorInitializer: () -> TangentVector { { .init() } } + static func proof_that_i_have_nonmutating_move_along() { + let empty = Self() + empty.move(along: .init()) + } +} + +class EmptyClass: Differentiable {} +func testEmptyClass() { + assertConformsToAdditiveArithmetic(EmptyClass.TangentVector.self) +} + // Test interaction with `AdditiveArithmetic` derived conformances. // Previously, this crashed due to duplicate memberwise initializer synthesis. struct EmptyAdditiveArithmetic: AdditiveArithmetic, Differentiable {} @@ -21,14 +50,24 @@ struct EmptyAdditiveArithmetic: AdditiveArithmetic, Differentiable {} struct ImmutableStoredProperties: Differentiable { var okay: Float - // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Int' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute, or conform 'ImmutableStoredProperties' to 'AdditiveArithmetic'}} {{3-3=@noDerivative }} + // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Int' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let nondiff: Int - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties not marked with `@noDerivative` to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute, or conform 'ImmutableStoredProperties' to 'AdditiveArithmetic}} {{3-3=@noDerivative }} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties not marked with `@noDerivative` to be mutable or have a non-mutating 'move(along:)'; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let diff: Float + + let nonmutatingMoveAlongStruct: EmptyWithConcreteNonmutatingMoveAlong + + let inheritedNonmutatingMoveAlongStruct: EmptyWithInheritedNonmutatingMoveAlong + + let diffClass: EmptyClass // No error on class-bound `let` with a non-mutating `move(along:)`. } func testImmutableStoredProperties() { - _ = ImmutableStoredProperties.TangentVector(okay: 1) + _ = ImmutableStoredProperties.TangentVector( + okay: 1, + nonmutatingMoveAlongStruct: Empty.TangentVector(), + inheritedNonmutatingMoveAlongStruct: Empty.TangentVector(), + diffClass: EmptyClass.TangentVector()) } struct MutableStoredPropertiesWithInitialValue: Differentiable { var x = Float(1) @@ -36,7 +75,7 @@ struct MutableStoredPropertiesWithInitialValue: Differentiable { } // Test struct with both an empty constructor and memberwise initializer. struct AllMixedStoredPropertiesHaveInitialValue: Differentiable { - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'AllMixedStoredPropertiesHaveInitialValue' requires all stored properties not marked with `@noDerivative` to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'AllMixedStoredPropertiesHaveInitialValue' requires all stored properties not marked with `@noDerivative` to be mutable or have a non-mutating 'move(along:)'; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let x = Float(1) var y = Float(1) // Memberwise initializer should be `init(y:)` since `x` is immutable. @@ -363,7 +402,7 @@ struct Generic {} extension Generic: Differentiable where T: Differentiable {} struct WrappedProperties: Differentiable { - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'WrappedProperties' requires 'wrappedValue' in property wrapper 'ImmutableWrapper' to be mutable; add an explicit '@noDerivative' attribute}} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'WrappedProperties' requires 'wrappedValue' in property wrapper 'ImmutableWrapper' to be mutable or have a non-mutating 'move(along:)'; add an explicit '@noDerivative' attribute}} @ImmutableWrapper var immutableInt: Generic // expected-warning @+1 {{stored property 'mutableInt' has no derivative because 'Generic' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} @@ -383,8 +422,10 @@ struct WrappedProperties: Differentiable { // Verify that cross-file derived conformances are disallowed. -// expected-error @+1 2 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} extension OtherFileNonconforming: Differentiable {} +// expected-error @-1 {{extension outside of file declaring struct 'OtherFileNonconforming' prevents automatic synthesis of 'move(along:)' for protocol 'Differentiable'}} +// expected-error @-2 {{extension outside of file declaring struct 'OtherFileNonconforming' prevents automatic synthesis of 'zeroTangentVectorInitializer' for protocol 'Differentiable'}} -// expected-error @+1 2 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} extension GenericOtherFileNonconforming: Differentiable {} +// expected-error @-1 {{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of 'move(along:)' for protocol 'Differentiable'}} +// expected-error @-2 {{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of 'zeroTangentVectorInitializer' for protocol 'Differentiable'}} diff --git a/test/AutoDiff/Sema/derivative_attr_type_checking.swift b/test/AutoDiff/Sema/derivative_attr_type_checking.swift index 598dc3600879a..451bf4dd4fb51 100644 --- a/test/AutoDiff/Sema/derivative_attr_type_checking.swift +++ b/test/AutoDiff/Sema/derivative_attr_type_checking.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend-typecheck -verify -disable-availability-checking %s +// RUN: %target-swift-frontend-typecheck -enable-testing -verify -disable-availability-checking %s // Swift.AdditiveArithmetic:3:17: note: cannot yet register derivative default implementation for protocol requirements diff --git a/test/AutoDiff/Sema/differentiable_attr_type_checking.swift b/test/AutoDiff/Sema/differentiable_attr_type_checking.swift index a14090d14fe52..ac54b0bc349ed 100644 --- a/test/AutoDiff/Sema/differentiable_attr_type_checking.swift +++ b/test/AutoDiff/Sema/differentiable_attr_type_checking.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend-typecheck -verify -disable-availability-checking %s +// RUN: %target-swift-frontend-typecheck -enable-testing -verify -disable-availability-checking %s import _Differentiation diff --git a/test/AutoDiff/Sema/transpose_attr_type_checking.swift b/test/AutoDiff/Sema/transpose_attr_type_checking.swift index a49ff941a49d3..513e0b3d83ab9 100644 --- a/test/AutoDiff/Sema/transpose_attr_type_checking.swift +++ b/test/AutoDiff/Sema/transpose_attr_type_checking.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend-typecheck -verify %s +// RUN: %target-swift-frontend-typecheck -enable-testing -verify %s import _Differentiation diff --git a/test/AutoDiff/compiler_crashers_fixed/sr13411-tangent-value-category-mismatch.swift b/test/AutoDiff/compiler_crashers_fixed/sr13411-tangent-value-category-mismatch.swift new file mode 100644 index 0000000000000..a7678c55ffd6e --- /dev/null +++ b/test/AutoDiff/compiler_crashers_fixed/sr13411-tangent-value-category-mismatch.swift @@ -0,0 +1,12 @@ +// RUN: %target-build-swift %s +// REQUIRES: asserts + +// SR-13411: Semantic member getter pullback generation crash due to tangent value category mismatch + +import _Differentiation + +struct Dense: Differentiable { + @differentiable + var bias: Float? +} + diff --git a/test/AutoDiff/validation-test/class_differentiation.swift b/test/AutoDiff/validation-test/class_differentiation.swift index 2ae7619486214..ee76c21ba1d87 100644 --- a/test/AutoDiff/validation-test/class_differentiation.swift +++ b/test/AutoDiff/validation-test/class_differentiation.swift @@ -524,4 +524,19 @@ ClassTests.test("ClassProperties") { gradient(at: Super(base: 2)) { foo in foo.squared }) } +ClassTests.test("LetProperties") { + final class Foo: Differentiable { + var x: Tracked + init(x: Tracked) { self.x = x } + } + final class Bar: Differentiable { + let x = Foo(x: 2) + } + let bar = Bar() + let grad = gradient(at: bar) { bar in (bar.x.x * bar.x.x).value } + expectEqual(Bar.TangentVector(x: .init(x: 6.0)), grad) + bar.move(along: grad) + expectEqual(8.0, bar.x.x) +} + runAllTests() diff --git a/test/AutoDiff/validation-test/control_flow.swift b/test/AutoDiff/validation-test/control_flow.swift index d2042a1135216..ea3dff8e0ba2a 100644 --- a/test/AutoDiff/validation-test/control_flow.swift +++ b/test/AutoDiff/validation-test/control_flow.swift @@ -736,4 +736,85 @@ ControlFlowTests.test("BranchingCastInstructions") { expectEqual((3, 1), valueWithGradient(at: Float(3), in: conditionalCast)) } +ControlFlowTests.test("ThrowingCalls") { + // TF-433: Test non-active `try_apply` differentiation. + func throwing() throws -> Void {} + + @differentiable + func testThrowing(_ x: Float) -> Float { + try! throwing() + return x + } + expectEqual(10, pullback(at: 3, in: testThrowing)(10)) + + @differentiable + func testThrowingGeneric(_ x: T) -> T { + try! throwing() + return x + } + expectEqual(10, pullback(at: 3, in: testThrowingGeneric)(10)) + + func rethrowing(_ body: () throws -> Void) rethrows -> Void {} + + @differentiable + func testRethrowingIdentity(_ x: Float) -> Float { + rethrowing({}) // non-active `try_apply` + return x + } + expectEqual(10, pullback(at: 3, in: testRethrowingIdentity)(10)) + + @differentiable + func testRethrowingIdentityGeneric(_ x: T) -> T { + rethrowing({}) // non-active `try_apply` + return x + } + expectEqual(10, pullback(at: 3, in: testRethrowingIdentityGeneric)(10)) + + @differentiable + func testComplexControlFlow(_ x: Float) -> Float { + rethrowing({}) + for _ in 0..(_ x: T) -> T { + rethrowing({}) + for _ in 0..<10 { + if true { + rethrowing({}) + } + rethrowing({}) // non-active `try_apply` + } + rethrowing({}) + return x + } + expectEqual(10, pullback(at: 3, in: testComplexControlFlowGeneric)(10)) + + // Test `Array.map(_:)`, which is rethrowing. + func testArrayMap(_ x: [Float]) -> [Float] { + let max = x.map { $0 }.max()! // non-active `try_apply` + _blackHole(max) + return x + } + expectEqual([10, 10], pullback(at: [2, 3], in: testArrayMap)([10, 10])) + + // Test `Bool.&&(_:)`, which is rethrowing. + func testBooleanShortCircuitingOperations(_ x: Float, bool: Bool) -> Float { + if bool && bool || bool { // non-active `try_apply` + return x * x + } + return x + x + } + expectEqual(6, gradient(at: 3, in: { x in testBooleanShortCircuitingOperations(x, bool: true) })) + expectEqual(2, gradient(at: 3, in: { x in testBooleanShortCircuitingOperations(x, bool: false) })) +} + runAllTests() diff --git a/test/AutoDiff/validation-test/forward_mode.swift b/test/AutoDiff/validation-test/forward_mode.swift index c29b87f34c198..906d9dedbee23 100644 --- a/test/AutoDiff/validation-test/forward_mode.swift +++ b/test/AutoDiff/validation-test/forward_mode.swift @@ -1319,6 +1319,76 @@ ForwardModeTests.test("ForceUnwrapping") { expectEqual(5, forceUnwrap(Float(2))) } +ForwardModeTests.test("NonVariedResult") { + @differentiable(wrt: x) + func nonWrtInoutParam(_ x: T, _ y: inout T) { + y = x + } + + @differentiable + func wrtInoutParam(_ x: T, _ y: inout T) { + y = x + } + + @differentiable(wrt: x) + func nonWrtInoutParamNonVaried(_ x: T, _ y: inout T) {} + + @differentiable(wrt: x) + func wrtInoutParamNonVaried(_ x: T, _ y: inout T) {} + + @differentiable + func variedResultTracked(_ x: Tracked) -> Tracked { + var result: Tracked = 0 + nonWrtInoutParam(x, &result) + return result + } + + @differentiable + func variedResultTracked2(_ x: Tracked) -> Tracked { + var result: Tracked = 0 + wrtInoutParam(x, &result) + return result + } + + @differentiable + func nonVariedResultTracked(_ x: Tracked) -> Tracked { + var result: Tracked = 0 + nonWrtInoutParamNonVaried(x, &result) + return result + } + + @differentiable + func nonVariedResultTracked2(_ x: Tracked) -> Tracked { + // expected-warning @+1 {{variable 'result' was never mutated}} + var result: Tracked = 0 + return result + } + + @differentiable + func nonVariedResultTracked3(_ x: Tracked) -> Tracked { + return 0 + } + + @differentiable + func nonVariedResultTracked4(_ x: Tracked) -> Tracked { + var result: Tracked = 0 + wrtInoutParamNonVaried(x, &result) + return result + } +} + +ForwardModeTests.test("ApplyNonActiveIndirectResult") { + func identity(_ x: T) -> T { x } + + @differentiable + func applyNonactiveArgumentActiveIndirectResult(_ x: Tracked) -> Tracked { + var y = identity(0 as Tracked) + y = x + return y + } + expectEqual(1.0, derivative(at: 2, in: applyNonactiveArgumentActiveIndirectResult)) +} + //===----------------------------------------------------------------------===// // Array methods from ArrayDifferentiation.swift //===----------------------------------------------------------------------===// diff --git a/test/AutoDiff/validation-test/forward_mode_inout.swift b/test/AutoDiff/validation-test/forward_mode_inout.swift new file mode 100644 index 0000000000000..42ed40a89c6ca --- /dev/null +++ b/test/AutoDiff/validation-test/forward_mode_inout.swift @@ -0,0 +1,161 @@ +// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-forward-mode-differentiation) +// REQUIRES: executable_test + +import StdlibUnittest +import DifferentiationUnittest + +var ForwardModeInoutTests = TestSuite("ForwardModeInoutDifferentiation") + +//===----------------------------------------------------------------------===// +// Inout tests. +//===----------------------------------------------------------------------===// + +import DifferentiationUnittest +import StdlibUnittest + +ForwardModeInoutTests.test("Float.+=") { + func mutatingAddWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result += y + return result + } + expectEqual(20, differential(at: 4, 5, in: mutatingAddWrapper)(10, 10)) +} + +ForwardModeInoutTests.test("Float.-=") { + func mutatingSubtractWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result -= y + return result + } + expectEqual(0, differential(at: 4, 5, in: mutatingSubtractWrapper)(10, 10)) + expectEqual(10, differential(at: 4, 5, in: mutatingSubtractWrapper)(20, 10)) +} + +ForwardModeInoutTests.test("Float.*=") { + func mutatingMultiplyWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result *= y + return result + } + expectEqual(22, differential(at: 4, 5, in: mutatingMultiplyWrapper)(2, 3)) +} + +ForwardModeInoutTests.test("Float./=") { + func mutatingDivideWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result /= y + return result + } + expectEqual(-1, differential(at: 2, 3, in: mutatingDivideWrapper)(3, 9)) +} + +// Simplest possible `inout` parameter differentiation. +ForwardModeInoutTests.test("InoutIdentity") { + // Semantically, an empty function with an `inout` parameter is an identity + // function. + func inoutIdentity(_ x: inout Float) {} + + func identity(_ x: Float) -> Float { + var result = x + inoutIdentity(&result) + return result + } + expectEqual(1, derivative(at: 10, in: identity)) + expectEqual(10, differential(at: 10, in: identity)(10)) + + func inoutIdentityGeneric(_ x: inout T) {} + + func identityGeneric(_ x: T) -> T { + var result: T = x + inoutIdentityGeneric(&result) + return result + } + expectEqual(1, derivative(at: 10.0, in: identityGeneric)) + expectEqual(10, differential(at: 10.0, in: identityGeneric)(10)) +} + +ForwardModeInoutTests.test("MultipleInoutParams") { + func swap(_ x: inout T, _ y: inout T) { + let z = x + x = y + y = z + } + + func first(_ x: T, _ y: T) -> T { + var p1 = x + var p2 = y + swap(&p1, &p2) + return p2 + } + expectEqual(1, differential(at: 1, 1, in: first)(1, 2)) + + func second(_ x: T, _ y: T) -> T { + var p1 = x + var p2 = y + swap(&p1, &p2) + return p1 + } + expectEqual(2, differential(at: 1, 1, in: second)(1, 2)) +} + +ForwardModeInoutTests.test("StructMutatingMethod") { + struct Mut: Differentiable { + var x: Float + + mutating func add(_ y: Float) { + self.x += y + } + + mutating func addMut(_ m: Mut) { + self.x += m.x + } + } + + func identity(_ y: Float) -> Float { + var mut = Mut(x: 0.0) + mut.add(y) + return mut.x + } + expectEqual(1, derivative(at: 1, in: identity)) + + func identity2(_ y: Float) -> Float { + var mut = Mut(x: 0.0) + let mut2 = Mut(x: y) + mut.addMut(mut2) + return mut.x + } + expectEqual(1, derivative(at: 1, in: identity2)) + + func double(_ y: Float) -> Float { + var mut = Mut(x: y) + mut.add(y) + return mut.x + } + expectEqual(2, derivative(at: 1, in: double)) + + func double2(_ y: Float) -> Float { + var mut = Mut(x: y) + let mut2 = Mut(x: y) + mut.addMut(mut2) + return mut.x + } + expectEqual(2, derivative(at: 1, in: double2)) + + func square(_ y: Float) -> Float { + var mut = Mut(x: 0.0) + mut.add(y * y) + return mut.x + } + expectEqual(6, derivative(at: 3, in: square)) + + func square2(_ y: Float) -> Float { + var mut = Mut(x: 0.0) + let mut2 = Mut(x: y * y) + mut.addMut(mut2) + return mut.x + } + expectEqual(6, derivative(at: 3, in: square2)) +} + +runAllTests() diff --git a/test/AutoDiff/validation-test/inout_parameters.swift b/test/AutoDiff/validation-test/inout_parameters.swift index 4cbd25590b943..626546040a900 100644 --- a/test/AutoDiff/validation-test/inout_parameters.swift +++ b/test/AutoDiff/validation-test/inout_parameters.swift @@ -1,11 +1,174 @@ // RUN: %target-run-simple-swift // REQUIRES: executable_test +// `inout` parameter differentiation tests. + import DifferentiationUnittest import StdlibUnittest var InoutParameterAutoDiffTests = TestSuite("InoutParameterDifferentiation") +// TODO(TF-1173): Move floating-point mutating operation tests to +// `test/AutoDiff/stdlib/floating_point.swift.gyb` when forward-mode +// differentiation supports `inout` parameter differentiation. + +InoutParameterAutoDiffTests.test("Float.+=") { + func mutatingAddWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result += y + return result + } + expectEqual((1, 1), gradient(at: 4, 5, in: mutatingAddWrapper)) + expectEqual((10, 10), pullback(at: 4, 5, in: mutatingAddWrapper)(10)) +} + +InoutParameterAutoDiffTests.test("Float.-=") { + func mutatingSubtractWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result += y + return result + } + expectEqual((1, 1), gradient(at: 4, 5, in: mutatingSubtractWrapper)) + expectEqual((10, 10), pullback(at: 4, 5, in: mutatingSubtractWrapper)(10)) +} + +InoutParameterAutoDiffTests.test("Float.*=") { + func mutatingMultiplyWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result += y + return result + } + expectEqual((1, 1), gradient(at: 4, 5, in: mutatingMultiplyWrapper)) + expectEqual((10, 10), pullback(at: 4, 5, in: mutatingMultiplyWrapper)(10)) +} + +InoutParameterAutoDiffTests.test("Float./=") { + func mutatingDivideWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result += y + return result + } + expectEqual((1, 1), gradient(at: 4, 5, in: mutatingDivideWrapper)) + expectEqual((10, 10), pullback(at: 4, 5, in: mutatingDivideWrapper)(10)) +} + +// Simplest possible `inout` parameter differentiation. +InoutParameterAutoDiffTests.test("InoutIdentity") { + // Semantically, an empty function with an `inout` parameter is an identity + // function. + func inoutIdentity(_ x: inout Float) {} + + func identity(_ x: Float) -> Float { + var result = x + inoutIdentity(&result) + return result + } + expectEqual(1, gradient(at: 10, in: identity)) + expectEqual(10, pullback(at: 10, in: identity)(10)) +} + +extension Float { + // Custom version of `Float.*=`, implemented using `Float.*` and mutation. + // Verify that its generated derivative has the same behavior as the + // registered derivative for `Float.*=`. + @differentiable + static func multiplyAssign(_ lhs: inout Float, _ rhs: Float) { + lhs = lhs * rhs + } +} + +InoutParameterAutoDiffTests.test("ControlFlow") { + func sum(_ array: [Float]) -> Float { + var result: Float = 0 + for i in withoutDerivative(at: array.indices) { + result += array[i] + } + return result + } + expectEqual([1, 1, 1], gradient(at: [1, 2, 3], in: sum)) + + func product(_ array: [Float]) -> Float { + var result: Float = 1 + for i in withoutDerivative(at: array.indices) { + result *= array[i] + } + return result + } + expectEqual([20, 15, 12], gradient(at: [3, 4, 5], in: product)) + + func productCustom(_ array: [Float]) -> Float { + var result: Float = 1 + for i in withoutDerivative(at: array.indices) { + Float.multiplyAssign(&result, array[i]) + } + return result + } + expectEqual([20, 15, 12], gradient(at: [3, 4, 5], in: productCustom)) +} + +InoutParameterAutoDiffTests.test("SetAccessor") { + struct S: Differentiable { + var x: Float + + var computed: Float { + get { x } + set { x = newValue } + } + } + + // `squared` implemented using a `set` accessor. + func squared(_ x: Float) -> Float { + var s = S(x: 1) + s.x *= x + s.computed *= x + return s.x + } + expectEqual(6, gradient(at: 3, in: squared)) + expectEqual(8, gradient(at: 4, in: squared)) +} + +// Test differentiation wrt `inout` parameters that have a class type. +InoutParameterAutoDiffTests.test("InoutClassParameter") { + class Class: Differentiable { + @differentiable + var x: Float + + init(_ x: Float) { + self.x = x + } + } + + do { + func squaredViaMutation(_ c: inout Class) { + c = Class(c.x * c.x) + } + func squared(_ x: Float) -> Float { + var c = Class(x) + squaredViaMutation(&c) + return c.x + } + expectEqual((100, 20), valueWithGradient(at: 10, in: squared)) + expectEqual(200, pullback(at: 10, in: squared)(10)) + } + + do { + func squaredViaModifyAccessor(_ c: inout Class) { + // The line below calls `Class.x.modify`. + c.x *= c.x + } + func squared(_ x: Float) -> Float { + var c = Class(x) + squaredViaModifyAccessor(&c) + return c.x + } + // FIXME(TF-1080): Fix incorrect class property `modify` accessor derivative values. + // expectEqual((100, 20), valueWithGradient(at: 10, in: squared)) + // expectEqual(200, pullback(at: 10, in: squared)(10)) + expectEqual((100, 1), valueWithGradient(at: 10, in: squared)) + expectEqual(10, pullback(at: 10, in: squared)(10)) + } +} + // SR-13305: Test function with non-wrt `inout` parameter, which should be // treated as a differentiability result. diff --git a/test/AutoDiff/validation-test/optional-property.swift b/test/AutoDiff/validation-test/optional-property.swift new file mode 100644 index 0000000000000..7a8b150728e44 --- /dev/null +++ b/test/AutoDiff/validation-test/optional-property.swift @@ -0,0 +1,207 @@ +// RUN: %target-run-simple-swift +// RUN: %target-swift-emit-sil -Xllvm -debug-only=differentiation -o /dev/null 2>&1 %s | %FileCheck %s +// REQUIRES: executable_test + +// Test differentiation of `Optional` properties. + +import DifferentiationUnittest +import StdlibUnittest + +var OptionalTests = TestSuite("OptionalPropertyDifferentiation") + +// Test `Optional` struct stored properties. + +struct Struct: Differentiable { + var stored: Float + var optional: Float? + + @differentiable + func method() -> Float { + let s: Struct + do { + let tmp = Struct(stored: stored, optional: optional) + let tuple = (tmp, tmp) + s = tuple.0 + } + if let x = s.optional { + return x * s.stored + } + return s.stored + } +} + +// Check active SIL instructions in representative original functions. +// This tests SIL instruction coverage of derivative function cloners (e.g. PullbackCloner). + +// CHECK-LABEL: [AD] Activity info for ${{.*}}Struct{{.*}}method{{.*}} at (parameters=(0) results=(0)) +// CHECK: [ACTIVE] {{.*}} struct_extract {{%.*}} : $Struct, #Struct.stored +// CHECK: [ACTIVE] {{.*}} struct_extract {{%.*}} : $Struct, #Struct.optional +// CHECK: [ACTIVE] {{.*}} tuple ({{%.*}} : $Struct, {{%.*}} : $Struct) +// CHECK: [ACTIVE] {{.*}} destructure_tuple {{%.*}} : $(Struct, Struct) +// CHECK: [ACTIVE] {{.*}} struct_element_addr {{%.*}} : $*Struct, #Struct.optional +// CHECK: [ACTIVE] {{.*}} struct_element_addr {{%.*}} : $*Struct, #Struct.stored +// CHECK-LABEL: End activity info for ${{.*}}Struct{{.*}}method{{.*}} at (parameters=(0) results=(0)) + +// CHECK-LABEL: [AD] Activity info for $s4null6StructV6stored8optionalACSf_SfSgtcfC at (parameters=(0 1) results=(0)) +// CHECK: [ACTIVE] {{%.*}} struct $Struct ({{%.*}} : $Float, {{%.*}} : $Optional) +// CHECK-LABEL: End activity info for $s4null6StructV6stored8optionalACSf_SfSgtcfC at (parameters=(0 1) results=(0)) + +struct StructTracked: Differentiable { + var stored: NonresilientTracked + var optional: NonresilientTracked? + + @differentiable + func method() -> NonresilientTracked { + let s: StructTracked + do { + let tmp = StructTracked(stored: stored, optional: optional) + let tuple = (tmp, tmp) + s = tuple.0 + } + if let x = s.optional { + return x * s.stored + } + return s.stored + } +} + +struct StructGeneric: Differentiable { + var stored: T + var optional: T? + + @differentiable + func method() -> T { + let s: StructGeneric + do { + let tmp = StructGeneric(stored: stored, optional: optional) + let tuple = (tmp, tmp) + s = tuple.0 + } + if let x = s.optional { + return x + } + return s.stored + } +} + +OptionalTests.test("Optional struct stored properties") { + expectEqual( + valueWithGradient(at: Struct(stored: 3, optional: 4), in: { $0.method() }), + (12, .init(stored: 4, optional: .init(3)))) + expectEqual( + valueWithGradient(at: Struct(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) + + expectEqual( + valueWithGradient(at: StructTracked(stored: 3, optional: 4), in: { $0.method() }), + (12, .init(stored: 4, optional: .init(3)))) + expectEqual( + valueWithGradient(at: StructTracked(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) + + expectEqual( + valueWithGradient(at: StructGeneric(stored: 3, optional: 4), in: { $0.method() }), + (4, .init(stored: 0, optional: .init(1)))) + expectEqual( + valueWithGradient(at: StructGeneric(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) +} + +// Test `Optional` class stored properties. + +struct Class: Differentiable { + var stored: Float + var optional: Float? + + init(stored: Float, optional: Float?) { + self.stored = stored + self.optional = optional + } + + @differentiable + func method() -> Float { + let c: Class + do { + let tmp = Class(stored: stored, optional: optional) + let tuple = (tmp, tmp) + c = tuple.0 + } + if let x = c.optional { + return x * c.stored + } + return c.stored + } +} + +struct ClassTracked: Differentiable { + var stored: NonresilientTracked + var optional: NonresilientTracked? + + init(stored: NonresilientTracked, optional: NonresilientTracked?) { + self.stored = stored + self.optional = optional + } + + @differentiable + func method() -> NonresilientTracked { + let c: ClassTracked + do { + let tmp = ClassTracked(stored: stored, optional: optional) + let tuple = (tmp, tmp) + c = tuple.0 + } + if let x = c.optional { + return x * c.stored + } + return c.stored + } +} + +struct ClassGeneric: Differentiable { + var stored: T + var optional: T? + + init(stored: T, optional: T?) { + self.stored = stored + self.optional = optional + } + + @differentiable + func method() -> T { + let c: ClassGeneric + do { + let tmp = ClassGeneric(stored: stored, optional: optional) + let tuple = (tmp, tmp) + c = tuple.0 + } + if let x = c.optional { + return x + } + return c.stored + } +} + +OptionalTests.test("Optional class stored properties") { + expectEqual( + valueWithGradient(at: Class(stored: 3, optional: 4), in: { $0.method() }), + (12, .init(stored: 4, optional: .init(3)))) + expectEqual( + valueWithGradient(at: Class(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) + + expectEqual( + valueWithGradient(at: ClassTracked(stored: 3, optional: 4), in: { $0.method() }), + (12, .init(stored: 4, optional: .init(3)))) + expectEqual( + valueWithGradient(at: ClassTracked(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) + + expectEqual( + valueWithGradient(at: ClassGeneric>(stored: 3, optional: 4), in: { $0.method() }), + (4, .init(stored: 0, optional: .init(1)))) + expectEqual( + valueWithGradient(at: ClassGeneric>(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) +} + +runAllTests() diff --git a/test/AutoDiff/validation-test/optional.swift b/test/AutoDiff/validation-test/optional.swift index c2fc0fac4a695..09aa84d587da2 100644 --- a/test/AutoDiff/validation-test/optional.swift +++ b/test/AutoDiff/validation-test/optional.swift @@ -1,8 +1,10 @@ // RUN: %target-run-simple-swift // REQUIRES: executable_test -import StdlibUnittest +// Test differentiation of `Optional` values and operations. + import DifferentiationUnittest +import StdlibUnittest var OptionalTests = TestSuite("OptionalDifferentiation") @@ -10,11 +12,10 @@ var OptionalTests = TestSuite("OptionalDifferentiation") // Basic tests. //===----------------------------------------------------------------------===// +// TODO(TF-433): operator `??` lowers to an active `try_apply`. /* -// TODO(TF-433): operator `??` lowers to `try_apply` instead of `switch_enum`, -// which is not yet supported by differentiation. @differentiable -func optional1(_ maybeX: Float?) -> Float { +func optional_nil_coalescing(_ maybeX: Float?) -> Float { return maybeX ?? 10 } */ @@ -23,7 +24,7 @@ OptionalTests.test("Let") { @differentiable func optional_let(_ maybeX: Float?) -> Float { if let x = maybeX { - return x * x + return x * x } return 10 } @@ -33,13 +34,27 @@ OptionalTests.test("Let") { @differentiable func optional_let_tracked(_ maybeX: Tracked?) -> Tracked { if let x = maybeX { - return x * x + return x * x } return 10 } expectEqual(gradient(at: 10, in: optional_let_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_let_tracked), .init(0.0)) + @differentiable + func optional_let_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_let_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_let_nonresilient_tracked), .init(0.0)) + @differentiable func optional_let_nested(_ nestedMaybeX: Float??) -> Float { if let maybeX = nestedMaybeX { @@ -54,7 +69,26 @@ OptionalTests.test("Let") { expectEqual(gradient(at: nil, in: optional_let_nested), .init(.init(0.0))) @differentiable - func optional_let_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_let_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked< + Float + > { + if let maybeX = nestedMaybeX { + if let x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_let_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_let_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_let_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { if let maybeX = nestedMaybeX { if let x = maybeX { return x * x @@ -63,24 +97,38 @@ OptionalTests.test("Let") { } return 10 } - expectEqual(gradient(at: 10, in: optional_let_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_let_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_let_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_let_nested_nonresilient_tracked), + .init(.init(0.0))) @differentiable - func optional_let_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_let_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { if let x = maybeX { - return x + return x } return defaultValue } expectEqual(gradient(at: 10, 20, in: optional_let_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_let_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: nil, 20, in: optional_let_generic), (.init(0.0), 1.0)) - expectEqual(gradient(at: Tracked.init(10), Tracked.init(20), in: optional_let_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, Tracked.init(20), in: optional_let_generic), (.init(0.0), 1.0)) + expectEqual( + gradient( + at: Tracked.init(10), Tracked.init(20), + in: optional_let_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, Tracked.init(20), in: optional_let_generic), + (.init(0.0), 1.0)) @differentiable - func optional_let_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_let_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { if let maybeX = nestedMaybeX { if let x = maybeX { return x @@ -90,8 +138,12 @@ OptionalTests.test("Let") { return defaultValue } - expectEqual(gradient(at: 10.0, 20.0, in: optional_let_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_let_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10.0, 20.0, in: optional_let_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_let_nested_generic), + (.init(.init(0.0)), 1.0)) } OptionalTests.test("Switch") { @@ -115,14 +167,28 @@ OptionalTests.test("Switch") { expectEqual(gradient(at: 10, in: optional_switch_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_switch_tracked), .init(0.0)) + @differentiable + func optional_switch_nonresilient_tracked( + _ maybeX: NonresilientTracked? + ) -> NonresilientTracked { + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + expectEqual( + gradient(at: 10, in: optional_switch_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_switch_nonresilient_tracked), .init(0.0)) + @differentiable func optional_switch_nested(_ nestedMaybeX: Float??) -> Float { switch nestedMaybeX { case nil: return 10 case let .some(maybeX): switch maybeX { - case nil: return 10 - case let .some(x): return x * x + case nil: return 10 + case let .some(x): return x * x } } } @@ -130,50 +196,84 @@ OptionalTests.test("Switch") { expectEqual(gradient(at: nil, in: optional_switch_nested), .init(.init(0.0))) @differentiable - func optional_switch_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_switch_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { + switch nestedMaybeX { + case nil: return 10 + case let .some(maybeX): + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + } + expectEqual( + gradient(at: 10, in: optional_switch_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_switch_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_switch_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { switch nestedMaybeX { case nil: return 10 case let .some(maybeX): switch maybeX { - case nil: return 10 - case let .some(x): return x * x + case nil: return 10 + case let .some(x): return x * x } } } - expectEqual(gradient(at: 10, in: optional_switch_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_switch_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_switch_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_switch_nested_nonresilient_tracked), + .init(.init(0.0))) @differentiable - func optional_switch_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_switch_generic( + _ maybeX: T?, _ defaultValue: T + ) -> T { switch maybeX { case nil: return defaultValue case let .some(x): return x } } - expectEqual(gradient(at: 10, 20, in: optional_switch_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_switch_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_switch_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_switch_generic), (.init(0.0), 1.0)) @differentiable - func optional_switch_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_switch_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { switch nestedMaybeX { case nil: return defaultValue case let .some(maybeX): switch maybeX { - case nil: return defaultValue - case let .some(x): return x + case nil: return defaultValue + case let .some(x): return x } } } - expectEqual(gradient(at: 10, 20, in: optional_switch_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_switch_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_switch_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_switch_nested_generic), + (.init(.init(0.0)), 1.0)) } -OptionalTests.test("Var1") { +OptionalTests.test("Optional binding: if let") { @differentiable func optional_var1(_ maybeX: Float?) -> Float { var maybeX = maybeX if let x = maybeX { - return x * x + return x * x } return 10 } @@ -184,13 +284,28 @@ OptionalTests.test("Var1") { func optional_var1_tracked(_ maybeX: Tracked?) -> Tracked { var maybeX = maybeX if let x = maybeX { - return x * x + return x * x } return 10 } expectEqual(gradient(at: 10, in: optional_var1_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_var1_tracked), .init(0.0)) + @differentiable + func optional_var1_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + var maybeX = maybeX + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var1_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_var1_nonresilient_tracked), .init(0.0)) + @differentiable func optional_var1_nested(_ nestedMaybeX: Float??) -> Float { var nestedMaybeX = nestedMaybeX @@ -206,7 +321,27 @@ OptionalTests.test("Var1") { expectEqual(gradient(at: nil, in: optional_var1_nested), .init(.init(0.0))) @differentiable - func optional_var1_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_var1_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { + var nestedMaybeX = nestedMaybeX + if let maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var1_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var1_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_var1_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { var nestedMaybeX = nestedMaybeX if let maybeX = nestedMaybeX { if var x = maybeX { @@ -216,22 +351,32 @@ OptionalTests.test("Var1") { } return 10 } - expectEqual(gradient(at: 10, in: optional_var1_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_var1_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_var1_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var1_nested_nonresilient_tracked), + .init(.init(0.0))) @differentiable - func optional_var1_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_var1_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { var maybeX = maybeX if let x = maybeX { - return x + return x } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var1_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var1_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var1_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var1_generic), (.init(0.0), 1.0)) @differentiable - func optional_var1_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_var1_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { var nestedMaybeX = nestedMaybeX if let maybeX = nestedMaybeX { if var x = maybeX { @@ -241,11 +386,15 @@ OptionalTests.test("Var1") { } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var1_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var1_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var1_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var1_nested_generic), + (.init(.init(0.0)), 1.0)) } -OptionalTests.test("Var2") { +OptionalTests.test("Optional binding: if var") { @differentiable func optional_var2(_ maybeX: Float?) -> Float { if var x = maybeX { @@ -266,6 +415,20 @@ OptionalTests.test("Var2") { expectEqual(gradient(at: 10, in: optional_var2_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_var2_tracked), .init(0.0)) + @differentiable + func optional_var2_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + if var x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var2_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_var2_nonresilient_tracked), .init(0.0)) + @differentiable func optional_var2_nested(_ nestedMaybeX: Float??) -> Float { if var maybeX = nestedMaybeX { @@ -280,7 +443,26 @@ OptionalTests.test("Var2") { expectEqual(gradient(at: nil, in: optional_var2_nested), .init(.init(0.0))) @differentiable - func optional_var2_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_var2_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { + if var maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var2_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var2_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_var2_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { if var maybeX = nestedMaybeX { if var x = maybeX { return x * x @@ -289,21 +471,31 @@ OptionalTests.test("Var2") { } return 10 } - expectEqual(gradient(at: 10, in: optional_var2_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_var2_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_var2_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var2_nested_nonresilient_tracked), + .init(.init(0.0))) @differentiable - func optional_var2_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_var2_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { if var x = maybeX { return x } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var2_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var2_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var2_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var2_generic), (.init(0.0), 1.0)) @differentiable - func optional_var2_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_var2_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { if var maybeX = nestedMaybeX { if var x = maybeX { return x @@ -312,8 +504,12 @@ OptionalTests.test("Var2") { } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var2_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var2_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var2_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var2_nested_generic), + (.init(.init(0.0)), 1.0)) } runAllTests() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 858da28140d94..91d1d02d9e19a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -102,6 +102,7 @@ function(get_test_dependencies SDK result_var_name) ("${SDK}" STREQUAL "IOS_SIMULATOR") OR ("${SDK}" STREQUAL "TVOS_SIMULATOR") OR ("${SDK}" STREQUAL "WATCHOS_SIMULATOR") OR + ("${SDK}" STREQUAL "FREESTANDING") OR ("${SDK}" STREQUAL "LINUX") OR ("${SDK}" STREQUAL "CYGWIN") OR ("${SDK}" STREQUAL "FREEBSD") OR @@ -355,7 +356,7 @@ _Block_release(void) { }\n") endif() execute_process(COMMAND - $ "-c" "import psutil" + $ "-c" "import psutil" RESULT_VARIABLE python_psutil_status TIMEOUT 1 # second ERROR_QUIET) @@ -419,7 +420,7 @@ _Block_release(void) { }\n") ${command_upload_swift_reflection_test} ${command_clean_test_results_dir} COMMAND - $ "${LIT}" + $ "${LIT}" ${LIT_ARGS} "--param" "swift_test_subset=${test_subset}" "--param" "swift_test_mode=${test_mode}" @@ -438,7 +439,7 @@ _Block_release(void) { }\n") ${command_upload_swift_reflection_test} ${command_clean_test_results_dir} COMMAND - $ "${LIT}" + $ "${LIT}" ${LIT_ARGS} "--param" "swift_test_subset=${test_subset}" "--param" "swift_test_mode=${test_mode}" diff --git a/test/stdlib/CastTraps.swift.gyb b/test/Casting/CastTraps.swift.gyb similarity index 61% rename from test/stdlib/CastTraps.swift.gyb rename to test/Casting/CastTraps.swift.gyb index e5608874d028d..95c7cbbebfe31 100644 --- a/test/stdlib/CastTraps.swift.gyb +++ b/test/Casting/CastTraps.swift.gyb @@ -5,17 +5,17 @@ // FIXME: Casting.cpp has dozens of places to fail a cast. This test does not // attempt to enumerate them all. -// REQUIRES: objc_interop - import StdlibUnittest - +#if _runtime(_ObjC) import Foundation +#endif % types = [] % objectTypes = [] % protocolTypes = [] +% ObjCTypes = [] % types.append(['main.Class1', 'main.Class2']) % objectTypes.append(['main.Class1', 'main.Class2']) @@ -28,11 +28,15 @@ struct Struct2 { } % types.append(['main.ObjCClass1', 'main.ObjCClass2']) % objectTypes.append(['main.ObjCClass1', 'main.ObjCClass2']) +% ObjCTypes.extend(['main.ObjCClass1', 'main.ObjCClass2']) +#if _runtime(_ObjC) class ObjCClass1 : NSObject { } class ObjCClass2 : NSObject { } +#endif % types.append(['DateFormatter', 'NumberFormatter']) % objectTypes.append(['DateFormatter', 'NumberFormatter']) +% ObjCTypes.extend(['DateFormatter', 'NumberFormatter']) // non-Swift Objective-C class % protocolTypes.append('main.Proto1') @@ -40,6 +44,7 @@ class ObjCClass2 : NSObject { } protocol Proto1 { } protocol Proto2 { } % protocolTypes.append('URLSessionDelegate') +% ObjCTypes.append('URLSessionDelegate') // non-Swift Objective-C protocol @@ -51,6 +56,7 @@ var CastTrapsTestSuite = TestSuite("CastTraps") % for (t1, _) in types: % for (_, t2) in types: +% if t1 not in ObjCTypes and t2 not in ObjCTypes: CastTrapsTestSuite.test("${t1}__${t2}") .skip(.custom( { _isFastAssertConfiguration() }, @@ -67,6 +73,7 @@ CastTrapsTestSuite.test("${t1}__${t2}") _blackHole(r) } +% end % end % end @@ -76,6 +83,7 @@ CastTrapsTestSuite.test("${t1}__${t2}") % for (t1, _) in objectTypes: % for (t2) in protocolTypes: +% if t1 not in ObjCTypes and t2 not in ObjCTypes: CastTrapsTestSuite.test("${t1}__${t2}") .skip(.custom( { _isFastAssertConfiguration() }, @@ -92,7 +100,47 @@ CastTrapsTestSuite.test("${t1}__${t2}") _blackHole(r) } +% end % end % end +protocol P2 {} +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastTrapsTestSuite.test("Unexpected null") + .crashOutputMatches("Found unexpected null pointer value while trying to cast value of type '") + .crashOutputMatches("Foo'") + .crashOutputMatches(" to '") + .crashOutputMatches("P2'") + .code +{ + class Foo {} + let n = UnsafeRawPointer(bitPattern: 0) + var o: Foo = unsafeBitCast(n, to: Foo.self) + let r = o as Any + expectCrashLater() + let s = r as? P2 + _blackHole(s) +} +} + + +#if _runtime(_ObjC) +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastTrapsTestSuite.test("Unexpected Obj-C null") + .crashOutputMatches("Found unexpected null pointer value while trying to cast value of type '") + .crashOutputMatches("NSObject'") + .crashOutputMatches(" to '") + .crashOutputMatches("P2'") + .code +{ + let n = UnsafeRawPointer(bitPattern: 0) + var o: NSObject = unsafeBitCast(n, to: NSObject.self) + let r = o as Any + expectCrashLater() + let s = r as? P2 + _blackHole(s) +} +} +#endif + runAllTests() diff --git a/test/Casting/Casts.swift b/test/Casting/Casts.swift new file mode 100644 index 0000000000000..54eeef85adff6 --- /dev/null +++ b/test/Casting/Casts.swift @@ -0,0 +1,763 @@ +// Casts.swift - Tests for conversion between types. +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +// ----------------------------------------------------------------------------- +/// +/// Contains tests for non-trapping type conversions reported by users. +/// +// ----------------------------------------------------------------------------- +// RUN: %empty-directory(%t) +// +// RUN: %target-build-swift -swift-version 5 -g -Onone -Xfrontend -enable-experimental-concurrency -module-name a %s -o %t/a.swift5.Onone.out +// RUN: %target-codesign %t/a.swift5.Onone.out +// RUN: %target-run %t/a.swift5.Onone.out +// +// RUN: %target-build-swift -swift-version 5 -g -O -Xfrontend -enable-experimental-concurrency -module-name a %s -o %t/a.swift5.O.out +// RUN: %target-codesign %t/a.swift5.O.out +// RUN: %target-run %t/a.swift5.O.out +// +// REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib + +import StdlibUnittest +#if _runtime(_ObjC) +import Foundation +#endif + +func blackhole(_ t: T) { } + +private func runtimeCast(_ from: T, to: U.Type) -> U? { + return from as? U +} + +let CastsTests = TestSuite("Casts") + +// Test for SR-426: missing release for some types after failed conversion +CastsTests.test("No leak for failed tuple casts") { + let t: Any = (1, LifetimeTracked(0)) + expectFalse(t is Any.Type) +} + +protocol P {} +class ErrClass : Error { } + +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 _ in 0..<10 { + if case let a as P = t { + _ = a + } + } + } + + let err: Error = ErrClass() + bar(err) +} + +extension Int : P {} + +// Test for SR-7664: Inconsistent optional casting behaviour with generics +// Runtime failed to unwrap multiple levels of Optional when casting. +CastsTests.test("Multi-level optionals can be casted") { + func testSuccess(_ x: From, from: From.Type, to: To.Type) { + expectNotNil(x as? To) + } + func testFailure(_ x: From, from: From.Type, to: To.Type) { + expectNil(x as? To) + } + testSuccess(42, from: Int?.self, to: Int.self) + testSuccess(42, from: Int??.self, to: Int.self) + testSuccess(42, from: Int???.self, to: Int.self) + testSuccess(42, from: Int???.self, to: Int?.self) + testSuccess(42, from: Int???.self, to: Int??.self) + testSuccess(42, from: Int???.self, to: Int???.self) + testFailure(42, from: Int?.self, to: String.self) + testFailure(42, from: Int??.self, to: String.self) + testFailure(42, from: Int???.self, to: String.self) +} + +// Test for SR-9837: Optional.none not casting to Optional.none in generic context +CastsTests.test("Optional.none can be casted to Optional.none in generic context") { + func test(_ type: T.Type) -> T? { + return Any?.none as? T + } + + expectEqual(type(of: test(Bool.self)), Bool?.self) + expectEqual(type(of: test(Bool?.self)), Bool??.self) +} + +// Test for SR-3871: Cannot cast from ObjC existential without going through AnyObject +#if _runtime(_ObjC) +protocol P2 {} +CastsTests.test("Cast from ObjC existential to Protocol (SR-3871)") { + if #available(macOS 10.16, iOS 14.0, watchOS 7.0, tvOS 14.0, *) { + struct S: P2 {} + + class ObjCWrapper { + @objc dynamic let any: Any = S() + init() {} + } + let a = ObjCWrapper().any + expectTrue(a is P2) + // In SR-3871, the following cast failed (everything else here succeeded) + expectNotNil(a as? P2) + expectNotNil(a as? S) + let b = a as AnyObject + expectTrue(a is P2) + expectNotNil(b as? P2) + expectNotNil(b as? S) + } +} +#endif + +protocol P3 {} +CastsTests.test("Cast from Swift existential to Protocol") { + struct S: P3 {} + class SwiftWrapper { + let any: Any = S() + init() {} + } + let a = SwiftWrapper().any + expectTrue(a is P3) + expectNotNil(a as? P3) + expectNotNil(a as? S) + let b = a as AnyObject + expectTrue(b is P3) + expectNotNil(b as? P3) + expectNotNil(b as? S) +} + + +#if _runtime(_ObjC) +extension CFBitVector : P { + static func makeImmutable(from values: Array) -> CFBitVector { + return CFBitVectorCreate(/*allocator:*/ nil, values, values.count * 8) + } +} + +extension CFMutableBitVector { + static func makeMutable(from values: Array) -> CFMutableBitVector { + return CFBitVectorCreateMutableCopy( + /*allocator:*/ nil, + /*capacity:*/ 0, + CFBitVector.makeImmutable(from: values)) + } +} + +func isP(_ t: T) -> Bool { + return t is P +} + +CastsTests.test("Dynamic casts of CF types to protocol existentials (SR-2289)") +.skip(.custom({ + !_isDebugAssertConfiguration() + }, + reason: "This test behaves unpredictably in optimized mode.")) +.code { + expectTrue(isP(10 as Int)) + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectTrue(isP(CFBitVector.makeImmutable(from: [10, 20]))) + expectTrue(isP(CFMutableBitVector.makeMutable(from: [10, 20]))) + } +} +#endif + +// Another test for SR-3871, SR-5590, SR-6309, SR-8651: +// user type in a _SwiftValue in an Optional can't be cast to a protocol. +// Note: This uses the (misnamed) _bridgeAnythingToObjectiveC so it can +// test these paths on Linux as well. +protocol P6309 {} +CastsTests.test("Casting struct -> Obj-C -> Protocol fails (SR-3871, SR-5590, SR-6309, SR-8651)") { + struct S: P6309 { + let value: Int + let tracker = LifetimeTracked(13) + } + + let a: P6309 = S(value: 13) + + let b = _bridgeAnythingToObjectiveC(a) + let d = b as? Any + let e = d as? P6309 + expectNotNil(e) +} + + +protocol P4552 {} +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Casting Any(Optional(T)) -> Protocol fails (SR-4552)") { + struct S: P4552 { + let tracker = LifetimeTracked(13) + } + + let a = S() + let b: S? = a + let c = b as? Any + let d = c as? P4552 + expectNotNil(d) +} +} + +// rdar://27108240 (Optional casting bug (crash)) +protocol Key { + associatedtype Value +} +CastsTests.test("Cast to associated type") { + // Helper function to bypass compiler cast optimizations + func runtimeCast (_ x: From, to: To.Type) -> To? { + return x as? To + } + struct StringKey : Key { + typealias Value = String? + } + var string: String? + func value(forKey key: K.Type) { + let b = runtimeCast(string, to: K.Value.self) + expectNotNil(b) + let c = string as? K.Value + expectNotNil(c) + } + value(forKey: StringKey.self) +} + +#if _runtime(_ObjC) +// rdar://36288786 (Swift metatype stored in an Objective-C id property can't be typecast back to its original type) +CastsTests.test("Store Swift metatype in ObjC property and cast back to Any.Type") { + class MyObj { + var sVar: Any? = nil + @objc dynamic var objcVar: Any? = nil + } + + let a = MyObj() + + // Double values + a.sVar = 1.234 + a.objcVar = 1.234 + + let sValue1 = a.sVar as? Double + let objcValue1 = a.objcVar as? Double + expectEqual(sValue1, objcValue1) + + // Swift types + let b = Bool.self + a.sVar = b + a.objcVar = b + + let sValue2 = a.sVar as? Any.Type + let objcValue2 = a.objcVar as? Any.Type + expectTrue(sValue2 == b) + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectTrue(sValue2 == objcValue2) + expectTrue(objcValue2 == b) + } +} +#endif + +// rdar://37793004 ([dynamic casting] [SR-7049]: Enums don't cast back from AnyHashable) +CastsTests.test("Enums don't cast back from AnyHashable (SR-7049)") { + enum E { + case a + } + + // This works as expected. + let str: AnyHashable = "hello" + expectNotNil(str as? String) // Optional("hello") + expectNotNil(str as? String as Any) // Optional("hello") + + // This doesn't. + let ea: AnyHashable = E.a + expectNotNil(ea as? E) + expectNotNil(ea as? E as Any) + expectEqual((ea as? E), E.a) +} + +#if _runtime(_ObjC) +//rdar://39415812 ([dynamic casting] [SR-7432]: Can't see through boxed _SwiftValue when casting from @objc Type) +@objc(Exporter) +protocol Exporter: NSObjectProtocol { + var type: Any { get } + func export(item: Any) -> String? +} +CastsTests.test("Casts from @objc Type") { + struct User { var name: String } + + final class UserExporter: NSObject, Exporter { + var type: Any { return User.self } + func export(item: Any) -> String? { + let u = item as? User + return u?.name + } + } + + let user = User(name: "Kermit") + let exporter: Exporter = UserExporter() + + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectTrue(exporter.type is User.Type) + } + expectNotNil(exporter.export(item: user)) +} +#endif + +#if _runtime(_ObjC) +// rdar://44467533 (Swift master branch: conditional casts for _ObjectiveCBridgeable miscompile in swift-corelibs-foundation) +CastsTests.test("Conditional NSNumber -> Bool casts") { + let x = NSNumber(value: -1) as? Bool + expectNil(x) +} +#endif + +// rdar://45217461 ([dynamic casting] [SR-8964]: Type check operator (is) fails for Any! variable holding an Error (struct) value) +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Casts from Any(struct) to Error (SR-8964)") { + struct MyError: Error { } + + let a: Any! = MyError() + let b: Any = a + expectTrue(b is Error) +} +} + +#if _runtime(_ObjC) +// rdar://15494623 (Handle dynamic cast to archetype bound to ObjC existential) +CastsTests.test("Dynamic cast to ObjC protocol") { + func genericCast(x: NSObject, _: T.Type) -> T? { + return x as? T + } + + let n: NSNumber = 1 + let copying = genericCast(x: n, NSCopying.self) + expectNotNil(copying) +} +#endif + +// SR-6126 +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Nil handling for Optionals and Arrays (SR-6126)") { + func check(_ arg: Int??) -> String { + switch arg { + case .none: + return ".none" + case .some(.none): + return ".some(.none)" + case .some(.some): + return ".some(.some)" + } + } + + let x: Int? = .none + let y: [Int?] = [.none] + + let a = x as Int?? + let b = (x as? Int??)! + let b2 = runtimeCast(x, to: Int??.self)! + let c = Int?.none as Int?? + let d = (Int?.none as? Int??)! + let d2 = runtimeCast(Int?.none, to: Int??.self)! + let e = (y as [Int??]).first! + let f = (y as? [Int??])!.first! + let f2 = runtimeCast(y, to: [Int??].self)!.first! + let g = ([Int?.none] as [Int??]).first! + let h = ([Int?.none] as? [Int??])!.first! + let h2 = runtimeCast([Int?.none], to: [Int??].self)!.first! + + // Original reporter believes all of these should be .some(.none) + expectEqual(".some(.none)", check(a)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(b)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(b2)) + expectEqual(".some(.none)", check(c)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(d)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(d2)) + expectEqual(".some(.none)", check(e)) // Xcode 9.0: .none + expectEqual(".some(.none)", check(f)) // Xcode 9.0: .none + expectEqual(".some(.none)", check(f2)) + expectEqual(".some(.none)", check(g)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(h)) // Xcode 9.0: .none + expectEqual(".some(.none)", check(h2)) +} +} + +protocol SwiftProtocol {} +CastsTests.test("Swift Protocol Metatypes don't self-conform") { + let a = SwiftProtocol.self + // `is P.Protocol` tests whether the argument is a subtype of P. + // In particular, the protocol identifier `P.self` is such a subtype. + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectNotNil(runtimeCast(a, to: SwiftProtocol.Protocol.self)) // Fixed by rdar://58991956 + } + expectNotNil(a as? SwiftProtocol.Protocol) + expectTrue(a is SwiftProtocol.Protocol) + blackhole(a as! SwiftProtocol.Protocol) // Should not trap + + // `is P.Type` tests conformance to P. Protocols cannot conform to + // protocols, so these always fail. + expectNil(runtimeCast(a, to: SwiftProtocol.Type.self)) + expectNil(a as? SwiftProtocol.Type) + expectFalse(a is SwiftProtocol.Type) +} + +CastsTests.test("Self-conformance for Any.self") { + let b = Any.self + expectNotNil(runtimeCast(b, to: Any.Protocol.self)) + blackhole(b as! Any.Protocol) // Should not trap + expectTrue(b is Any.Protocol) + expectNotNil(b as? Any.Protocol) + + // Unlike most other protocols, Any.self does conform to Any + expectNotNil(runtimeCast(b, to: Any.Type.self)) + expectNotNil(b as? Any.Type) + expectTrue(b is Any.Type) + blackhole(b as! Any.Type) +} + +// rdar://59067748 (Error Protocol should self-conform in optimized casts) +CastsTests.test("Self-conformance for Error.self") +.skip(.custom({ + !_isDebugAssertConfiguration() + }, + reason: "Cast optimizer breaks this test")) +.code { + let c = Error.self + expectNotNil(runtimeCast(c, to: Error.Protocol.self)) + expectNotNil(c as? Error.Protocol) + expectTrue(c is Error.Protocol) + blackhole(c as! Error.Protocol) + + // Unlike most other protocols, Error.self does conform to Error + expectNotNil(runtimeCast(c, to: Error.Type.self)) + expectFailure { expectNotNil(c as? Error.Type) } + expectFailure { expectTrue(c is Error.Type) } + // blackhole(c as! Error.Type) // Should not trap, but currently does +} + +// rdar://59067556 (Obj-C Protocol Metatypes should self-conform) +#if _runtime(_ObjC) +@objc protocol ObjCProtocol {} +CastsTests.test("ObjC Protocol Metatypes self-conform") { + let a = ObjCProtocol.self + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectNotNil(runtimeCast(a, to: ObjCProtocol.Protocol.self)) + } + expectNotNil(a as? ObjCProtocol.Protocol) + expectTrue(a is ObjCProtocol.Protocol) + blackhole(a as! ObjCProtocol.Protocol) + + // Unlike Swift protocols, ObjC protocols do conform to themselves + expectFailure { expectNotNil(runtimeCast(a, to: ObjCProtocol.Type.self)) } + expectFailure { expectNotNil(a as? ObjCProtocol.Type) } + expectFailure { expectTrue(a is ObjCProtocol.Type) } + // blackhole(a as! ObjCProtocol.Type) // Should not trap, but currently does +} +#endif + +#if _runtime(_ObjC) +protocol NewStringProtocol {} +extension String: NewStringProtocol { } +CastsTests.test("String/NSString extension compat") { + let x: Any = NSString() + expectFailure { expectNotNil(runtimeCast(x, to: NewStringProtocol.self)) } + expectFailure { expectNotNil(x as? NewStringProtocol) } +} +#endif + +protocol P1999 {} +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Cast Any(Optional(class)) to Protocol type (SR-1999)") { + class Foo: P1999 { } + + let optionalFoo : Foo? = Foo() + let anyValue: Any = optionalFoo + + let foo1 = anyValue as? Foo + expectNotNil(foo1) + + let foo2 = anyValue as? P1999 + expectNotNil(foo2) + + let foo3 = runtimeCast(anyValue, to: Foo.self) + expectNotNil(foo3) + + let foo4 = runtimeCast(anyValue, to: P1999.self) + expectNotNil(foo4) +} +} + +#if _runtime(_ObjC) +CastsTests.test("Dict value casting (SR-2911)") { + var dict: [AnyHashable: String] = [:] + dict["Key"] = "Value" + expectNotNil(dict["Key"] as? NSString) + expectNotNil(runtimeCast(dict["Key"], to: NSString.self)) +} +#endif + +#if _runtime(_ObjC) +CastsTests.test("String coercions should work on Linux (SR-12020)") { + let a = "abc" as Substring as NSString + let b = "abc" as NSString + expectEqual(a, b) + + let c = "abc" as Substring + let d = c as? NSString + let e = "abc" as? NSString + expectEqual(d, e) + + let f = runtimeCast(d, to: NSString.self) + expectEqual(e, f) +} +#endif + +class ClassInt: Equatable, Hashable { + private var tracker = LifetimeTracked(77) + static func == (lhs: ClassInt, rhs: ClassInt) -> Bool {return true} + func hash(into hasher: inout Hasher) {} +} +CastsTests.test("AnyHashable(Class) -> Obj-C -> Class") +.skip(.custom({ + !_isDebugAssertConfiguration() + }, + reason: "Cast optimizer breaks this test")) +.code { + let a = ClassInt() + let b = runtimeCast(a, to: AnyHashable.self)! + let c = _bridgeAnythingToObjectiveC(b) + let d = /* SwiftValueBox(AnyHashable(ClassInt)) */ c as? ClassInt + expectNotNil(d) + let d2 = runtimeCast(c, to: ClassInt.self) + expectNotNil(d2) + let e = runtimeCast(/* SwiftValueBox(AnyHashable(ClassInt)) */ c, to: ClassInt.self) + expectNotNil(e) +} + +#if _runtime(_ObjC) +// rdar://58999120 +CastsTests.test("Error -> NSError -> Protocol transitivity (SR-12095)") { + enum NonConformingError: Error { + case ok + } + + let nonConformingError: Error = NonConformingError.ok + + // NSError conforms to CustomStringConvertible, so ... + let conformingError = nonConformingError as? NSError + expectTrue(conformingError is CustomStringConvertible) + expectNotNil(conformingError as? CustomStringConvertible) + + // Our error type does not conform directly, but should conform + // indirectly because of NSError... + // Note: Known broken in both runtime and compiler. + expectFailure { expectTrue(nonConformingError is CustomStringConvertible) } + expectFailure { expectNotNil(nonConformingError as? CustomStringConvertible) } +} +#endif + +#if _runtime(_ObjC) +CastsTests.test("Runtime crash casting Obj-C object to Obj-C protocol (rdar://16449805)") { + // FIXME: The reported crash was for `NSPoint(x:0, y:0) as? NSCoding`, + // but NSPoint seems to not be available on 32-bit platforms. + expectNotNil(NSString() as? NSCoding) +} +#endif + +CastsTests.test("Casting Swift Error-conforming types to Error existentials") { + enum Foo: Error { + case OK + case Broken + } + let a = Foo.Broken + let b = a as? Error + expectNotNil(b) + let c = b as? Foo + expectNotNil(c) + let d = Foo.self as? Error.Type + expectNotNil(d) +} + +#if _runtime(_ObjC) +CastsTests.test("Casting NSError <-> Error") { + @objc class Bar: NSError { + init() {super.init(domain: "Bar", code: 99)} + required init?(coder: NSCoder) {super.init(coder: coder)} + } + let e = Bar.self as? Error.Type + expectNotNil(e) + let f = Bar.self as? Bar.Type + expectNotNil(f) + let g = Bar() as? Error + expectNotNil(g) +} +#endif + +// Foundation's JSON handling makes heavy use of passing Any? inside of Any +// existentials. That inspired the following three checks: +CastsTests.test("[Any(Any?)] -> [Any?] should prefer unwrapping source") { + let a: Any? = nil + let b: [Any] = [a as Any] + let c = b as? [Any?] + let d = c! + let e = d[0] + expectNil(e) +} + +CastsTests.test("Any(Any?) -> Any? should prefer unwrapping source") { + let a: Any? = nil + let b: Any = a + let c = b as? Any? + let d = c! + expectNil(d) +} + +#if _runtime(_ObjC) +CastsTests.test("NSNull?.none -> Any? should set outer nil") { + let a: NSNull? = nil + let b = a as? Any? + let c = b! + expectNil(c) +} +#endif + +CastsTests.test("Int??.some(nil) => Int??? should inject naturally") { + let a: Int?? = .some(nil) + let b = a as? Int??? + let c = b! + let d = c! + let e = d! + expectNil(e) +} + +CastsTests.test("Int??.some(nil) => String??? should inject naturally") { + let a: Int?? = .some(nil) + let b = runtimeCast(a, to: String???.self) + let c = b! + let d = c! + let e = d! + expectNil(e) +} + +CastsTests.test("Int??.some(nil) => Any??? should inject naturally") { + let a: Int?? = .some(nil) + let b = a as? Any??? + let c = b! + let d = c! + let e = d! + expectNil(e) +} + +#if _runtime(_ObjC) +CastsTests.test("NSString -> String fast path") { + let a = "short" as NSString + expectNotNil(a as? String) + let b = runtimeCast(a, to: String.self) + expectNotNil(b) + + let c = "Long (adj) -- extended, large, the opposite of short" as NSString + expectNotNil(c as? String) + let d = runtimeCast(c, to: String.self) + expectNotNil(d) + + let e = NSMutableString("not read-only") + expectNotNil(e as? String) + let f = runtimeCast(e, to: String.self) + expectNotNil(f) + + let g = CFStringCreateWithCString(nil, "hello, world", CFStringBuiltInEncodings.UTF8.rawValue) + expectNotNil(g as? String) + let h = runtimeCast(g, to: String.self) + expectNotNil(h) + + let i = CFStringCreateMutable(nil, 0) + expectNotNil(i as? String) + let j = runtimeCast(i, to: String.self) + expectNotNil(j) +} +#endif + +// This fails in optimized builds because after inlining `runtimeCast`, +// the resulting SIL cast operation is left in a form that IRGen can't +// correctly handle. +//CastsTests.test("Optimized metatype -> AnyObject cast") { +// struct StructInt { } +// let a = StructInt.self +// let b = runtimeCast(a, to: AnyObject.self) +// expectNotNil(b) +//} + +CastsTests.test("Any.Protocol") { + class C {} + struct S {} + func isAnyProtocol(_ type: T.Type) -> Bool { + let result = T.self is Any.Protocol + if result { + // `as!` should succeed if `is` does + blackhole(T.self as! Any.Protocol) + } + return result + } + func isAnyType(_ type: T.Type) -> Bool { + return T.self is Any.Type + } + func isType(_ type: T.Type, to: U.Type) -> Bool { + return T.self is U.Type + } + + expectTrue(Int.self is Any.Type) + expectNotNil(Int.self as? Any.Type) + expectTrue(isAnyType(Int.self)) + expectFalse(Int.self is Any.Protocol) + expectNil(Int.self as? Any.Protocol) + expectFalse(isAnyProtocol(Int.self)) + expectFalse(isType(Int.self, to: Any.self)) + + expectTrue(C.self is Any.Type) + expectNotNil(C.self as? Any.Type) + expectTrue(isAnyType(C.self)) + expectFalse(C.self is Any.Protocol) + expectNil(C.self as? Any.Protocol) + expectFalse(isAnyProtocol(C.self)) + expectFalse(isType(C.self, to: Any.self)) + + expectTrue(S.self is Any.Type) + expectNotNil(S.self as? Any.Type) + expectTrue(isAnyType(S.self)) + expectFalse(S.self is Any.Protocol) + expectNil(S.self as? Any.Protocol) + expectFalse(isAnyProtocol(S.self)) + expectFalse(isType(S.self, to: Any.self)) + + expectTrue(Any.self is Any.Type) + expectNotNil(Any.self as? Any.Type) + expectTrue(isAnyType(Any.self)) + expectTrue(Any.self is Any.Protocol) + expectNotNil(Any.self as? Any.Protocol) + expectTrue(isAnyProtocol(Any.self)) + expectTrue(isType(Any.self, to: Any.self)) + + expectTrue(Any?.self is Any.Type) + expectNotNil(Any?.self as? Any.Type) + expectTrue(isAnyType(Any?.self)) + expectFalse(Any?.self is Any.Protocol) + expectNil(Any?.self as? Any.Protocol) + expectFalse(isAnyProtocol(Any?.self)) + expectFalse(isType(Any?.self, to: Any.self)) +} + +CastsTests.test("Async function types") { + let asyncFnType: Any.Type = (() async -> Void).self + let fnType: Any.Type = (() -> Void).self + + expectTrue(fnType is (() -> Void).Type) + expectTrue(asyncFnType is (() async -> Void).Type) + expectFalse(fnType is (() async -> Void).Type) + expectFalse(asyncFnType is (() -> Void).Type) +} + +runAllTests() diff --git a/test/ClangImporter/objc_async.swift b/test/ClangImporter/objc_async.swift new file mode 100644 index 0000000000000..1a30f41c97a44 --- /dev/null +++ b/test/ClangImporter/objc_async.swift @@ -0,0 +1,22 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -I %S/Inputs/custom-modules -enable-experimental-concurrency %s -verify + +// REQUIRES: objc_interop +import Foundation +import ObjCConcurrency + +func testSlowServer(slowServer: SlowServer) async throws { + let _: Int = await slowServer.doSomethingSlow("mail") + let _: Bool = await slowServer.checkAvailability() + let _: String = try await slowServer.findAnswer() ?? "nope" + let _: String = await try slowServer.findAnswerFailingly() ?? "nope" + let _: Void = await slowServer.doSomethingFun("jump") + let _: (Int) -> Void = slowServer.completionHandler +} + +func testSlowServerOldSchool(slowServer: SlowServer) { + var i1: Int = 0 + slowServer.doSomethingSlow("mail") { i in + i1 = i + } + print(i1) +} diff --git a/test/Constraints/argument_matching.swift b/test/Constraints/argument_matching.swift index c29b9c9649997..c321aa3e739a2 100644 --- a/test/Constraints/argument_matching.swift +++ b/test/Constraints/argument_matching.swift @@ -305,6 +305,93 @@ variadics6(x: 1, 2, 3) // expected-error{{missing argument for parameter 'z' in variadics6(x: 1) // expected-error{{missing argument for parameter 'z' in call}} variadics6() // expected-error{{missing argument for parameter 'z' in call}} +func variadics7(_ x: Int..., y: Int...) { } + +// Using multiple variadics (in order, complete) +variadics7(1, y: 2) +variadics7(1, 2, 3, y: 4, 5, 6) +variadics7(1, 2, y: 2) +variadics7(1, y: 2, 1) + +// multiple variadics, in order, some missing +variadics7(y: 1) +variadics7(1) +variadics7(y: 4, 5, 6) +variadics7(1, 2, 3) + +func variadics8(x: Int..., y: Int...) { } + +// multiple variadics, out of order +variadics8(y: 1, x: 2) // expected-error {{argument 'x' must precede argument 'y'}} {{12-12=x: 2, }} {{16-22=}} +variadics8(y: 1, 2, 3, x: 4) // expected-error {{argument 'x' must precede argument 'y'}} {{12-12=x: 4, }} {{22-28=}} +variadics8(y: 1, x: 2, 3, 4) // expected-error {{argument 'x' must precede argument 'y'}} {{12-12=x: 2, 3, 4, }} {{16-28=}} +variadics8(y: 1, 2, 3, x: 4, 5, 6) // expected-error {{argument 'x' must precede argument 'y'}} {{12-12=x: 4, 5, 6, }} {{22-34=}} + +func variadics9(_ a: Int..., b: Int, _ c: Int...) { } // expected-note {{'variadics9(_:b:_:)' declared here}} + +// multiple split variadics, in order, complete +variadics9(1, b: 2, 3) +variadics9(1, 2, 3, b: 2, 3) +variadics9(1, b: 2, 3, 2, 1) +variadics9(1, 2, 3, b: 2, 3, 2, 1) + +// multiple split variadics, in order, some missing +variadics9(b: 2, 3) +variadics9(1, b: 2) +variadics9(1, 2, b: 2) +variadics9(b: 2, 3, 2, 1) + +// multiple split variadics, required missing +variadics9(1) // expected-error {{missing argument for parameter 'b' in call}} + +func variadics10(_ a: Int..., b: Int = 2, _ c: Int...) { } + +// multiple unlabeled variadics split by defaulted param, in order, complete +variadics10(1, b: 2, 3) +variadics10(1, 2, 3, b: 2, 3) +variadics10(1, b: 2, 3, 2, 1) +variadics10(1, 2, 3, b: 2, 3, 2, 1) + +// multiple unlabeled variadics split by defaulted param, in order, some missing +variadics10(1, 2, 3) +variadics10(1, 2, 3, b: 3) +variadics10(b: 3) + +func variadics11(_ a: Int..., b: Bool = false, _ c: String...) { } + +variadics11(1, 2, 3, b: true, "hello", "world") +variadics11(b: true, "hello", "world") +variadics11(1, 2, 3, b: true) +variadics11(b: true) +variadics11() +variadics11(1, 2, 3, "hello", "world") // expected-error 2 {{cannot convert value of type 'String' to expected argument type 'Int'}} + +func variadics12(a: Int..., b: Int, c: Int...) { } + +variadics12(a: 1, 2, 3, b: 4, c: 5, 6, 7) +variadics12(b: 4, c: 5, 6, 7) +variadics12(a: 1, 2, 3, b: 4) + +variadics12(c: 5, 6, 7, b: 4, a: 1, 2, 3) // expected-error {{incorrect argument labels in call (have 'c:_:_:b:a:_:_:', expected 'a:b:c:')}} {{13-14=a}} {{19-19=b: }} {{22-22=c: }} {{25-28=}} {{31-34=}} + + +// Edge cases involving multiple trailing closures and forward matching. +func variadics13(a: Int..., b: (()->Void)...) {} + +variadics13() +variadics13(a: 1, 2, 3) {} _: {} _: {} +variadics13() {} _: {} _: {} +variadics13(a: 1, 2, 3) +variadics13(a: 1, 2, 3) {} + +func variadics14(a: (()->Void)..., b: (()->Void)...) {} // expected-note {{'variadics14(a:b:)' declared here}} + +variadics14(a: {}, {}, b: {}, {}) +variadics14(a: {}, {}) {} _: {} +variadics14 {} _: {} b: {} _: {} +variadics14 {} b: {} +variadics14 {} // expected-warning {{backward matching of the unlabeled trailing closure is deprecated; label the argument with 'b' to suppress this warning}} + func outOfOrder(_ a : Int, b: Int) { outOfOrder(b: 42, 52) // expected-error {{unnamed argument #2 must precede argument 'b'}} {{14-14=52, }} {{19-23=}} } @@ -1336,6 +1423,26 @@ d = sub2[d] // expected-error{{missing argument label 'd:' in subscript}} {{10-1 d = sub2[d: d] d = sub2[f: d] // expected-error{{incorrect argument label in subscript (have 'f:', expected 'd:')}} {{10-11=d}} +struct Sub3 { + subscript (a: Int..., b b: Int...) -> Int { 42 } +} + +let sub3 = Sub3() +_ = sub3[1, 2, 3, b: 4, 5, 6] +_ = sub3[b: 4, 5, 6] +_ = sub3[1, 2, 3] +_ = sub3[1, c: 4] // expected-error {{incorrect argument label in subscript (have '_:c:', expected '_:b:')}} + +struct Sub4 { + subscript (a: Int..., b b: Int = 0, c: Int...) -> Int { 42 } +} + +let sub4 = Sub4() +_ = sub4[1, 2, 3, b: 2, 1, 2, 3] +_ = sub4[1, 2, 3, b: 2] +_ = sub4[1, 2, 3] +_ = sub4[] + // ------------------------------------------- // Closures // ------------------------------------------- diff --git a/test/Constraints/casts.swift b/test/Constraints/casts.swift index 0ea574583a5b8..c63dc7354d225 100644 --- a/test/Constraints/casts.swift +++ b/test/Constraints/casts.swift @@ -252,11 +252,11 @@ func test_coercions_with_overloaded_operator(str: String, optStr: String?, veryO _ = (str ?? "") as Int // expected-error {{cannot convert value of type 'String' to type 'Int' in coercion}} _ = (optStr ?? "") as Int // expected-error {{cannot convert value of type 'String' to type 'Int' in coercion}} - _ = (optStr ?? "") as Int? // expected-error {{cannot convert value of type 'String' to type 'Int?' in coercion}} + _ = (optStr ?? "") as Int? // expected-error {{'String' is not convertible to 'Int?'; did you mean to use 'as!' to force downcast?}} _ = (str ^^^ "") as Int // expected-error {{cannot convert value of type 'String' to type 'Int' in coercion}} _ = (optStr ^^^ "") as Int // expected-error {{cannot convert value of type 'String' to type 'Int' in coercion}} - _ = (optStr ^^^ "") as Int? // expected-error {{cannot convert value of type 'String' to type 'Int?' in coercion}} + _ = (optStr ^^^ "") as Int? // expected-error {{'String' is not convertible to 'Int?'; did you mean to use 'as!' to force downcast?}} _ = ([] ?? []) as String // expected-error {{cannot convert value of type '[Any]' to type 'String' in coercion}} _ = ([""] ?? []) as [Int: Int] // expected-error {{cannot convert value of type '[String]' to type '[Int : Int]' in coercion}} @@ -290,7 +290,7 @@ func test_compatibility_coercions(_ arr: [Int], _ optArr: [Int]?, _ dict: [Strin // expected-note@-1 {{arguments to generic parameter 'Element' ('Int' and 'String') are expected to be equal}} _ = dict as [String: String] // expected-error {{cannot convert value of type '[String : Int]' to type '[String : String]' in coercion}} // expected-note@-1 {{arguments to generic parameter 'Value' ('Int' and 'String') are expected to be equal}} - _ = dict as [String: String]? // expected-error {{cannot convert value of type '[String : Int]' to type '[String : String]?' in coercion}} + _ = dict as [String: String]? // expected-error {{'[String : Int]' is not convertible to '[String : String]?'; did you mean to use 'as!' to force downcast?}} _ = (dict as [String: Int]?) as [String: Int] // expected-error {{value of optional type '[String : Int]?' must be unwrapped to a value of type '[String : Int]'}} // expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} // expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index b6f99b7350729..0b77ce6ac87b2 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -1030,3 +1030,15 @@ func sr12815() { .doesntExist2() { $0 } } } + +// Make sure we can infer generic arguments in an explicit result type. +let explicitUnboundResult1 = { () -> Array in [0] } +let explicitUnboundResult2: (Array) -> Array = { + (arr: Array) -> Array in [0] +} +// FIXME: Should we prioritize the contextual result type and infer Array +// rather than using a type variable in these cases? +// expected-error@+1 {{unable to infer closure type in the current context}} +let explicitUnboundResult3: (Array) -> Array = { + (arr: Array) -> Array in [true] +} diff --git a/test/Constraints/conditionally_defined_types.swift b/test/Constraints/conditionally_defined_types.swift index 193d40a7f766d..73ebce7633514 100644 --- a/test/Constraints/conditionally_defined_types.swift +++ b/test/Constraints/conditionally_defined_types.swift @@ -36,12 +36,12 @@ let _ = SameType.Decl3.self let _ = SameType.Decl4.self let _ = SameType.Decl5.self -let _ = SameType.TypeAlias1.self // expected-error {{'SameType.TypeAlias1' (aka 'X') requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.TypeAlias2.self // expected-error {{'SameType.TypeAlias2' (aka 'Y') requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.TypeAlias1.self // expected-error {{'SameType.TypeAlias1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.TypeAlias2.self // expected-error {{'SameType.TypeAlias2' (aka 'Y') requires the types 'Y' and 'X' be equivalent}} let _ = SameType.TypeAlias3.self // expected-error {{'SameType.TypeAlias3' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl2.self // expected-error {{'SameType.Decl2' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl3.self // expected-error {{'SameType.Decl3' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl2.self // expected-error {{'SameType.Decl2' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl3.self // expected-error {{'SameType.Decl3' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.self // expected-error {{'SameType.Decl4' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl5.self // expected-error {{'SameType.Decl5' requires the types 'Y' and 'X' be equivalent}} @@ -49,7 +49,7 @@ extension SameType: AssociatedType where T == X {} // expected-note@-1 {{requirement specified as 'T' == 'X' [with T = Y]}} let _ = SameType.T.self -let _ = SameType.T.self // expected-error {{'SameType.T' (aka 'X') requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.T.self // expected-error {{'SameType.T' (aka 'X') requires the types 'Y' and 'X' be equivalent}} struct Conforms {} @@ -112,14 +112,14 @@ let _ = SameType.Decl1.Decl3.self let _ = SameType.Decl1.Decl4.self let _ = SameType.Decl1.Decl5.self -let _ = SameType.Decl1.TypeAlias1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.TypeAlias2.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.TypeAlias3.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl2.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl3.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl4.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl5.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.TypeAlias1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.TypeAlias2.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.TypeAlias3.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl2.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl3.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl4.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl5.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} extension SameType.Decl4 where U == X { // expected-note 5 {{requirement specified as 'U' == 'X' [with U = Y]}} typealias TypeAlias1 = T @@ -144,12 +144,12 @@ let _ = SameType.Decl4.Decl3.self let _ = SameType.Decl4.Decl4.self let _ = SameType.Decl4.Decl5.self -let _ = SameType.Decl4.TypeAlias1.self // expected-error {{'SameType.Decl4.TypeAlias1' (aka 'X') requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.TypeAlias2.self // expected-error {{'SameType.Decl4.TypeAlias2' (aka 'Y') requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.TypeAlias1.self // expected-error {{'SameType.Decl4.TypeAlias1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.TypeAlias2.self // expected-error {{'SameType.Decl4.TypeAlias2' (aka 'Y') requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.TypeAlias3.self // expected-error {{'SameType.Decl4.TypeAlias3' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.Decl1.self // expected-error {{'SameType.Decl4.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.Decl2.self // expected-error {{'SameType.Decl4.Decl2' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.Decl3.self // expected-error {{'SameType.Decl4.Decl3' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.Decl1.self // expected-error {{'SameType.Decl4.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.Decl2.self // expected-error {{'SameType.Decl4.Decl2' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.Decl3.self // expected-error {{'SameType.Decl4.Decl3' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.Decl4.self // expected-error {{'SameType.Decl4.Decl4' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.Decl5.self // expected-error {{'SameType.Decl4.Decl5' requires the types 'Y' and 'X' be equivalent}} diff --git a/test/Constraints/construction.swift b/test/Constraints/construction.swift index 82f660ed6a7bb..048667c4e129b 100644 --- a/test/Constraints/construction.swift +++ b/test/Constraints/construction.swift @@ -22,7 +22,7 @@ enum Z { init(_ x: Int, _ y: Int) { self = .point(x, y) } } -enum Optional { // expected-note {{'T' declared as parameter to type 'Optional'}} +enum Optional { case none case value(T) @@ -59,8 +59,7 @@ acceptString("\(hello), \(world) #\(i)!") Optional(1) // expected-warning{{unused}} Optional(1) // expected-warning{{unused}} _ = .none as Optional -Optional(.none) // expected-error{{generic parameter 'T' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{9-9=}} -// expected-error@-1 {{cannot infer contextual base in reference to member 'none'}} +Optional(.none) // expected-error {{cannot infer contextual base in reference to member 'none'}} // Interpolation _ = "\(hello), \(world) #\(i)!" diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index bff33fe7caa73..fac6d8b343a10 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -423,7 +423,7 @@ let _ : Color = .rainbow(42) // expected-error {{argument passed to call that t let _ : (Int, Float) = (42.0, 12) // expected-error {{cannot convert value of type '(Double, Float)' to specified type '(Int, Float)'}} -let _ : Color = .rainbow // expected-error {{member 'rainbow()' is a function; did you mean to call it?}} {{25-25=()}} +let _ : Color = .rainbow // expected-error {{member 'rainbow()' is a function that produces expected type 'Color'; did you mean to call it?}} {{25-25=()}} let _: Color = .overload(a : 1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} let _: Color = .overload(1.0) // expected-error {{no exact matches in call to static method 'overload'}} diff --git a/test/Constraints/function_builder.swift b/test/Constraints/function_builder.swift index eb5e6857c55c1..d30a3a932f7ce 100644 --- a/test/Constraints/function_builder.swift +++ b/test/Constraints/function_builder.swift @@ -6,10 +6,6 @@ enum Either { case second(U) } -struct Do { - var value: T -} - @_functionBuilder struct TupleBuilder { static func buildBlock(_ t1: T1) -> (T1) { @@ -36,19 +32,6 @@ struct TupleBuilder { return (t1, t2, t3, t4, t5) } - static func buildDo(_ t1: T1) -> Do<(T1)> { - .init(value: t1) - } - - static func buildDo(_ t1: T1, _ t2: T2) -> Do<(T1, T2)> { - .init(value: (t1, t2)) - } - - static func buildDo(_ t1: T1, _ t2: T2, _ t3: T3) - -> Do<(T1, T2, T3)> { - .init(value: (t1, t2, t3)) - } - static func buildIf(_ value: T?) -> T? { return value } static func buildEither(first value: T) -> Either { @@ -61,11 +44,11 @@ struct TupleBuilder { static func buildArray(_ array: [T]) -> [T] { return array } } -func tuplify(_ cond: Bool, @TupleBuilder body: (Bool) -> T) { - print(body(cond)) +func tuplify(_ cond: Bool, @TupleBuilder body: (Bool) throws -> T) rethrows { + print(try body(cond)) } -// CHECK: (17, 3.14159, "Hello, DSL", main.Do<(Swift.Array, Swift.Int)>(value: (["nested", "do"], 6)), Optional((2.71828, ["if", "stmt"]))) +// CHECK: (17, 3.14159, "Hello, DSL", (["nested", "do"], 6), Optional((2.71828, ["if", "stmt"]))) let name = "dsl" tuplify(true) { 17 @@ -664,7 +647,6 @@ struct TupleBuilderWithOpt { return (t1, t2, t3, t4, t5) } - static func buildDo(_ value: T) -> T { return value } static func buildOptional(_ value: T?) -> T? { return value } static func buildEither(first value: T) -> Either { @@ -703,5 +685,85 @@ tuplify(true) { c in } } +// Test the use of function builders partly implemented through a protocol. +indirect enum FunctionBuilder { + case expression(Expression) + case block([FunctionBuilder]) + case either(Either) + case optional(FunctionBuilder?) +} + +protocol FunctionBuilderProtocol { + associatedtype Expression + typealias Component = FunctionBuilder + associatedtype Return + + static func buildExpression(_ expression: Expression) -> Component + static func buildBlock(_ components: Component...) -> Component + static func buildOptional(_ optional: Component?) -> Component + static func buildArray(_ components: [Component]) -> Component + static func buildLimitedAvailability(_ component: Component) -> Component + + static func buildFinalResult(_ components: Component) -> Return +} +extension FunctionBuilderProtocol { + static func buildExpression(_ expression: Expression) -> Component { .expression(expression) } + static func buildBlock(_ components: Component...) -> Component { .block(components) } + static func buildOptional(_ optional: Component?) -> Component { .optional(optional) } + static func buildArray(_ components: [Component]) -> Component { .block(components) } + static func buildLimitedAvailability(_ component: Component) -> Component { component } +} +@_functionBuilder +enum ArrayBuilder: FunctionBuilderProtocol { + typealias Expression = E + typealias Component = FunctionBuilder + typealias Return = [E] + + static func buildFinalResult(_ components: Component) -> Return { + switch components { + case .expression(let e): return [e] + case .block(let children): return children.flatMap(buildFinalResult) + case .either(.first(let child)): return buildFinalResult(child) + case .either(.second(let child)): return buildFinalResult(child) + case .optional(let child?): return buildFinalResult(child) + case .optional(nil): return [] + } + } +} + + +func buildArray(@ArrayBuilder build: () -> [String]) -> [String] { + return build() +} + + +let a = buildArray { + "1" + "2" + if Bool.random() { + "maybe 3" + } +} +// CHECK: ["1", "2" +print(a) + +// Throwing in function builders. +enum MyError: Error { + case boom +} + +// CHECK: testThrow +do { + print("testThrow") + try tuplify(true) { c in + "ready to throw" + throw MyError.boom + } +} catch MyError.boom { + // CHECK: caught it! + print("caught it!") +} catch { + fatalError("Threw something else?") +} diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index 7a7029b499935..36bba5457d066 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -6,7 +6,7 @@ enum Either { } @_functionBuilder -struct TupleBuilder { // expected-note 3{{struct 'TupleBuilder' declared here}} +struct TupleBuilder { // expected-note 2 {{struct 'TupleBuilder' declared here}} static func buildBlock() -> () { } static func buildBlock(_ t1: T1) -> T1 { @@ -87,7 +87,7 @@ func testDiags() { // For loop tuplify(true) { _ in 17 - for c in name { // expected-error{{closure containing control flow statement cannot be used with function builder 'TupleBuilder'}} + for c in name { // expected-error@-1 {{cannot find 'name' in scope}} } } @@ -418,13 +418,16 @@ func testNonExhaustiveSwitch(e: E) { // rdar://problem/59856491 struct TestConstraintGenerationErrors { @TupleBuilder var buildTupleFnBody: String { - let a = nil // expected-error {{'nil' requires a contextual type}} + let a = nil // There is no diagnostic here because next line fails to pre-check, so body is invalid String(nothing) // expected-error {{cannot find 'nothing' in scope}} } + @TupleBuilder var nilWithoutContext: String { + let a = nil // expected-error {{'nil' requires a contextual type}} + } + func buildTupleClosure() { - // FIXME: suppress the ambiguity error - tuplify(true) { _ in // expected-error {{type of expression is ambiguous without more context}} + tuplify(true) { _ in let a = nothing // expected-error {{cannot find 'nothing' in scope}} String(nothing) // expected-error {{cannot find 'nothing' in scope}} } @@ -616,7 +619,27 @@ struct MyView { } // expected-error {{expected identifier after '.' expression}} } + @TupleBuilder var invalidCaseWithoutDot: some P { + switch Optional.some(1) { + case none: 42 // expected-error {{cannot find 'none' in scope}} + case .some(let x): + 0 + } + } + @TupleBuilder var invalidConversion: Int { // expected-error {{cannot convert value of type 'String' to specified type 'Int'}} "" } } + +// Make sure throwing function builder closures are implied. +enum MyError: Error { + case boom +} + +do { + tuplify(true) { c in // expected-error{{invalid conversion from throwing function of type '(Bool) throws -> String' to non-throwing function type '(Bool) -> String'}} + "testThrow" + throw MyError.boom + } +} diff --git a/test/Constraints/keypath.swift b/test/Constraints/keypath.swift index 107739ee0b9a8..2512e9d9f372b 100644 --- a/test/Constraints/keypath.swift +++ b/test/Constraints/keypath.swift @@ -179,3 +179,11 @@ func key_path_root_mismatch(_ base: KeyPathBase?, subBase: KeyPathBaseSubtype let _ : T = subBase[keyPath: kpa] // expected-error {{key path with root type 'AnotherBase' cannot be applied to a base of type 'KeyPathBaseSubtype?'}} } + +// SR-13442 +func SR13442(_ x: KeyPath) -> T { "1"[keyPath: x] } + +func testSR13442() { + _ = SR13442(\.!.count) // OK + _ = SR13442(\String?.!.count) // OK +} diff --git a/test/Constraints/optional.swift b/test/Constraints/optional.swift index 246abdbe22491..352a8bee83eff 100644 --- a/test/Constraints/optional.swift +++ b/test/Constraints/optional.swift @@ -64,15 +64,17 @@ func test5() -> Int? { } func test6(_ x : T) { - // FIXME: this code should work; T could be Int? or Int?? - // or something like that at runtime. rdar://16374053 - _ = x as? Int? // expected-error {{cannot downcast from 'T' to a more optional type 'Int?'}} + _ = x as? Int? // Okay. We know nothing about T, so cannot judge. } class B : A { } func test7(_ x : A) { - _ = x as? B? // expected-error{{cannot downcast from 'A' to a more optional type 'B?'}} + _ = x as? B? // Okay: Injecting into an Optional +} + +func test7a(_ x : B) { + _ = x as? A // expected-warning{{conditional cast from 'B' to 'A' always succeeds}} } func test8(_ x : AnyObject?) { diff --git a/test/Constraints/rdar39931339.swift b/test/Constraints/rdar39931339.swift index 40add2eb11c18..eee8de950baad 100644 --- a/test/Constraints/rdar39931339.swift +++ b/test/Constraints/rdar39931339.swift @@ -32,12 +32,12 @@ _ = B.S1() // Ok _ = B.S2() // Ok _ = B.S1() // expected-error {{type 'Float' does not conform to protocol 'P'}} _ = B.S2() -// expected-error@-1 {{'B.S2' (aka 'Int') requires the types '[String]' and '[Int]' be equivalent}} +// expected-error@-1 {{'A.S2' (aka 'Int') requires the types '[String]' and '[Int]' be equivalent}} _ = S.A() // Ok _ = S.A() // expected-error {{type 'Int' does not conform to protocol 'P'}} _ = S.B() // expected-error {{type 'String' does not conform to protocol 'P'}} -_ = S.C() // expected-error {{'S.C' (aka 'Int') requires the types 'Int' and 'Float' be equivalent}} +_ = S.C() // expected-error {{'S.C' (aka 'Int') requires the types 'Int' and 'Float' be equivalent}} func foo(_ s: S.Type) { _ = s.A() // expected-error {{referencing type alias 'A' on 'S' requires that 'T' conform to 'P'}} diff --git a/test/Constraints/rdar44770297.swift b/test/Constraints/rdar44770297.swift index 8d0b128b9e136..9853dd1ca2f53 100644 --- a/test/Constraints/rdar44770297.swift +++ b/test/Constraints/rdar44770297.swift @@ -4,10 +4,8 @@ protocol P { associatedtype A } -func foo(_: () throws -> T) -> T.A? { +func foo(_: () throws -> T) -> T.A? { // expected-note {{where 'T' = 'Never'}} fatalError() } -let _ = foo() {fatalError()} & nil // expected-error {{value of optional type 'Never.A?' must be unwrapped to a value of type 'Never.A'}} -// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} -// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} +let _ = foo() {fatalError()} & nil // expected-error {{global function 'foo' requires that 'Never' conform to 'P'}} diff --git a/test/Constraints/rdar65320500.swift b/test/Constraints/rdar65320500.swift new file mode 100644 index 0000000000000..dfb8f722a2692 --- /dev/null +++ b/test/Constraints/rdar65320500.swift @@ -0,0 +1,43 @@ +// RUN: %target-typecheck-verify-swift + +struct Result {} + +@_functionBuilder +struct Builder { + static func buildBlock() -> Result { + Result() + } +} + +func test_builder(@Builder _: () -> T) {} +func test_builder(@Builder _: () -> Int) {} + +test_builder { + let _ = 0 + + if let x = does_not_exist { // expected-error {{cannot find 'does_not_exist' in scope}} + } +} + +func test(_: Int) -> Bool { + return false +} + +test_builder { + let totalSeconds = 42000 + test(totalseconds / 3600) // expected-error {{cannot find 'totalseconds' in scope}} +} + +test_builder { + test(doesntExist()) // expected-error {{cannot find 'doesntExist' in scope}} + + if let result = doesntExist() { // expected-error {{cannot find 'doesntExist' in scope}} + } + + if bar = test(42) {} // expected-error {{cannot find 'bar' in scope}} + + let foo = bar() // expected-error {{cannot find 'bar' in scope}} + + switch (doesntExist()) { // expected-error {{cannot find 'doesntExist' in scope}} + } +} diff --git a/test/Constraints/requirement_failures_in_contextual_type.swift b/test/Constraints/requirement_failures_in_contextual_type.swift index 31eb477fa7153..75bf679ad92ce 100644 --- a/test/Constraints/requirement_failures_in_contextual_type.swift +++ b/test/Constraints/requirement_failures_in_contextual_type.swift @@ -14,11 +14,11 @@ extension A where T == Int32 { // expected-note 3{{requirement specified as 'T' } let _: A.B = 0 -// expected-error@-1 {{'A.B' requires the types 'Int' and 'Int32' be equivalent}} +// expected-error@-1 {{'A.B' requires the types 'Int' and 'Int32' be equivalent}} let _: A.C = 0 -// expected-error@-1 {{'A.C' (aka 'Int') requires the types 'Int' and 'Int32' be equivalent}} +// expected-error@-1 {{'A.C' (aka 'Int') requires the types 'Int' and 'Int32' be equivalent}} let _: A.B.E = 0 -// expected-error@-1 {{'A.B' requires the types 'Int' and 'Int32' be equivalent}} +// expected-error@-1 {{'A.B' requires the types 'Int' and 'Int32' be equivalent}} protocol P {} diff --git a/test/Constraints/valid_pointer_conversions.swift b/test/Constraints/valid_pointer_conversions.swift index 3a3bd9ea9cbc4..265083a6bc211 100644 --- a/test/Constraints/valid_pointer_conversions.swift +++ b/test/Constraints/valid_pointer_conversions.swift @@ -41,3 +41,8 @@ func SR12382(_ x: UnsafeMutablePointer??) {} var i = 0 SR12382(&i) // expected-error {{cannot convert value of type 'UnsafeMutablePointer' to expected argument type 'UnsafeMutablePointer'}} // expected-note@-1 {{arguments to generic parameter 'Pointee' ('Int' and 'Double') are expected to be equal}} + +//problem/68254165 - Bad diagnostic when using String init(decodingCString:) with an incorrect pointer type +func rdar68254165(ptr: UnsafeMutablePointer) { + _ = String(decodingCString: ptr, as: .utf8) // expected-error {{generic parameter 'Encoding' could not be inferred}} +} diff --git a/test/DebugInfo/Inputs/Macro.h b/test/DebugInfo/Inputs/Macro.h index 5f43bbf5641a6..7cba01337adde 100644 --- a/test/DebugInfo/Inputs/Macro.h +++ b/test/DebugInfo/Inputs/Macro.h @@ -1,6 +1,12 @@ +#ifdef __cplusplus #define MY_ENUM(NAME) \ - enum NAME : int NAME; \ enum NAME : int +#else +#define MY_ENUM(NAME) \ + enum NAME : int; \ + typedef enum NAME NAME; \ + enum NAME : int +#endif MY_ENUM(macro_enum) { zero = 0 diff --git a/test/DebugInfo/inlinescopes.swift b/test/DebugInfo/inlinescopes.swift index 6c4a3a4fefc3d..4b40340d49a28 100644 --- a/test/DebugInfo/inlinescopes.swift +++ b/test/DebugInfo/inlinescopes.swift @@ -6,13 +6,17 @@ // RUN: %FileCheck %s -check-prefix=TRANSPARENT-CHECK < %t.ll // CHECK: define{{( dllexport)?}}{{( protected)?( signext)?}} i32 @main{{.*}} -// CHECK: call swiftcc i64 @"$s4main8noinlineys5Int64VADF"(i64 %{{.*}}), !dbg ![[CALL:.*]] +// CHECK: call swiftcc i64 @"$s4main8noinlineys5Int64VADF"(i64 %{{.*}}) +// CHECK-SAME: !dbg ![[CALL:.*]] // CHECK-DAG: ![[TOPLEVEL:.*]] = !DIFile(filename: "{{.*}}inlinescopes.swift" import FooBar @inline(never) -func noinline(_ x: Int64) -> Int64 { return x } +func use(_ x: Int64) -> Int64 { return x } + +@inline(never) +func noinline(_ x: Int64) -> Int64 { return use(x) } @_transparent func transparent(_ x: Int64) -> Int64 { return noinline(x) } diff --git a/test/DebugInfo/modulecache.swift b/test/DebugInfo/modulecache.swift index 6af85efa2bcf3..22d126eca7cde 100644 --- a/test/DebugInfo/modulecache.swift +++ b/test/DebugInfo/modulecache.swift @@ -16,7 +16,7 @@ import ClangModule // RUN: %empty-directory(%t) // RUN: %target-swift-frontend %s -c -g -o %t.o -module-cache-path %t -I %S/Inputs // RUN: llvm-readobj -h %t/*/ClangModule-*.pcm | %FileCheck %s -// CHECK: Format: {{(Mach-O|ELF|COFF|WASM)}} +// CHECK: Format: {{(Mach-O|ELF|elf64|COFF|elf32-littlearm|WASM)}} // 3. Test that swift-ide-check will not share swiftc's module cache. diff --git a/test/DebugInfo/top_level_code.swift b/test/DebugInfo/top_level_code.swift index 790f5dffbdf84..6693d78863fb4 100644 --- a/test/DebugInfo/top_level_code.swift +++ b/test/DebugInfo/top_level_code.swift @@ -2,7 +2,7 @@ func markUsed(_ t: T) {} // CHECK: {{_?}}main: -// CHECK-NEXT: Lfunc_begin0: +// CHECK: Lfunc_begin0: // Verify that the top-level function (main) begins at line 0 and then // proceeds to the first line. // CHECK: .loc {{[0-9]}} 0 {{[0-9]}} diff --git a/test/DebugInfo/transparent.swift b/test/DebugInfo/transparent.swift index 5bfd301c65ca6..b951b4a19e012 100644 --- a/test/DebugInfo/transparent.swift +++ b/test/DebugInfo/transparent.swift @@ -19,7 +19,6 @@ use(z) // CHECK-SAME: !dbg ![[SP:[0-9]+]] // CHECK-NEXT: entry: // CHECK-NEXT: !dbg ![[ZERO:[0-9]+]] -// CHECK-NEXT: !dbg ![[ZERO]] // CHECK-NEXT: } // CHECK: ![[FILE:[0-9]+]] = {{.*}}"" diff --git a/test/DebugInfo/vector.swift b/test/DebugInfo/vector.swift index d815055df63ff..f50164ce1f54f 100644 --- a/test/DebugInfo/vector.swift +++ b/test/DebugInfo/vector.swift @@ -4,7 +4,7 @@ // CHECK: !DICompositeType(tag: DW_TAG_array_type, baseType: ![[FLOAT:[0-9]+]], size: 64, flags: DIFlagVector, elements: ![[ELTS:[0-9]+]]) // CHECK: ![[FLOAT]] = !DIBasicType(name: "$sBf32_D", size: 32, encoding: DW_ATE_float) // CHECK: ![[ELTS]] = !{![[SR:[0-9]+]]} -// CHECK: ![[SR]] = !DISubrange(count: 2) +// CHECK: ![[SR]] = !DISubrange(count: 2, lowerBound: 0) import Swift diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index 01591a1ab8530..f0b200e2979a9 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -365,3 +365,5 @@ $s0059xxxxxxxxxxxxxxx_ttttttttBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBee -> $s0059xxxx $sx1td_t ---> (t: A...) $s7example1fyyYF -> example.f() async -> () $s7example1fyyYKF -> example.f() async throws -> () +$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF ---> main.receiveInstantiation(inout __C.__CxxTemplateInst12MagicWrapperIiE) -> () +$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF ---> main.returnInstantiation() -> __C.__CxxTemplateInst12MagicWrapperIiE diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreDaemon.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreDaemon.h new file mode 100644 index 0000000000000..82d8f39a18d69 --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreDaemon.h @@ -0,0 +1,5 @@ +typedef void Runner(int); + +struct Daemon { + Runner *run; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreMemory.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreMemory.h new file mode 100644 index 0000000000000..058328d0f82a9 --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreMemory.h @@ -0,0 +1,4 @@ +struct MemoryMapRegion { + void *start; + void *end; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/DaemonKit.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/DaemonKit.h new file mode 100644 index 0000000000000..7a4cc1d8c8866 --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/DaemonKit.h @@ -0,0 +1,7 @@ +#import + +#import + +struct DaemonPair { + struct Daemon daemons[2]; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/ViolateSecondLawOfThermodynamics.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/ViolateSecondLawOfThermodynamics.h new file mode 100644 index 0000000000000..2850f0f6f424c --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/ViolateSecondLawOfThermodynamics.h @@ -0,0 +1,5 @@ +#import + +struct MaxwellsDaemon { + Runner *doorOperation; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/FilesystemKit.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/FilesystemKit.h new file mode 100644 index 0000000000000..5956aaf20c0cf --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/FilesystemKit.h @@ -0,0 +1,5 @@ +#import + +struct FileStorage { + MyNode *nodes[4]; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/MemoryKit.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/MemoryKit.h new file mode 100644 index 0000000000000..fd8b265646ccc --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/MemoryKit.h @@ -0,0 +1,7 @@ +#import +#import + +struct MemoryMap { + MemoryMapEntry *entries; + unsigned count; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/module.modulemap b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/module.modulemap new file mode 100644 index 0000000000000..6fee43771483d --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/module.modulemap @@ -0,0 +1,33 @@ +module CoreFilesystem { + header "CoreFilesystem-Generated.h" + export * +} + +module FilesystemKit { + header "FilesystemKit.h" + export * +} + +module CoreDaemon { + header "CoreDaemon.h" + export * +} + +module DaemonKit { + umbrella header "DaemonKit/DaemonKit.h" + explicit module ViolateSecondLawOfThermodynamics { + header "DaemonKit/ViolateSecondLawOfThermodynamics.h" + export * + } + export * +} + +module CoreMemory { + header "CoreMemory.h" + export * +} + +module MemoryKit { + header "MemoryKit.h" + export * +} diff --git a/test/Driver/Inputs/imported_modules/SelfImport/module.modulemap b/test/Driver/Inputs/imported_modules/SelfImport/module.modulemap new file mode 100644 index 0000000000000..df67010362525 --- /dev/null +++ b/test/Driver/Inputs/imported_modules/SelfImport/module.modulemap @@ -0,0 +1,6 @@ +module Outer { + module Inner { + export Outer.Inner + } + export Outer +} diff --git a/test/Driver/badJ.swift b/test/Driver/badJ.swift new file mode 100644 index 0000000000000..9f27b6735d52f --- /dev/null +++ b/test/Driver/badJ.swift @@ -0,0 +1,2 @@ +// RUN: not %swiftc_driver %S/../Inputs/empty.swift -jsnort 2>&1 | %FileCheck %s +// CHECK-NOT: Stack dump diff --git a/test/Driver/bad_tmpdir.swift b/test/Driver/bad_tmpdir.swift index bf0565ef89439..50be890aee355 100644 --- a/test/Driver/bad_tmpdir.swift +++ b/test/Driver/bad_tmpdir.swift @@ -6,6 +6,9 @@ // // REQUIRES: OS=macosx +// SR-12362: This test is failing on master-next. +// XFAIL: * + // RUN: env TMP="%t/fake/" TMPDIR="%t/fake/" not %target-build-swift -c -driver-filelist-threshold=0 %s 2>&1 | %FileCheck -check-prefix=CHECK-SOURCES %s // CHECK-SOURCES: - unable to create list of input sources diff --git a/test/Driver/coverage-prefix-map.swift b/test/Driver/coverage-prefix-map.swift index fd2ff8a5cbc2c..c4f42d0bff999 100644 --- a/test/Driver/coverage-prefix-map.swift +++ b/test/Driver/coverage-prefix-map.swift @@ -3,7 +3,7 @@ // RUN: %target-swiftc_driver -### -coverage-prefix-map old=n=ew %s 2>&1 | %FileCheck %s -check-prefix CHECK-COMPLEX // RUN: %target-swiftc_driver -### -coverage-prefix-map old= %s 2>&1 | %FileCheck %s -check-prefix CHECK-EMPTY -// CHECK-INVALID: error: invalid argument 'old' to -coverage-prefix-map +// CHECK-INVALID: error: values for '-coverage-prefix-map' must be in the format 'original=remapped', but 'old' was provided // CHECK-SIMPLE: coverage-prefix-map old=new // CHECK-COMPLEX: coverage-prefix-map old=n=ew // CHECK-EMPTY: coverage-prefix-map old= diff --git a/test/Driver/debug-prefix-map.swift b/test/Driver/debug-prefix-map.swift index 3483f3fe3c856..d23e72faf4fd5 100644 --- a/test/Driver/debug-prefix-map.swift +++ b/test/Driver/debug-prefix-map.swift @@ -3,7 +3,7 @@ // RUN: %target-swiftc_driver -### -debug-prefix-map old=n=ew %s 2>&1 | %FileCheck %s -check-prefix CHECK-COMPLEX // RUN: %target-swiftc_driver -### -debug-prefix-map old= %s 2>&1 | %FileCheck %s -check-prefix CHECK-EMPTY -// CHECK-INVALID: error: invalid argument 'old' to -debug-prefix-map +// CHECK-INVALID: error: values for '-debug-prefix-map' must be in the format 'original=remapped', but 'old' was provided // CHECK-SIMPLE: debug-prefix-map old=new // CHECK-COMPLEX: debug-prefix-map old=n=ew // CHECK-EMPTY: debug-prefix-map old= diff --git a/test/Driver/emit-module-summary.swift b/test/Driver/emit-module-summary.swift new file mode 100644 index 0000000000000..d1fef3299ae20 --- /dev/null +++ b/test/Driver/emit-module-summary.swift @@ -0,0 +1,6 @@ +// RUN: %empty-directory(%t) +// RUN: echo 'print("Hello, World!")' >%t/main.swift +// RUN: cd %t + +// RUN: %target-swiftc_driver -emit-sib -emit-module-summary -emit-module-summary-path %t/main.swiftmodulesummary %t/main.swift +// RUN: test -f %t/main.swiftmodulesummary diff --git a/test/Driver/loaded_module_trace_directness_2.swift b/test/Driver/loaded_module_trace_directness_2.swift new file mode 100644 index 0000000000000..79e3ce25223a3 --- /dev/null +++ b/test/Driver/loaded_module_trace_directness_2.swift @@ -0,0 +1,185 @@ +// RUN: %empty-directory(%t) +// RUN: cp -r %S/Inputs/imported_modules/ComplexModuleGraph2 %t/include + +// REQUIRES: objc_interop + +// Dependency graph: +// +// * CoreFilesystem - Swift module with generated ObjC header +// * FilesystemKit - ObjC module without overlay, has #import +// * TestFilesystem - Swift module, has import CoreFilesystem or FilesystemKit. +// +// * CoreDaemon - ObjC module with overlay, the overlay has import DaemonKit +// * DaemonKit - ObjC module without overlay, has #import +// * TestDaemon - Swift module, has import CoreDaemon or DaemonKit. +// NOTE: This mimics the Darwin -> SwiftOverlayShims -> Darwin dependency "cycle". +// +// * CoreMemory - ObjC module with overlay and generated header for overlay, the overlay has import MemoryKit +// * MemoryKit - ObjC module without overlay, has #import +// * TestMemory - Swift module, has import CoreMemory or MemoryKit. + +// 1. CoreFilesystem - Build. + +// RUN: %target-swift-frontend %s -emit-module -o %t/include/CoreFilesystem.swiftmodule -DCoreFilesystem -module-name CoreFilesystem -emit-objc-header-path %t/include/CoreFilesystem-Generated.h -disable-objc-attr-requires-foundation-module + +#if CoreFilesystem +@objc +public class MyNode { + public var number: Int + public init(_ n: Int) { number = n } +} +#endif + +// 2. FilesystemKit - Nothing to do (pure Clang module). + +// 3. TestFilesystem - Check that CoreFilesystem and Filesytem can be imported. + +// RUN: %target-swift-frontend %s -typecheck -DTestFilesystem -DV1 -module-name TestFilesystemV1 -emit-loaded-module-trace-path %t/TestFilesystemV1.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTFILESYSTEM < %t/TestFilesystemV1.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestFilesystem -DV2 -module-name TestFilesystemV2 -emit-loaded-module-trace-path %t/TestFilesystemV2.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTFILESYSTEM < %t/TestFilesystemV2.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestFilesystem -DV3 -module-name TestFilesystemV3 -emit-loaded-module-trace-path %t/TestFilesystemV3.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTFILESYSTEM < %t/TestFilesystemV3.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestFilesystem -DV4 -module-name TestFilesystemV4 -emit-loaded-module-trace-path %t/TestFilesystemV4.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTFILESYSTEM < %t/TestFilesystemV4.trace.json + +#if TestFilesystem + #if V1 + import CoreFilesystem + #endif + #if V2 + import FilesystemKit + public func noop(_: CoreFilesystem.MyNode) {} + #endif + #if V3 + import CoreFilesystem + import FilesystemKit + #endif + #if V4 + import FilesystemKit + import CoreFilesystem + #endif +#endif + +// FilesystemKit has no overlay, so it shouldn't show up. +// TESTFILESYSTEM: "swiftmodulesDetailedInfo":[ +// TESTFILESYSTEM-NOT: FilesystemKit +// TESTFILESYSTEM-DAG: {"name":"CoreFilesystem","path":"{{[^"]*}}CoreFilesystem.swiftmodule","isImportedDirectly":true, +// TESTFILESYSTEM: ] + +// 4. CoreDaemon - Build. + +// RUN: %target-swift-frontend %s -emit-module -o %t/include/CoreDaemon.swiftmodule -DCoreDaemon -module-name CoreDaemon -emit-loaded-module-trace-path %t/CoreDaemon.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=COREDAEMON < %t/CoreDaemon.trace.json + +// * CoreDaemon - ObjC module with overlay, the overlay has import DaemonKit +// * DaemonKit - ObjC module without overlay, has #import +// * TestDaemon - Swift module, has import CoreDaemon or DaemonKit. + +#if CoreDaemon +@_exported import CoreDaemon +import DaemonKit + +public func runBoth(_ pair: DaemonKit.DaemonPair) { + let daemons : (CoreDaemon.Daemon, CoreDaemon.Daemon) = pair.daemons; + daemons.0.run(0); + daemons.1.run(1); +} +#endif + +// COREDAEMON: "swiftmodulesDetailedInfo":[ +// COREDAEMON-NOT: CoreDaemon +// COREDAEMON-NOT: DaemonKit +// COREDAEMON: ] + +// 5. DaemonKit - Nothing to do (pure Clang module). + +// 6. TestCoreDaemon + +// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV1 -module-name TestDaemonV1 -emit-loaded-module-trace-path %t/TestDaemonV1.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV1.trace.json + +// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV2 -module-name TestDaemonV2 -emit-loaded-module-trace-path %t/TestDaemonV2.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV2.trace.json + +// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV3 -module-name TestDaemonV3 -emit-loaded-module-trace-path %t/TestDaemonV3.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV3.trace.json + +// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV4 -module-name TestDaemonV4 -emit-loaded-module-trace-path %t/TestDaemonV4.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV4.trace.json + +#if TestDaemon + #if V1 + import CoreDaemon + #endif + #if V2 + import DaemonKit + public func noop(_: CoreDaemon.Daemon, _: MaxwellsDaemon) {} + #endif + #if V3 + import CoreDaemon + import DaemonKit + #endif + #if V4 + import DaemonKit + import CoreDaemon + #endif +#endif + +// DaemonKit has no overlay, so it shouldn't show up. +// TESTDAEMON: "swiftmodulesDetailedInfo":[ +// TESTDAEMON-NOT: DaemonKit +// TESTDAEMON-DAG: {"name":"CoreDaemon","path":"{{[^"]*}}CoreDaemon.swiftmodule","isImportedDirectly":true, +// TESTDAEMON: ] + +// 7. CoreMemory - Build. + +// RUN: %target-swift-frontend %s -emit-module -o %t/include/CoreMemory.swiftmodule -DCoreMemory -module-name CoreMemory -emit-objc-header-path %t/include/CoreMemory-Generated.h -disable-objc-attr-requires-foundation-module -I %t/include + +#if CoreMemory +@_exported import CoreMemory + +@objc +public class MemoryMapEntry { + public var region: MemoryMapRegion + public var permissions: Int = 0 + public init(_ r: MemoryMapRegion) { region = r } +} +#endif + +// 8. MemoryKit - Nothing to do (pure Clang module). + +// 9. TestMemory - Check that CoreMemory and MemoryKit can be imported. + +// RUN: %target-swift-frontend %s -typecheck -DTestMemory -DV1 -module-name TestMemoryV1 -emit-loaded-module-trace-path %t/TestMemoryV1.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTMEMORY < %t/TestMemoryV1.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestMemory -DV2 -module-name TestMemoryV2 -emit-loaded-module-trace-path %t/TestMemoryV2.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTMEMORY < %t/TestMemoryV2.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestMemory -DV3 -module-name TestMemoryV3 -emit-loaded-module-trace-path %t/TestMemoryV3.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTMEMORY < %t/TestMemoryV3.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestMemory -DV4 -module-name TestMemoryV4 -emit-loaded-module-trace-path %t/TestMemoryV4.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTMEMORY < %t/TestMemoryV4.trace.json + +#if TestMemory + #if V1 + import CoreMemory + #endif + #if V2 + import MemoryKit + public func noop(_: CoreMemory.MemoryMapRegion, _: CoreMemory.MemoryMapEntry) {} + #endif + #if V3 + import CoreMemory + import MemoryKit + #endif + #if V4 + import MemoryKit + import CoreMemory + #endif +#endif + +// MemoryKit has no overlay, so it shouldn't show up. +// TESTMEMORY: "swiftmodulesDetailedInfo":[ +// TESTMEMORY-NOT: MemoryKit +// TESTMEMORY-DAG: {"name":"CoreMemory","path":"{{[^"]*}}CoreMemory.swiftmodule","isImportedDirectly":true, +// TESTMEMORY: ] diff --git a/test/Driver/loaded_module_trace_self_cycle.swift b/test/Driver/loaded_module_trace_self_cycle.swift new file mode 100644 index 0000000000000..309ef714e34bf --- /dev/null +++ b/test/Driver/loaded_module_trace_self_cycle.swift @@ -0,0 +1,4 @@ +// Check that this doesn't crash due to a self-cycle. rdar://67435472 +// RUN: %target-swift-frontend %s -emit-module -o /dev/null -emit-loaded-module-trace-path /dev/null -I %S/Inputs/imported_modules/SelfImport + +import Outer diff --git a/test/Frontend/emit-module-summary.swift b/test/Frontend/emit-module-summary.swift new file mode 100644 index 0000000000000..7e69f23c95247 --- /dev/null +++ b/test/Frontend/emit-module-summary.swift @@ -0,0 +1,10 @@ +// RUN: %empty-directory(%t) +// RUN: echo 'print("Hello, World!")' >%t/main.swift +// RUN: cd %t + +// RUN: %target-swift-frontend -emit-sib -emit-module-summary-path %t/main.swiftmodulesummary %t/main.swift +// RUN: test -f %t/main.swiftmodulesummary + +// RUN: echo '"%/t/main.swift": { swiftmodulesummary: "%/t/foo.swiftmodulesummary" }' > %/t/filemap.yaml +// RUN: %target-swift-frontend -emit-sib -supplementary-output-file-map %/t/filemap.yaml %/t/main.swift +// RUN: test -f %t/foo.swiftmodulesummary diff --git a/test/Generics/constrained_type_witnesses.swift b/test/Generics/constrained_type_witnesses.swift new file mode 100644 index 0000000000000..e56586e752a64 --- /dev/null +++ b/test/Generics/constrained_type_witnesses.swift @@ -0,0 +1,75 @@ +// RUN: %target-typecheck-verify-swift + +protocol P { + associatedtype A + // expected-note@-1 3{{protocol requires nested type 'A'; do you want to add it?}} +} + +struct S1 {} + +extension S1 where T : P { + typealias A = Int +} + +// This is rejected because S1.A is not a suitable witness for P.A. +extension S1 : P {} +// expected-error@-1 {{type 'S1' does not conform to protocol 'P'}} + +struct S2 {} + +extension S2 where T : P { + typealias A = Never +} + +// Hack: This is OK to make SwiftUI work, which accidentally relies on the +// incorrect behavior with a typealias whose underlying type is 'Never' +// (so it didn't hit the compiler crash). +extension S2 : P {} + +// Here we have a suitable witness +struct S3 {} + +extension S3 where T == Int { + typealias A = Int +} + +extension S3 : P where T == Int {} + +// Check where clause on the type itself + +struct S4 { + typealias A = Int where T : P +} + +extension S4 : P {} +// expected-error@-1 {{type 'S4' does not conform to protocol 'P'}} + +struct S5 { + typealias A = Never where T : P +} + +extension S5 : P {} + +struct S6 { + typealias A = Int where T == Int +} + +extension S6 : P where T == Int {} + +// Witness in a constrained protocol extension +protocol Q { + associatedtype B +} + +extension Q where B == Int { + typealias A = Int +} + +struct S7 : Q, P { + typealias B = Int +} + +struct S8 : Q, P { +// expected-error@-1 {{type 'S8' does not conform to protocol 'P'}} + typealias B = String +} diff --git a/test/Generics/unbound.swift b/test/Generics/unbound.swift index aed3469e8f6b5..8f57d930ee13c 100644 --- a/test/Generics/unbound.swift +++ b/test/Generics/unbound.swift @@ -74,3 +74,20 @@ struct X1 { func bar() where T: X2 {} } class X2 {} + +// missing check for unbound parent type +struct Outer { + struct Inner {} + + struct Middle { + typealias Inner = Outer.Middle + } +} + +func makeInner() -> Outer.Middle.Inner { + return .init() +} + +var innerProperty: Outer.Middle.Inner = makeInner() +// expected-error@-1 {{reference to generic type 'Outer' requires arguments in <...>}} + diff --git a/test/Generics/where_clause_contextually_generic_decls.swift b/test/Generics/where_clause_contextually_generic_decls.swift index 96b2c4fb6ed99..27819a167a03f 100644 --- a/test/Generics/where_clause_contextually_generic_decls.swift +++ b/test/Generics/where_clause_contextually_generic_decls.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift -typecheck %s -verify -swift-version 4 +// RUN: %target-typecheck-verify-swift -swift-version 4 func bet() where A : B {} // expected-error {{'where' clause cannot be applied to a non-generic top-level declaration}} @@ -148,7 +148,7 @@ _ = Container.NestedAlias2.self // expected-error {{type 'String' does n _ = Container>.NestedClass.self // expected-error {{type 'Container' does not conform to protocol 'Equatable'}} _ = Container.NestedStruct.self // expected-error {{type 'Void' does not conform to protocol 'Sequence'}} _ = Container>.NestedStruct2.self // expected-error {{type 'Void' does not conform to protocol 'Comparable'}} -_ = Container.NestedStruct2.NestedEnum.self // expected-error {{'Container.NestedStruct2.NestedEnum' requires the types 'String.Element' (aka 'Character') and 'Double' be equivalent}} +_ = Container.NestedStruct2.NestedEnum.self // expected-error {{'Container.NestedStruct2.NestedEnum' requires the types 'String.Element' (aka 'Character') and 'Double' be equivalent}} _ = Container.NestedAlias2.self _ = Container.NestedClass.self _ = Container.NestedStruct.self diff --git a/test/IDE/Inputs/complete_user_accessibility_helper.swift b/test/IDE/Inputs/complete_user_accessibility_helper.swift new file mode 100644 index 0000000000000..0ff5d6c417bf9 --- /dev/null +++ b/test/IDE/Inputs/complete_user_accessibility_helper.swift @@ -0,0 +1,3 @@ +public enum MyEnum { + case foo, bar +} diff --git a/test/IDE/complete_annotation.swift b/test/IDE/complete_annotation.swift index d9dde1ac6c8e5..0e267618ca87a 100644 --- a/test/IDE/complete_annotation.swift +++ b/test/IDE/complete_annotation.swift @@ -95,9 +95,13 @@ func testPostfix(value: MyStruct) { func testImplicitMember() -> MyStruct { return .#^EXPR_IMPLICITMEMBER^# } -// EXPR_IMPLICITMEMBER: Begin completions, 3 items +// EXPR_IMPLICITMEMBER: Begin completions, 7 items // EXPR_IMPLICITMEMBER-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init(x: Int); typename=MyStruct; // EXPR_IMPLICITMEMBER-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: instance; typename=MyStruct; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: labelNameParamName(_ self: MyStruct); typename=(label: (inout Int) throws -> MyStruct) -> Void; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: labelName(_ self: MyStruct); typename=(label: (@autoclosure () -> Int) -> Int) -> Void; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: sameName(_ self: MyStruct); typename=(label: inout Int) -> Void; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: paramName(_ self: MyStruct); typename=(Int) -> Void; // EXPR_IMPLICITMEMBER-DAG: Decl[StaticMethod]/ExprSpecific/TypeRelation[Identical]: create(x: Int); typename=MyStruct; // EXPR_IMPLICITMEMBER: End completions diff --git a/test/IDE/complete_assignment.swift b/test/IDE/complete_assignment.swift index 3fa5753e0b30c..871ef3db1dd2c 100644 --- a/test/IDE/complete_assignment.swift +++ b/test/IDE/complete_assignment.swift @@ -127,17 +127,19 @@ func f2() { d = .#^ASSIGN_5^# } -// ASSIGN_5: Begin completions, 2 items +// ASSIGN_5: Begin completions, 3 items // ASSIGN_5-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case2[#D1#]; name=case2 // ASSIGN_5-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case1[#D1#]; name=case1 +// ASSIGN_5-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): D1#})[#(into: inout Hasher) -> Void#]; name=hash(self: D1) func f6() { var d : D2 d = .#^ASSIGN_6^# } -// ASSIGN_6: Begin completions, 2 items +// ASSIGN_6: Begin completions, 3 items // ASSIGN_6-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case3[#D2#]; name=case3 // ASSIGN_6-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case4[#D2#]; name=case4 +// ASSIGN_6-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): D2#})[#(into: inout Hasher) -> Void#]; name=hash(self: D2) func f7 (C : C2) { var i : Int diff --git a/test/IDE/complete_attributes.swift b/test/IDE/complete_attributes.swift index a1fa33e3a9bb9..e7b5d203500f9 100644 --- a/test/IDE/complete_attributes.swift +++ b/test/IDE/complete_attributes.swift @@ -1,5 +1,7 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_ATTR_1 -code-completion-keywords=false | %FileCheck %s -check-prefix=ERROR_COMMON // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=MEMBER_DECL_ATTR_1 -code-completion-keywords=false | %FileCheck %s -check-prefix=ERROR_COMMON +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ATTRARG_MEMBER | %FileCheck %s -check-prefix=MEMBER_MyValue +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ATTRARG_MEMBER_IN_CLOSURE | %FileCheck %s -check-prefix=MEMBER_MyValue // ERROR_COMMON: found code completion token // ERROR_COMMON-NOT: Keyword/ @@ -9,3 +11,22 @@ class MemberDeclAttribute { @#^MEMBER_DECL_ATTR_1^# func memberDeclAttr1() {} } + +struct MyValue { + init() {} + static var val: Int +} + +// MEMBER_MyValue: Begin completions, 4 items +// MEMBER_MyValue-DAG: Keyword[self]/CurrNominal: self[#MyValue.Type#]; +// MEMBER_MyValue-DAG: Keyword/CurrNominal: Type[#MyValue.Type#]; +// MEMBER_MyValue-DAG: Decl[Constructor]/CurrNominal: init()[#MyValue#]; +// MEMBER_MyValue-DAG: Decl[StaticVar]/CurrNominal: val[#Int#]; +// MEMBER_MyValue: End completions + +class TestUknownDanglingAttr1 { + @UknownAttr(arg: MyValue.#^ATTRARG_MEMBER^#) +} +class TestUknownDanglingAttr2 { + @UknownAttr(arg: { MyValue.#^ATTRARG_MEMBER_IN_CLOSURE^# }) +} diff --git a/test/IDE/complete_call_arg.swift b/test/IDE/complete_call_arg.swift index 978810776e125..bbd17ff20cd9e 100644 --- a/test/IDE/complete_call_arg.swift +++ b/test/IDE/complete_call_arg.swift @@ -78,11 +78,13 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_AFTERPAREN_2 | %FileCheck %s -check-prefix=STATIC_METHOD_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_SECOND | %FileCheck %s -check-prefix=STATIC_METHOD_SECOND // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_SKIPPED | %FileCheck %s -check-prefix=STATIC_METHOD_SKIPPED +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_OVERLOADED | %FileCheck %s -check-prefix=STATIC_METHOD_OVERLOADED // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_AFTERPAREN_1 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_AFTERPAREN_2 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_AFTERPAREN_3 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_3 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_SECOND | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SECOND // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_SKIPPED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SKIPPED +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_OVERLOADED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_OVERLOADED // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_1_AFTERPAREN_1 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_1_AFTERPAREN_2 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_1_SECOND | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SECOND @@ -91,6 +93,7 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_AFTERPAREN_2 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_SECOND | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SECOND // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_SKIPPED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SKIPPED +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_OVERLOADED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_OVERLOADED // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARCHETYPE_GENERIC_1 | %FileCheck %s -check-prefix=ARCHETYPE_GENERIC_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PARAM_WITH_ERROR_AUTOCLOSURE| %FileCheck %s -check-prefix=PARAM_WITH_ERROR_AUTOCLOSURE @@ -579,10 +582,12 @@ func testTupleShuffle() { // SHUFFLE_2-DAG: Decl[GlobalVar]/CurrModule/TypeRelation[Identical]: s1[#String#]; name=s1 // SHUFFLE_2-DAG: Decl[GlobalVar]/CurrModule/TypeRelation[Identical]: s2[#String#]; name=s2 -// SHUFFLE_3: Begin completions, 3 items +// SHUFFLE_3: Begin completions, 4 items // SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: foo[#SimpleEnum#]; name=foo // SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: bar[#SimpleEnum#]; name=bar // SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: baz[#SimpleEnum#]; name=baz +// SHUFFLE_3-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SimpleEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: SimpleEnum) + class HasSubscript { subscript(idx: Int) -> String {} @@ -665,6 +670,8 @@ class TestStaticMemberCall { static func create2(_ arg1: Int, arg2: Int = 0, arg3: Int = 1, arg4: Int = 2) -> TestStaticMemberCall { return TestStaticMemberCall() } + static func createOverloaded(arg1: Int) -> TestStaticMemberCall { TestStaticMemberCall() } + static func createOverloaded(arg1: String) -> String { arg1 } } func testStaticMemberCall() { let _ = TestStaticMemberCall.create1(#^STATIC_METHOD_AFTERPAREN_1^#) @@ -693,24 +700,30 @@ func testStaticMemberCall() { // STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; // STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // STATIC_METHOD_SKIPPED: End completions + + let _ = TestStaticMemberCall.createOverloaded(#^STATIC_METHOD_OVERLOADED^#) +// STATIC_METHOD_OVERLOADED: Begin completions, 2 items +// STATIC_METHOD_OVERLOADED-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// STATIC_METHOD_OVERLOADED-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: String#}[')'][#String#]; name=arg1: String +// STATIC_METHOD_OVERLOADED: End completions } func testImplicitMember() { let _: TestStaticMemberCall = .create1(#^IMPLICIT_MEMBER_AFTERPAREN_1^#) // IMPLICIT_MEMBER_AFTERPAREN_1: Begin completions, 1 items -// IMPLICIT_MEMBER_AFTERPAREN_1: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// IMPLICIT_MEMBER_AFTERPAREN_1: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int // IMPLICIT_MEMBER_AFTERPAREN_1: End completions let _: TestStaticMemberCall = .create2(#^IMPLICIT_MEMBER_AFTERPAREN_2^#) // IMPLICIT_MEMBER_AFTERPAREN_2: Begin completions -// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#(arg1): Int#}[')'][#TestStaticMemberCall#]; -// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#(arg1): Int#}, {#arg2: Int#}, {#arg3: Int#}, {#arg4: Int#}[')'][#TestStaticMemberCall#]; +// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#(arg1): Int#}[')'][#TestStaticMemberCall#]; +// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#(arg1): Int#}, {#arg2: Int#}, {#arg3: Int#}, {#arg4: Int#}[')'][#TestStaticMemberCall#]; // IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[Struct]/OtherModule[Swift]/IsSystem/TypeRelation[Identical]: Int[#Int#]; // IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Literal[Integer]/None/TypeRelation[Identical]: 0[#Int#]; // IMPLICIT_MEMBER_AFTERPAREN_2: End completions let _: TestStaticMemberCall? = .create1(#^IMPLICIT_MEMBER_AFTERPAREN_3^#) // IMPLICIT_MEMBER_AFTERPAREN_3: Begin completions, 1 items -// IMPLICIT_MEMBER_AFTERPAREN_3: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// IMPLICIT_MEMBER_AFTERPAREN_3: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int // IMPLICIT_MEMBER_AFTERPAREN_3: End completions let _: TestStaticMemberCall = .create2(1, #^IMPLICIT_MEMBER_SECOND^#) @@ -726,6 +739,12 @@ func testImplicitMember() { // IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; // IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // IMPLICIT_MEMBER_SKIPPED: End completions + + let _: TestStaticMemberCall = .createOverloaded(#^IMPLICIT_MEMBER_OVERLOADED^#) +// IMPLICIT_MEMBER_OVERLOADED: Begin completions, 2 items +// IMPLICIT_MEMBER_OVERLOADED: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// IMPLICIT_MEMBER_OVERLOADED: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: String#}[')'][#String#]; name=arg1: String +// IMPLICIT_MEMBER_OVERLOADED: End completions } func testImplicitMemberInArrayLiteral() { struct Receiver { @@ -739,8 +758,12 @@ func testImplicitMemberInArrayLiteral() { // Same as IMPLICIT_MEMBER_AFTERPAREN_1. ]) Receiver([ + .create1(x: 1), .create2(#^IMPLICIT_MEMBER_ARRAY_1_AFTERPAREN_2^#), // Same as IMPLICIT_MEMBER_AFTERPAREN_2. + ]) + Receiver([ + .create1(x: 1), .create2(1, #^IMPLICIT_MEMBER_ARRAY_1_SECOND^# // Same as IMPLICIT_MEMBER_SECOND. ]) @@ -749,15 +772,22 @@ func testImplicitMemberInArrayLiteral() { // Same as IMPLICIT_MEMBER_SKIPPED. .create1(x: 12) ]) + Receiver(arg1: 12, arg2: [ + .create1(x: 12), + .createOverloaded(#^IMPLICIT_MEMBER_ARRAY_1_OVERLOADED^#) + // Same as IMPLICIT_MEMBER_OVERLOADED. + ]) let _: [TestStaticMemberCall] = [ .create1(#^IMPLICIT_MEMBER_ARRAY_2_AFTERPAREN_1^#), - // Same as STATIC_METHOD_AFTERPAREN_1. + // Same as IMPLICIT_MEMBER_AFTERPAREN_1. .create2(#^IMPLICIT_MEMBER_ARRAY_2_AFTERPAREN_2^#), - // Same as STATIC_METHOD_AFTERPAREN_2. + // Same as IMPLICIT_MEMBER_AFTERPAREN_2. .create2(1, #^IMPLICIT_MEMBER_ARRAY_2_SECOND^#), - // Same as STATIC_METHOD_SECOND. + // Same as IMPLICIT_MEMBER_SECOND. .create2(1, arg3: 2, #^IMPLICIT_MEMBER_ARRAY_2_SKIPPED^#), - // Same as STATIC_METHOD_SKIPPED. + // Same as IMPLICIT_MEMBER_SKIPPED. + .createOverloaded(#^IMPLICIT_MEMBER_ARRAY_2_OVERLOADED^#), + // Same as IMPLICIT_MEMBER_OVERLOADED ] } @@ -833,10 +863,11 @@ func testPamrameterFlags(_: Int, inoutArg: inout Int, autoclosureArg: @autoclosu func testTupleElement(arg: (SimpleEnum, SimpleEnum)) { testTupleElement(arg: (.foo, .#^TUPLEELEM_1^#)) -// TUPLEELEM_1: Begin completions, 3 items +// TUPLEELEM_1: Begin completions, 4 items // TUPLEELEM_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: foo[#SimpleEnum#]; name=foo // TUPLEELEM_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: bar[#SimpleEnum#]; name=bar // TUPLEELEM_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: baz[#SimpleEnum#]; name=baz +// TUPLEELEM_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SimpleEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: SimpleEnum) // TUPLEELEM_1: End completions testTupleElement(arg: (.foo, .bar, .#^TUPLEELEM_2^#)) // TUPLEELEM_2-NOT: Begin completions @@ -852,10 +883,11 @@ func testKeyPathThunkInBase() { func foo(_ fn: (TestKP) -> Int) -> TestKPResult { TestKPResult() } foo(\.value).testFunc(.#^KEYPATH_THUNK_BASE^#) -// KEYPATH_THUNK_BASE: Begin completions, 3 items +// KEYPATH_THUNK_BASE: Begin completions, 4 items // KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: foo[#SimpleEnum#]; name=foo // KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: bar[#SimpleEnum#]; name=bar // KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: baz[#SimpleEnum#]; name=baz +// KEYPATH_THUNK_BASE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SimpleEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: SimpleEnum) // KEYPATH_THUNK_BASE: End completions } diff --git a/test/IDE/complete_call_as_function.swift b/test/IDE/complete_call_as_function.swift index 836b3a9a7d84e..ebd371b95312c 100644 --- a/test/IDE/complete_call_as_function.swift +++ b/test/IDE/complete_call_as_function.swift @@ -111,10 +111,12 @@ func testCallAsFunctionOverloaded(fn: Functor) { fn(h: .left, v: .#^OVERLOADED_ARG2_VALUE^#) // FIXME: Should only suggest 'up' and 'down' (rdar://problem/60346573). -//OVERLOADED_ARG2_VALUE: Begin completions, 4 items +//OVERLOADED_ARG2_VALUE: Begin completions, 6 items //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: up[#Functor.Vertical#]; //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: down[#Functor.Vertical#]; +//OVERLOADED_ARG2_VALUE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Functor.Vertical#})[#(into: inout Hasher) -> Void#]; //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: left[#Functor.Horizontal#]; //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: right[#Functor.Horizontal#]; +//OVERLOADED_ARG2_VALUE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Functor.Horizontal#})[#(into: inout Hasher) -> Void#]; //OVERLOADED_ARG2_VALUE: End completions } diff --git a/test/IDE/complete_constrained.swift b/test/IDE/complete_constrained.swift index bb85a6c711c02..cc655f4af2ea2 100644 --- a/test/IDE/complete_constrained.swift +++ b/test/IDE/complete_constrained.swift @@ -117,9 +117,11 @@ struct Vegetarian: EatsFruit, EatsVegetables { } func testVegetarian(chef: Chef) { chef.cook(.#^CONDITIONAL_OVERLOAD_ARG^#) -// CONDITIONAL_OVERLOAD_ARG: Begin completions, 2 items +// CONDITIONAL_OVERLOAD_ARG: Begin completions, 4 items // CONDITIONAL_OVERLOAD_ARG-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: apple[#Fruit#]; name=apple +// CONDITIONAL_OVERLOAD_ARG-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Fruit#})[#(into: inout Hasher) -> Void#]; name=hash(self: Fruit) // CONDITIONAL_OVERLOAD_ARG-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: broccoli[#Vegetable#]; name=broccoli +// CONDITIONAL_OVERLOAD_ARG-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Vegetable#})[#(into: inout Hasher) -> Void#]; name=hash(self: Vegetable) // CONDITIONAL_OVERLOAD_ARG: End completions var chefMeta: Chef.Type = Chef.self diff --git a/test/IDE/complete_enum_elements.swift b/test/IDE/complete_enum_elements.swift index 7f4097efb0a9c..48d8b01d8b23a 100644 --- a/test/IDE/complete_enum_elements.swift +++ b/test/IDE/complete_enum_elements.swift @@ -138,10 +138,20 @@ enum FooEnum: CaseIterable { // FOO_ENUM_DOT_INVALID-NEXT: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]{{; name=.+$}} // FOO_ENUM_DOT_INVALID-NEXT: End completions -// FOO_ENUM_DOT_ELEMENTS: Begin completions, 3 items +// FOO_ENUM_DOT_ELEMENTS: Begin completions, 13 items // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Foo1[#FooEnum#]{{; name=.+$}} // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Foo2[#FooEnum#]{{; name=.+$}} // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: alias1[#FooEnum#]; name=alias1 +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): FooEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: FooEnum) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#arrayLiteral: FooEnum...#})[#Array#]; name=AllCases(arrayLiteral: FooEnum...) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases()[#Array#]; name=AllCases() +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#(s): Sequence#})[#Array#]; name=AllCases(s: Sequence) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#repeating: FooEnum#}, {#count: Int#})[#Array#]; name=AllCases(repeating: FooEnum, count: Int) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#unsafeUninitializedCapacity: Int#}, {#initializingWith: (inout UnsafeMutableBufferPointer, inout Int) throws -> Void##(inout UnsafeMutableBufferPointer, inout Int) throws -> Void#})[' rethrows'][#Array#]; name=AllCases(unsafeUninitializedCapacity: Int, initializingWith: (inout UnsafeMutableBufferPointer, inout Int) throws -> Void) rethrows +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#from: Decoder#})[' throws'][#Array#]; name=AllCases(from: Decoder) throws +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#repeating: FooEnum#}, {#count: Int#})[#FooEnum.AllCases#]; name=AllCases(repeating: FooEnum, count: Int) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#(elements): Sequence#})[#FooEnum.AllCases#]; name=AllCases(elements: Sequence) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]; name=allCases // FOO_ENUM_DOT_ELEMENTS-NEXT: End completions enum BarEnum { @@ -454,9 +464,12 @@ func testWithInvalid1() { func testUnqualified1(x: QuxEnum) { _ = x == .Qux1 || x == .#^UNRESOLVED_2^#Qux2 - // UNRESOLVED_2: Begin completions, 2 items + // UNRESOLVED_2: Begin completions // UNRESOLVED_2-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Qux1[#QuxEnum#]; name=Qux1 // UNRESOLVED_2-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Qux2[#QuxEnum#]; name=Qux2 + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#bitPattern: UInt#})[#Int#]; name=RawValue(bitPattern: UInt) + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal: init({#rawValue: Int#})[#QuxEnum?#]; name=init(rawValue: Int) + // UNRESOLVED_2-DAG: Decl[InstanceMethod]/Super/IsSystem/TypeRelation[Invalid]: hash({#(self): QuxEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: QuxEnum) // UNRESOLVED_2: End completions _ = (x == .Qux1#^UNRESOLVED_3^#) diff --git a/test/IDE/complete_exception.swift b/test/IDE/complete_exception.swift index 48d222ced7565..a5cef6bb5175b 100644 --- a/test/IDE/complete_exception.swift +++ b/test/IDE/complete_exception.swift @@ -5,11 +5,13 @@ // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=CATCH2 | %FileCheck %s -check-prefix=CATCH2 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=THROW2 | %FileCheck %s -check-prefix=THROW2 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=CATCH3 | %FileCheck %s -check-prefix=CATCH3 +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=THROW3 | %FileCheck %s -check-prefix=THROW3 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_CATCH1 | %FileCheck %s -check-prefix=CATCH1 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW1 | %FileCheck %s -check-prefix=THROW1 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_CATCH2 | %FileCheck %s -check-prefix=CATCH2 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW2 | %FileCheck %s -check-prefix=THROW2 +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW3 | %FileCheck %s -check-prefix=THROW3 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH1 > %t.inside_catch1 // RUN: %FileCheck %s -check-prefix=STMT < %t.inside_catch1 @@ -70,10 +72,10 @@ func test001() { do {} catch #^CATCH1^# // CATCH1: Begin completions -// CATCH1-DAG: Decl[Enum]/CurrModule: Error4[#Error4#]; name=Error4{{$}} -// CATCH1-DAG: Decl[Class]/CurrModule: Error3[#Error3#]; name=Error3{{$}} -// CATCH1-DAG: Decl[Class]/CurrModule: Error2[#Error2#]; name=Error2{{$}} -// CATCH1-DAG: Decl[Class]/CurrModule: Error1[#Error1#]; name=Error1{{$}} +// CATCH1-DAG: Decl[Enum]/CurrModule/TypeRelation[Convertible]: Error4[#Error4#]; name=Error4{{$}} +// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error3[#Error3#]; name=Error3{{$}} +// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error2[#Error2#]; name=Error2{{$}} +// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error1[#Error1#]; name=Error1{{$}} // CATCH1-DAG: Keyword[let]/None: let{{; name=.+$}} // CATCH1-DAG: Decl[Class]/CurrModule: NoneError1[#NoneError1#]; name=NoneError1{{$}} // CATCH1-DAG: Decl[Class]/OtherModule[Foundation]/IsSystem: NSError[#NSError#]{{; name=.+$}} @@ -126,11 +128,20 @@ func test005() { // CATCH3: End completions } +func testInvalid() { + try throw Error4.#^THROW3^# +// THROW3: Begin completions +// THROW3: Decl[EnumElement]/CurrNominal: E1[#Error4#]{{; name=.+$}} +// THROW3: Decl[EnumElement]/CurrNominal: E2({#Int32#})[#Error4#]{{; name=.+$}} +// THROW3: End completions +} + //===--- Top-level throw/catch do {} catch #^TOP_LEVEL_CATCH1^# {} throw #^TOP_LEVEL_THROW1^# do {} catch Error4.#^TOP_LEVEL_CATCH2^# {} throw Error4.#^TOP_LEVEL_THROW2^# +try throw Error4.#^TOP_LEVEL_THROW3^# //===--- Inside catch body diff --git a/test/IDE/complete_in_ifconfig.swift b/test/IDE/complete_in_ifconfig.swift new file mode 100644 index 0000000000000..56b8bcfe46b6b --- /dev/null +++ b/test/IDE/complete_in_ifconfig.swift @@ -0,0 +1,75 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t + +struct MyStruct { + init() {} + var value: Int +} + +// MEMBER_MyStruct: Begin completions, 2 items +// MEMBER_MyStruct-DAG: Keyword[self]/CurrNominal: self[#MyStruct#]; +// MEMBER_MyStruct-DAG: Decl[InstanceVar]/CurrNominal: value[#Int#]; +// MEMBER_MyStruct: End completions + +#if true +let toplevelActive = MyStruct() +_ = toplevelActive.#^MEMBER_TOPLEVEL_ACTIVE?check=MEMBER_MyStruct^# +#else +let toplevelInactive = MyStruct() +_ = toplevelInactive.#^MEMBER_TOPLEVEL_INACTIVE?check=MEMBER_MyStruct^# +#endif + +func foo() { +#if true + let infuncActive = MyStruct() + _ = infuncActive.#^MEMBER_INFUNC_ACTIVE?check=MEMBER_MyStruct^# +#else + let infuncInactive = MyStruct() + _ = infuncInactive.#^MEMBER_INFUNC_INACTIVE?check=MEMBER_MyStruct^# +#endif +} + +protocol TestP { + func foo() + func bar() +} +struct TestStruct: TestP { +#if true + func foo() {} + func #^OVERRIDE_ACTIVE^# +// OVERRIDE_ACTIVE: Begin completions, 1 items +// OVERRIDE_ACTIVE-DAG: Decl[InstanceMethod]/Super: bar() {|}; +// OVERRIDE_ACTIVE: End completions +#else + func bar() {} + func #^OVERRIDE_INACTIVE^# +// OVERRIDE_INACTIVE: Begin completions, 1 items +// OVERRIDE_INACTIVE-DAG: Decl[InstanceMethod]/Super: foo() {|}; +// OVERRIDE_INACTIVE: End completions +#endif +} + +struct TestStruct2 { +#if true + func activeFunc() {} + func test() { + self.#^SELF_ACTIVE^# + } +// SELF_ACTIVE: Begin completions, 3 items +// SELF_ACTIVE-DAG: Keyword[self]/CurrNominal: self[#TestStruct2#]; +// SELF_ACTIVE-DAG: Decl[InstanceMethod]/CurrNominal: activeFunc()[#Void#]; +// SELF_ACTIVE-DAG: Decl[InstanceMethod]/CurrNominal: test()[#Void#]; +// SELF_ACTIVE: End completions +#else + func inactiveFunc() {} + func test() { + self.#^SELF_INACTIVE^# + } +// SELF_INACTIVE: Begin completions, 3 items +// SELF_INACTIVE-DAG: Keyword[self]/CurrNominal: self[#TestStruct2#]; +// SELF_INACTIVE-DAG: Decl[InstanceMethod]/CurrNominal: inactiveFunc()[#Void#]; +// SELF_INACTIVE-DAG: Decl[InstanceMethod]/CurrNominal: test()[#Void#]; +// SELF_INACTIVE: End completions +#endif +} + diff --git a/test/IDE/complete_property_delegate_attribute.swift b/test/IDE/complete_property_delegate_attribute.swift index 5cf00f41e1b1b..ba1de7930993d 100644 --- a/test/IDE/complete_property_delegate_attribute.swift +++ b/test/IDE/complete_property_delegate_attribute.swift @@ -34,9 +34,10 @@ struct TestStruct { @MyStruct(arg1: .#^ARG_MyEnum_DOT^# var test3 -// ARG_MyEnum_DOT: Begin completions, 2 items +// ARG_MyEnum_DOT: Begin completions, 3 items // ARG_MyEnum_DOT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: east[#MyEnum#]; name=east // ARG_MyEnum_DOT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: west[#MyEnum#]; name=west +// ARG_MyEnum_DOT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MyEnum#})[#(into: inout Hasher) -> Void#]; // ARG_MyEnum_DOT: End completions @MyStruct(arg1: MyEnum.#^ARG_MyEnum_NOBINDING^#) diff --git a/test/IDE/complete_rdar67155695.swift b/test/IDE/complete_rdar67155695.swift new file mode 100644 index 0000000000000..9682653b1f662 --- /dev/null +++ b/test/IDE/complete_rdar67155695.swift @@ -0,0 +1,111 @@ +// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token=PUBLIC | %FileCheck %s --check-prefix=PUBLIC +// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token=INTERNAL | %FileCheck %s --check-prefix=INTERNAL +// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token=PRIVATE | %FileCheck %s --check-prefix=PRIVATE + +public protocol PubP {} + +public extension PubP { + func availableP_availableC() {} + + func availableP_unavailableC() {} + + @available(*, unavailable) + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +struct TestForPubP: PubP { + func availableP_availableC() {} + + @available(*, unavailable) + func availableP_unavailableC() {} + + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +func test(val: TestForPubP) { + val.#^PUBLIC^# +// PUBLIC: Begin completions, 4 items +// PUBLIC-DAG: Keyword[self]/CurrNominal: self[#TestForPubP#]; +// PUBLIC-DAG: Decl[InstanceMethod]/CurrNominal: unavailableP_availableC()[#Void#]; +// PUBLIC-DAG: Decl[InstanceMethod]/Super: availableP_availableC()[#Void#]; +// PUBLIC-DAG: Decl[InstanceMethod]/Super: availableP_unavailableC()[#Void#]; +// PUBLIC: End completions +} + +protocol InternalP {} + +extension InternalP { + func availableP_availableC() {} + + func availableP_unavailableC() {} + + @available(*, unavailable) + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +struct TestForInternalP: InternalP { + func availableP_availableC() {} + + @available(*, unavailable) + func availableP_unavailableC() {} + + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +func test(val: TestForInternalP) { + val.#^INTERNAL^# +// INTERNAL: Begin completions, 4 items +// INTERNAL-DAG: Keyword[self]/CurrNominal: self[#TestForInternalP#]; +// INTERNAL-DAG: Decl[InstanceMethod]/CurrNominal: availableP_availableC()[#Void#]; +// INTERNAL-DAG: Decl[InstanceMethod]/CurrNominal: unavailableP_availableC()[#Void#]; +// INTERNAL-DAG: Decl[InstanceMethod]/Super: availableP_unavailableC()[#Void#]; +// INTERNAL: End completions +} + +private protocol PrivP {} + +private extension PrivP { + func availableP_availableC() {} + + func availableP_unavailableC() {} + + @available(*, unavailable) + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +struct TestForPrivP: PrivP { + func availableP_availableC() {} + + @available(*, unavailable) + func availableP_unavailableC() {} + + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +func test(val: TestForPrivP) { + val.#^PRIVATE^# +// PRIVATE: Begin completions, 4 items +// PRIVATE-DAG: Keyword[self]/CurrNominal: self[#TestForPrivP#]; +// PRIVATE-DAG: Decl[InstanceMethod]/CurrNominal: availableP_availableC()[#Void#]; +// PRIVATE-DAG: Decl[InstanceMethod]/CurrNominal: unavailableP_availableC()[#Void#]; +// PRIVATE-DAG: Decl[InstanceMethod]/Super: availableP_unavailableC()[#Void#]; +// PRIVATE-DAG: End completions +} diff --git a/test/IDE/complete_stmt_controlling_expr.swift b/test/IDE/complete_stmt_controlling_expr.swift index b76a9bfad2f14..ccbabf4c8395f 100644 --- a/test/IDE/complete_stmt_controlling_expr.swift +++ b/test/IDE/complete_stmt_controlling_expr.swift @@ -644,11 +644,17 @@ func testGuardCase(x:FooStruct?) { // FOOSTRUCT_LOCALVAL-DAG: Decl[LocalVar]/Local{{(/TypeRelation\[Convertible\])?}}: boundVal[#FooStruct#]; // FOOSTRUCT_LOCALVAL: End completions -// OPTIONAL_FOOSTRUCT: Begin completions, 5 items +// OPTIONAL_FOOSTRUCT: Begin completions, 9 items // OPTIONAL_FOOSTRUCT-DAG: Keyword[nil]/None/Erase[1]: nil[#FooStruct?#]; name=nil // OPTIONAL_FOOSTRUCT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // OPTIONAL_FOOSTRUCT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#FooStruct#})[#Optional#]; name=some(FooStruct) // FIXME: 'FooStruct' members should not be shown. // OPTIONAL_FOOSTRUCT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init()[#FooStruct#]; name=init() // OPTIONAL_FOOSTRUCT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init({#Int#})[#FooStruct#]; name=init(Int) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal: boolGen({#(self): FooStruct#})[#() -> Bool#]; name=boolGen(self: FooStruct) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal: intGen({#(self): FooStruct#})[#() -> Int#]; name=intGen(self: FooStruct) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((FooStruct) throws -> U) -> U?#]; name=map(self: Optional) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((FooStruct) throws -> U?) -> U?#]; name=flatMap(self: Optional) +// OPTIONAL_FOOSTRUCT-NOT: init({#(some): +// OPTIONAL_FOOSTRUCT-NOT: init({#nilLiteral: // OPTIONAL_FOOSTRUCT: End completions diff --git a/test/IDE/complete_string_interpolation.swift b/test/IDE/complete_string_interpolation.swift index 4187ca51cf480..1089516beb5f1 100644 --- a/test/IDE/complete_string_interpolation.swift +++ b/test/IDE/complete_string_interpolation.swift @@ -31,17 +31,19 @@ struct MsgInterpolation: StringInterpolationProtocol { var messenger = Messenger() func testMessenger(intVal: Int, fltVal: Float) { messenger.send(" \(intVal, format: .#^OVERLOAD_INT^#) ") -// OVERLOAD_INT: Begin completions, 4 items +// OVERLOAD_INT: Begin completions, 5 items // OVERLOAD_INT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: decimal[#MsgInterpolation.IntFormat#]; // OVERLOAD_INT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: hex[#MsgInterpolation.IntFormat#]; +// OVERLOAD_INT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MsgInterpolation.IntFormat#})[#(into: inout Hasher) -> Void#]; // OVERLOAD_INT-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: precision({#Int#})[#MsgInterpolation.FloatFormat#]; // OVERLOAD_INT-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: hex[#MsgInterpolation.FloatFormat#]; // OVERLOAD_INT: End completions messenger.send(" \(fltVal, format: .#^OVERLOAD_FLT^#) ") -// OVERLOAD_FLT: Begin completions, 4 items +// OVERLOAD_FLT: Begin completions, 5 items // OVERLOAD_FLT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: decimal[#MsgInterpolation.IntFormat#]; // OVERLOAD_FLT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: hex[#MsgInterpolation.IntFormat#]; +// OVERLOAD_FLT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MsgInterpolation.IntFormat#})[#(into: inout Hasher) -> Void#]; // OVERLOAD_FLT-DAG: Decl[StaticMethod]/ExprSpecific/TypeRelation[Identical]: precision({#Int#})[#MsgInterpolation.FloatFormat#]; // OVERLOAD_FLT-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: hex[#MsgInterpolation.FloatFormat#]; // OVERLOAD_FLT: End completions diff --git a/test/IDE/complete_swift_key_path_optional_root.swift b/test/IDE/complete_swift_key_path_optional_root.swift new file mode 100644 index 0000000000000..c80822c601c4f --- /dev/null +++ b/test/IDE/complete_swift_key_path_optional_root.swift @@ -0,0 +1,55 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE_INFER_DOT_OPTIONAL | %FileCheck %s -check-prefix=PERSONTYPE-INFER-DOT-OPT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE_DOT_OPTIONAL | %FileCheck %s -check-prefix=PERSONTYPE-DOT-OPT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE_DOT_OPTIONAL_SPACE | %FileCheck %s -check-prefix=PERSONTYPE-DOT-OPT-SPACE + +class Person { + var name: String + var friends: [Person] = [] + var bestFriend: Person? = nil + var itself: Person { return self } + init(name: String) { + self.name = name + } + func getName() -> String { return name } + subscript(_ index: Int) -> Int { get { return 1} } +} + +extension Optional { + var optMember: String { "member" } +} + +let _ : KeyPath = \.#^TYPE_INFER_DOT_OPTIONAL^# +// PERSONTYPE-INFER-DOT-OPT: Begin completions, 9 items +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.name[#String#]; name=name +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.friends[#[Person]#]; name=friends +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.bestFriend[#Person?#]; name=bestFriend +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.itself[#Person#]; name=itself +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[Subscript]/CurrNominal: ?[{#(index): Int#}][#Int#]; name=[index: Int] +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: unsafelyUnwrapped[#Person#]; name=unsafelyUnwrapped +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: optMember[#String#]; name=optMember +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: debugDescription[#String#]; name=debugDescription +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: customMirror[#Mirror#]; name=customMirror + +let _ : KeyPath = \Person?.#^TYPE_DOT_OPTIONAL^# +// PERSONTYPE-DOT-OPT: Begin completions, 9 items +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.name[#String#]; name=name +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.friends[#[Person]#]; name=friends +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.bestFriend[#Person?#]; name=bestFriend +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.itself[#Person#]; name=itself +// PERSONTYPE-DOT-OPT-NEXT: Decl[Subscript]/CurrNominal: ?[{#(index): Int#}][#Int#]; name=[index: Int] +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: unsafelyUnwrapped[#Person#]; name=unsafelyUnwrapped +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: optMember[#String#]; name=optMember +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: debugDescription[#String#]; name=debugDescription +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: customMirror[#Mirror#]; name=customMirror + +let _ : KeyPath = \Person?. #^TYPE_DOT_OPTIONAL_SPACE^# +// PERSONTYPE-DOT-OPT-SPACE: Begin completions, 9 items +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.name[#String#]; name=name +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.friends[#[Person]#]; name=friends +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.bestFriend[#Person?#]; name=bestFriend +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.itself[#Person#]; name=itself +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[Subscript]/CurrNominal/Erase[1]: ?[{#(index): Int#}][#Int#]; name=[index: Int] +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: unsafelyUnwrapped[#Person#]; name=unsafelyUnwrapped +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal: optMember[#String#]; name=optMember +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: debugDescription[#String#]; name=debugDescription +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: customMirror[#Mirror#]; name=customMirror diff --git a/test/IDE/complete_type.swift b/test/IDE/complete_type.swift index 04b9158fda578..4178ff2840b04 100644 --- a/test/IDE/complete_type.swift +++ b/test/IDE/complete_type.swift @@ -765,3 +765,17 @@ func testUnbound2(x: OuterStruct.Inner.#^UNBOUND_DOT_3^#) {} // UNBOUND_DOT_3: Begin completions // UNBOUND_DOT_3-DAG: Keyword/None: Type[#OuterStruct.Inner.Type#]; name=Type // UNBOUND_DOT_3: End completions + +// rdar://problem/67102794 +struct HasProtoAlias { + typealias ProtoAlias = FooProtocol +} +extension FooStruct: HasProtoAlias.#^EXTENSION_INHERITANCE_1?check=EXTENSION_INHERITANCE^# {} + +struct ContainExtension { + extension FooStruct: HasProtoAlias.#^EXTENSION_INHERITANCE_2?check=EXTENSION_INHERITANCE^# {} +} +// EXTENSION_INHERITANCE: Begin completions, 2 items +// EXTENSION_INHERITANCE-DAG: Decl[TypeAlias]/CurrNominal: ProtoAlias[#FooProtocol#]; +// EXTENSION_INHERITANCE-DAG: Keyword/None: Type[#HasProtoAlias.Type#]; +// EXTENSION_INHERITANCE: End completions diff --git a/test/IDE/complete_unresolved_chains.swift b/test/IDE/complete_unresolved_chains.swift new file mode 100644 index 0000000000000..f1d2930ce7e17 --- /dev/null +++ b/test/IDE/complete_unresolved_chains.swift @@ -0,0 +1,85 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_1 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_2 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_3 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_4 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_5 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_2 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_6 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_7 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DOUBLY_NESTED| %FileCheck %s -check-prefix=DOUBLY_NESTED + +struct ChainStruct1 { + static var chain2 = ChainStruct2() + static func chain2Func() -> ChainStruct2 { ChainStruct2() } +} + +struct ChainStruct2 { + var chainStruct1 = ChainStruct1() + var chainEnum = ChainEnum.case1 + var chainStruct2: ChainStruct2 { ChainStruct2() } + func chainStruct1Func() -> ChainStruct1 { ChainStruct1() } +} + +enum ChainEnum { + case case1 + var chainStruct2: ChainStruct2 { ChainStruct2() } + func chainStruct2Func() -> ChainStruct2 { ChainStruct2() } +} + +func testChains() { + let _: ChainStruct1 = .chain2.#^UNRESOLVED_CHAIN_1^# + let _: ChainStruct1 = .chain2.chainStruct2.#^UNRESOLVED_CHAIN_2^# + let _: ChainStruct1 = .chain2Func().#^UNRESOLVED_CHAIN_3^# + let _: ChainStruct1 = .chain2Func().#^UNRESOLVED_CHAIN_4^# + let _: ChainEnum = .case1.#^UNRESOLVED_CHAIN_5^# + let _: ChainEnum = .case1.chainStruct2.#^UNRESOLVED_CHAIN_6^# + let _: ChainEnum = .case1.chainStruct2.#^UNRESOLVED_CHAIN_7^# +} + +// UNRESOLVED_CHAIN_1: Begin completions, 5 items +// UNRESOLVED_CHAIN_1-DAG: Keyword[self]/CurrNominal: self[#ChainStruct2#]; name=self +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: chainStruct1[#ChainStruct1#]; +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal: chainEnum[#ChainEnum#]; +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: chainStruct1Func()[#ChainStruct1#]; +// UNRESOLVED_CHAIN_1: End completions + +// UNRESOLVED_CHAIN_2: Begin completions, 5 items +// UNRESOLVED_CHAIN_2-DAG: Keyword[self]/CurrNominal: self[#ChainEnum#]; name=self +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; name=chainStruct2 +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceMethod]/CurrNominal: chainStruct2Func()[#ChainStruct2#]; name=chainStruct2Func() +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceVar]/CurrNominal: hashValue[#Int#]; name=hashValue +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#into: &Hasher#})[#Void#]; name=hash(into: &Hasher) +// UNRESOLVED_CHAIN_2: End completions + +// UNRESOLVED_CHAIN_3: Begin completions, 5 items +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceVar]/CurrNominal: chainStruct1[#ChainStruct1#]; name=chainStruct1 +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: chainEnum[#ChainEnum#]; name=chainEnum +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; name=chainStruct2 +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceMethod]/CurrNominal: chainStruct1Func()[#ChainStruct1#]; name=chainStruct1Func() +// UNRESOLVED_CHAIN_3: End completions + +class Outer { + class Inner: Outer { + class InnerInner: Inner {} + static var outer = Outer() + static var inner = Inner() + static func makeOuter() -> Outer { Outer() } + static func makeInner() -> Inner { Inner() } + } +} + +func testDoublyNestedType() { + let _: Outer = .Inner.#^DOUBLY_NESTED^# +} + +// DOUBLY_NESTED: Begin completions, 8 items +// DOUBLY_NESTED-DAG: Keyword[self]/CurrNominal: self[#Outer.Inner.Type#]; name=self +// DOUBLY_NESTED-DAG: Decl[Class]/CurrNominal/TypeRelation[Convertible]: InnerInner[#Outer.Inner.InnerInner#]; +// DOUBLY_NESTED-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: outer[#Outer#]; +// DOUBLY_NESTED-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Convertible]: inner[#Outer.Inner#]; +// DOUBLY_NESTED-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: makeOuter()[#Outer#]; +// DOUBLY_NESTED-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: makeInner()[#Outer.Inner#]; +// DOUBLY_NESTED-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init()[#Outer.Inner#]; +// DOUBLY_NESTED-DAG: Decl[Class]/Super/TypeRelation[Convertible]: Inner[#Outer.Inner#]; +// DOUBLY_NESTED: End completions + diff --git a/test/IDE/complete_unresolved_members.swift b/test/IDE/complete_unresolved_members.swift index 7a895c550c665..53d20a8a07d36 100644 --- a/test/IDE/complete_unresolved_members.swift +++ b/test/IDE/complete_unresolved_members.swift @@ -109,9 +109,9 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GENERICPARAM_21 | %FileCheck %s -check-prefix=GENERICPARAM_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DECL_MEMBER_INIT_1 | %FileCheck %s -check-prefix=UNRESOLVED_3 -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_1 | %FileCheck %s -check-prefix=UNRESOLVED_3_NOTIDEAL -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_2 | %FileCheck %s -check-prefix=UNRESOLVED_3_NOTIDEAL -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_3 | %FileCheck %s -check-prefix=UNRESOLVED_3_NOTIDEAL +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_1 | %FileCheck %s -check-prefix=UNRESOLVED_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_2 | %FileCheck %s -check-prefix=UNRESOLVED_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_3 | %FileCheck %s -check-prefix=UNRESOLVED_3 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPEPARAM_IN_CONTEXTTYPE_1 | %FileCheck %s -check-prefix=TYPEPARAM_IN_CONTEXTTYPE_1 @@ -226,7 +226,8 @@ class C2 { // UNRESOLVED_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: Option1[#SomeOptions1#]; name=Option1 // UNRESOLVED_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: Option2[#SomeOptions1#]; name=Option2 // UNRESOLVED_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: Option3[#SomeOptions1#]; name=Option3 -// UNRESOLVED_1-NOT: Not +// UNRESOLVED_1-DAG: Decl[StaticVar]/CurrNominal: NotOption[#Int#]; name=NotOption +// UNRESOLVED_1-NOT: NotStaticOption // UNRESOLVED_1_NOTIDEAL: Begin completions // UNRESOLVED_1_NOTIDEAL-NOT: SomeEnum1 @@ -234,7 +235,8 @@ class C2 { // UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: Option1[#SomeOptions1#]; name=Option1 // UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: Option2[#SomeOptions1#]; name=Option2 // UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: Option3[#SomeOptions1#]; name=Option3 -// UNRESOLVED_1_NOTIDEAL-NOT: Not +// UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal: NotOption[#Int#]; name=NotOption +// UNRESOLVED_1_NOTIDEAL-NOT: NotStaticOption } class C3 { @@ -274,39 +276,49 @@ class C4 { var _: SomeEnum1??? = .#^UNRESOLVED_OPT_3^# } } -// UNRESOLVED_3: Begin completions, 2 items +// UNRESOLVED_3: Begin completions, 3 items // UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: North[#SomeEnum1#]; name=North // UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: South[#SomeEnum1#]; name=South +// UNRESOLVED_3-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; name=hash(self: SomeEnum1) // UNRESOLVED_3-NOT: SomeOptions1 // UNRESOLVED_3-NOT: SomeOptions2 // UNRESOLVED_3-NOT: none // UNRESOLVED_3-NOT: some( -// UNRESOLVED_3_NOTIDEAL: Begin completions, 2 items +// UNRESOLVED_3_NOTIDEAL: Begin completions, 3 items // UNRESOLVED_3_NOTIDEAL-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: North[#SomeEnum1#]; name=North // UNRESOLVED_3_NOTIDEAL-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: South[#SomeEnum1#]; name=South +// UNRESOLVED_3_NOTIDEAL-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; name=hash(self: SomeEnum1) // UNRESOLVED_3_NOTIDEAL-NOT: SomeOptions1 // UNRESOLVED_3_NOTIDEAL-NOT: SomeOptions2 // UNRESOLVED_3_NOTIDEAL-NOT: none // UNRESOLVED_3_NOTIDEAL-NOT: some( -// UNRESOLVED_3_OPT: Begin completions, 5 items +// UNRESOLVED_3_OPT: Begin completions, 9 items // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: North[#SomeEnum1#]; // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: South[#SomeEnum1#]; +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_3_OPT-DAG: Keyword[nil]/None/Erase[1]: nil[#SomeEnum1?#]; name=nil // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#SomeEnum1#})[#Optional#]; +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((SomeEnum1) throws -> U) -> U?#]; +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((SomeEnum1) throws -> U?) -> U?#]; // UNRESOLVED_3_OPT-NOT: init({#(some): // UNRESOLVED_3_OPT-NOT: init({#nilLiteral: +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: hash({#(self): Optional#})[#(into: inout Hasher) -> Void#]; -// UNRESOLVED_3_OPTOPTOPT: Begin completions, 5 items +// UNRESOLVED_3_OPTOPTOPT: Begin completions, 9 items // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: North[#SomeEnum1#]; // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: South[#SomeEnum1#]; +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_3_OPTOPTOPT-DAG: Keyword[nil]/None/Erase[1]: nil[#SomeEnum1???#]; name=nil // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#SomeEnum1??#})[#Optional#]; +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((SomeEnum1??) throws -> U) -> U?#]; +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((SomeEnum1??) throws -> U?) -> U?#]; // UNRESOLVED_3_OPTOPTOPT-NOT: init({#(some): // UNRESOLVED_3_OPTOPTOPT-NOT: init({#nilLiteral: +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: hash({#(self): Optional#})[#(into: inout Hasher) -> Void#]; enum Somewhere { case earth, mars @@ -317,14 +329,18 @@ extension Optional where Wrapped == Somewhere { } func testOptionalWithCustomExtension() { var _: Somewhere? = .#^UNRESOLVED_OPT_4^# -// UNRESOLVED_OPT_4: Begin completions, 7 items +// UNRESOLVED_OPT_4: Begin completions, 11 items // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: earth[#Somewhere#]; // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: mars[#Somewhere#]; +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Somewhere#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_OPT_4-DAG: Keyword[nil]/None/Erase[1]: nil[#Somewhere?#]; name=nil // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#Somewhere#})[#Optional#]; // UNRESOLVED_OPT_4-DAG: Decl[Constructor]/CurrNominal: init({#str: String#})[#Optional#]; name=init(str: String) // UNRESOLVED_OPT_4-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: nowhere[#Optional#]; name=nowhere +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((Somewhere) throws -> U) -> U?#]; +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((Somewhere) throws -> U?) -> U?#]; +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: hash({#(self): Optional#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_OPT_4-NOT: init({#(some): // UNRESOLVED_OPT_4-NOT: init({#nilLiteral: // UNRESOLVED_OPT_4: End completions @@ -433,10 +449,11 @@ let _: [SomeEnum3:SomeEnum1] = [.Payload(.South):.South, .Payload(.#^UNRESOLVED_ func testAvail1(_ x: EnumAvail1) { testAvail1(.#^ENUM_AVAIL_1^#) } -// ENUM_AVAIL_1: Begin completions, 2 items +// ENUM_AVAIL_1: Begin completions, 3 items // ENUM_AVAIL_1-NOT: AAA // ENUM_AVAIL_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: aaa[#EnumAvail1#]; // ENUM_AVAIL_1-DAG: Decl[EnumElement]/ExprSpecific/NotRecommended/TypeRelation[Identical]: BBB[#EnumAvail1#]; +// ENUM_AVAIL_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): EnumAvail1#})[#(into: inout Hasher) -> Void#]; // ENUM_AVAIL_1-NOT: AAA // ENUM_AVAIL_1: End completions @@ -444,11 +461,11 @@ func testAvail2(_ x: OptionsAvail1) { testAvail2(.#^OPTIONS_AVAIL_1^#) } // OPTIONS_AVAIL_1: Begin completions -// ENUM_AVAIL_1-NOT: AAA +// OPTIONS_AVAIL_1-NOT: AAA // OPTIONS_AVAIL_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: aaa[#OptionsAvail1#]; // OPTIONS_AVAIL_1-DAG: Decl[StaticVar]/ExprSpecific/NotRecommended/TypeRelation[Identical]: BBB[#OptionsAvail1#]; // OPTIONS_AVAIL_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init({#rawValue: Int#})[#OptionsAvail1#] -// ENUM_AVAIL_1-NOT: AAA +// OPTIONS_AVAIL_1-NOT: AAA // OPTIONS_AVAIL_1: End completions func testWithLiteral1() { @@ -460,8 +477,9 @@ func testWithLiteral1() { } let s: S _ = s.takeEnum(thing: .#^WITH_LITERAL_1^#, other: 1.0) -// WITH_LITERAL_1: Begin completions, 1 items +// WITH_LITERAL_1: Begin completions, 2 items // WITH_LITERAL_1-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: myCase[#S.MyEnum#]; +// WITH_LITERAL_1-NEXT: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): S.MyEnum#})[#(into: inout Hasher) -> Void#]; // WITH_LITERAL_1-NEXT: End completions } func testWithLiteral2() { @@ -484,8 +502,9 @@ func testWithLiteral3() { func takeEnum(thing: MyEnum, other: Double) {} func test(s: S) { _ = s.takeEnum(thing: .#^WITH_LITERAL_3^#, other: 1.0) -// WITH_LITERAL_3: Begin completions, 1 items +// WITH_LITERAL_3: Begin completions, 2 items // WITH_LITERAL_3-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: myCase[#MyEnum#]; +// WITH_LITERAL_3-NEXT: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MyEnum#})[#(into: inout Hasher) -> Void#]; // WITH_LITERAL_3-NEXT: End completions } } @@ -521,11 +540,13 @@ func testNonOptSet() { let x: NonOptSet x = .#^NON_OPT_SET_1^# } -// NON_OPT_SET_1: Begin completions, 4 items +// NON_OPT_SET_1: Begin completions, 6 items // NON_OPT_SET_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: a[#NonOptSet#] +// NON_OPT_SET_1-DAG: Decl[StaticVar]/CurrNominal: wrongType[#Int#]; // NON_OPT_SET_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init({#x: Int#}, {#y: Int#})[#NonOptSet#] // NON_OPT_SET_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init()[#NonOptSet#] // NON_OPT_SET_1-DAG: Decl[StaticMethod]/ExprSpecific/TypeRelation[Identical]: b()[#NonOptSet#] +// NON_OPT_SET_1-DAG: Decl[InstanceMethod]/ExprSpecific/TypeRelation[Identical]: notStatic({#(self): NonOptSet#})[#() -> NonOptSet#]; // NON_OPT_SET_1: End completions func testNonOptSet() { @@ -562,12 +583,12 @@ struct AnotherTy: MyProtocol {} func testSubType() { var _: BaseClass = .#^SUBTYPE_1^# } -// SUBTYPE_1: Begin completions, 3 items -// SUBTYPE_1-NOT: init(failable: +// SUBTYPE_1: Begin completions, 4 items // SUBTYPE_1-NOT: Concrete1( // SUBTYPE_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init()[#BaseClass#]; // SUBTYPE_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: SubClass()[#BaseClass.SubClass#]; // SUBTYPE_1-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Convertible]: subInstance[#BaseClass.SubClass#]; +// SUBTYPE_1-DAG: Decl[Constructor]/CurrNominal: init({#failable: Void#})[#BaseClass?#]; // SUBTYPE_1: End completions func testMemberTypealias() { @@ -618,11 +639,11 @@ struct HasCreator { func testHasStaticClosure() { let _: HasCreator = .#^STATIC_CLOSURE_1^# } -// STATIC_CLOSURE_1: Begin completions, 2 items +// STATIC_CLOSURE_1: Begin completions, 3 items // STATIC_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init()[#HasCreator#]; // FIXME: Suggest 'create()[#HasCreateor#]', not 'create'. // STATIC_CLOSURE_1-DAG: Decl[StaticVar]/CurrNominal: create[#() -> HasCreator#]; -// STATIC_CLOSURE_1-NOT: create_curried +// STATIC_CLOSURE_1-DAG: Decl[StaticVar]/CurrNominal: create_curried[#() -> () -> HasCreator#]; // STATIC_CLOSURE_1: End completions struct HasOverloaded { @@ -633,11 +654,13 @@ struct HasOverloaded { } func testOverload(val: HasOverloaded) { let _ = val.takeEnum(.#^OVERLOADED_METHOD_1^#) -// OVERLOADED_METHOD_1: Begin completions, 4 items +// OVERLOADED_METHOD_1: Begin completions, 6 items // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: South[#SomeEnum1#]; name=South // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: North[#SomeEnum1#]; name=North +// OVERLOADED_METHOD_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: East[#SomeEnum2#]; name=East // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: West[#SomeEnum2#]; name=West +// OVERLOADED_METHOD_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum2#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_METHOD_1: End completions let _ = HasOverloaded.init(e: .#^OVERLOADED_INIT_1^#) @@ -761,10 +784,10 @@ extension MyStruct where T: OtherProtocol { func receiveMyStructOfMyProtocol(value: MyStruct) {} func testTypeParamInContextType() { receiveMyStructOfMyProtocol(value: .#^TYPEPARAM_IN_CONTEXTTYPE_1^#) -// TYPEPARAM_IN_CONTEXTTYPE_1: Begin completions, 2 items -// TYPEPARAM_IN_CONTEXTTYPE_1-NOT: otherProtocolOption +// TYPEPARAM_IN_CONTEXTTYPE_1: Begin completions, 3 items // TYPEPARAM_IN_CONTEXTTYPE_1-DAG: Decl[Constructor]/CurrNominal: init()[#MyStruct#]; // TYPEPARAM_IN_CONTEXTTYPE_1-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Convertible]: myProtocolOption[#MyStruct#]; +// TYPEPARAM_IN_CONTEXTTYPE_1-DAG: Decl[StaticVar]/CurrNominal: otherProtocolOption[#MyStruct#]; // TYPEPARAM_IN_CONTEXTTYPE_1: End completions } @@ -795,11 +818,13 @@ func testClosureReturnTypeForOverloaded() { overloadedClosureRcv { .#^OVERLOADED_CLOSURE_RETURN^# } -// OVERLOADED_CLOSURE_RETURN: Begin completions, 4 items +// OVERLOADED_CLOSURE_RETURN: Begin completions, 6 items // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: South[#SomeEnum1#]; // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: North[#SomeEnum1#]; +// OVERLOADED_CLOSURE_RETURN-DAG: Decl[InstanceMethod]/CurrNominal: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: East[#SomeEnum2#]; // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: West[#SomeEnum2#]; +// OVERLOADED_CLOSURE_RETURN-DAG: Decl[InstanceMethod]/CurrNominal: hash({#(self): SomeEnum2#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_CLOSURE_RETURN: End completions } diff --git a/test/IDE/complete_user_accessible.swift b/test/IDE/complete_user_accessible.swift new file mode 100644 index 0000000000000..551648d195f31 --- /dev/null +++ b/test/IDE/complete_user_accessible.swift @@ -0,0 +1,19 @@ +/// Check that serialized non user accessible functions are not autocompleted. +/// rdar://problem/53891642 +/// SR-7460 + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module %S/Inputs/complete_user_accessibility_helper.swift -module-name helper -emit-module-path %t/helper.swiftmodule +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=USER-ACCESS -I %t | %FileCheck %s -check-prefix=USER-ACCESS + +import helper + +{ + _ = MyEnum.#^USER-ACCESS^# +// USER-ACCESS: Begin completions +// USER-ACCESS-DAG: Keyword[self]/CurrNominal: self[#MyEnum.Type#]; name=self +// USER-ACCESS-DAG: Keyword/CurrNominal: Type[#MyEnum.Type#]; name=Type +// USER-ACCESS-DAG: Decl[EnumElement]/CurrNominal: foo[#MyEnum#]; name=foo +// USER-ACCESS-DAG: Decl[EnumElement]/CurrNominal: bar[#MyEnum#]; name=bar +// USER-ACCESS-NOT: __derived_enum_equals +} diff --git a/test/IDE/print_ast_tc_decls_errors.swift b/test/IDE/print_ast_tc_decls_errors.swift index 802c10a7dea84..4127f2cc0e034 100644 --- a/test/IDE/print_ast_tc_decls_errors.swift +++ b/test/IDE/print_ast_tc_decls_errors.swift @@ -109,11 +109,11 @@ class ClassWithInheritance9 : FooClass, BarClass, FooProtocol, BarProtocol, FooN //===--- Inheritance list in enums. //===--- -enum EnumWithInheritance1 : FooNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{raw type}} expected-error {{an enum with no cases}} +enum EnumWithInheritance1 : FooNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{an enum with no cases}} // NO-TYREPR: {{^}}enum EnumWithInheritance1 : <> {{{$}} // TYREPR: {{^}}enum EnumWithInheritance1 : FooNonExistentProtocol {{{$}} -enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{cannot find type 'BarNonExistentProtocol' in scope}} expected-error {{raw type}} expected-error {{an enum with no cases}} +enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{cannot find type 'BarNonExistentProtocol' in scope}} expected-error {{an enum with no cases}} // NO-TYREPR: {{^}}enum EnumWithInheritance2 : <>, <> {{{$}} // TYREPR: {{^}}enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {{{$}} diff --git a/test/IDE/print_clang_objc_async.swift b/test/IDE/print_clang_objc_async.swift new file mode 100644 index 0000000000000..7d3029fff8be6 --- /dev/null +++ b/test/IDE/print_clang_objc_async.swift @@ -0,0 +1,20 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -print-module -source-filename %s -module-to-print=ObjCConcurrency -function-definitions=false -enable-experimental-concurrency > %t/ObjCConcurrency.printed.txt +// RUN: %FileCheck -input-file %t/ObjCConcurrency.printed.txt %s + +// REQUIRES: objc_interop + +// CHECK-LABEL: class SlowServer : NSObject { +// CHECK-DAG: func doSomethingSlow(_ operation: String, completionHandler handler: @escaping (Int) -> Void) +// CHECK-DAG: func doSomethingSlow(_ operation: String) async -> Int +// CHECK-DAG: func doSomethingDangerous(_ operation: String, completionHandler handler: ((String?, Error?) -> Void)? = nil) +// CHECK-DAG: func doSomethingDangerous(_ operation: String) async throws -> String? +// CHECK-DAG: func checkAvailability(completionHandler: @escaping (Bool) -> Void) +// CHECK-DAG: func checkAvailability() async -> Bool +// CHECK-DAG: func findAnswer(completionHandler handler: @escaping (String?, Error?) -> Void) +// CHECK-DAG: func findAnswer() async throws -> String? +// CHECK-DAG: func findAnswerFailingly(completionHandler handler: @escaping (String?, Error?) -> Void) throws +// CHECK-DAG: func findAnswerFailingly() async throws -> String? +// CHECK-DAG: func doSomethingFun(_ operation: String) async +// CHECK: {{^[}]$}} diff --git a/test/IDE/print_swift_module.swift b/test/IDE/print_swift_module.swift index 63e4a9d54aa55..a54c31fa390b3 100644 --- a/test/IDE/print_swift_module.swift +++ b/test/IDE/print_swift_module.swift @@ -28,7 +28,9 @@ public func returnsAlias() -> Alias { } @_functionBuilder -struct BridgeBuilder {} +struct BridgeBuilder { + static func buildBlock(_: Any...) {} +} public struct City { public init(@BridgeBuilder builder: () -> ()) {} diff --git a/test/IRGen/Inputs/comdat1.swift b/test/IRGen/Inputs/comdat1.swift new file mode 100644 index 0000000000000..f219fa273491d --- /dev/null +++ b/test/IRGen/Inputs/comdat1.swift @@ -0,0 +1,5 @@ +private final class C {} +public func f() { + var cs: [C] = [] + cs.append(C()) +} diff --git a/test/IRGen/Inputs/comdat2.swift b/test/IRGen/Inputs/comdat2.swift new file mode 100644 index 0000000000000..96f5838138883 --- /dev/null +++ b/test/IRGen/Inputs/comdat2.swift @@ -0,0 +1,4 @@ +public func g() { + var a: [Int] = [] + a.append(1) +} diff --git a/test/IRGen/Inputs/local_extern.h b/test/IRGen/Inputs/local_extern.h new file mode 100644 index 0000000000000..de84f094bee45 --- /dev/null +++ b/test/IRGen/Inputs/local_extern.h @@ -0,0 +1,21 @@ +static inline int _no_prior_var() { + extern int var; + return var; +} + +static inline int _no_prior_func() { + extern int func(); + return func(); +} + +static int prior_var = 1; +static inline int _prior_var() { + extern int prior_var; + return prior_var; +} + +static inline int prior_func() { return 1; } +static inline int _prior_func() { + extern int prior_func(); + return prior_func(); +} diff --git a/test/IRGen/Inputs/opaque_result_type_private_underlying_2.swift b/test/IRGen/Inputs/opaque_result_type_private_underlying_2.swift index 2699a3405908a..ebabbef714c62 100644 --- a/test/IRGen/Inputs/opaque_result_type_private_underlying_2.swift +++ b/test/IRGen/Inputs/opaque_result_type_private_underlying_2.swift @@ -45,3 +45,39 @@ public struct PublicUnderlyingInlinable : A { return PublicS() } } + + +public protocol P {} + +private struct PrivateSome : P {} +public func getSome() -> some P { + return PrivateSome() +} + +@propertyWrapper +public struct Wrapper { + public var wrappedValue: T + + public init(wrappedValue v: T) { + wrappedValue = v + } +} + +public struct R: P { + @Wrapper private var privateState = PrivateState() + var x: T? = nil + + public init(_ v: V.Type, _ t: T) { + x = t + } + + public mutating func modify() { + x = nil + } +} + +private extension R { + struct PrivateState { + var x = 0 + } +} diff --git a/test/IRGen/abitypes.swift b/test/IRGen/abitypes.swift index e62790d288d3c..00b804c660a23 100644 --- a/test/IRGen/abitypes.swift +++ b/test/IRGen/abitypes.swift @@ -580,7 +580,8 @@ public func testInlineAgg(_ rect: MyRect) -> Float { // arm64-ios: [[PTR0:%.*]] = getelementptr inbounds %TSo14FiveByteStructV, %TSo14FiveByteStructV* [[STRUCTPTR]], {{i.*}} 0, {{i.*}} 0 // arm64-ios: [[PTR1:%.*]] = getelementptr inbounds %T10ObjectiveC8ObjCBoolV, %T10ObjectiveC8ObjCBoolV* [[PTR0]], {{i.*}} 0, {{i.*}} 0 // arm64-ios: [[PTR2:%.*]] = getelementptr inbounds %TSb, %TSb* [[PTR1]], {{i.*}} 0, {{i.*}} 0 -// arm64-ios: store i1 false, i1* [[PTR2]], align 8 +// arm64-ios: [[BYTE_ADDR:%.*]] = bitcast i1* [[PTR2]] to i8* +// arm64-ios: store i8 0, i8* [[BYTE_ADDR]], align 8 // arm64-ios: [[ARG:%.*]] = load i64, i64* [[COERCED]] // arm64-ios: call void bitcast (void ()* @objc_msgSend to void (i8*, i8*, i64)*)(i8* {{.*}}, i8* {{.*}}, i64 [[ARG]]) // @@ -590,7 +591,8 @@ public func testInlineAgg(_ rect: MyRect) -> Float { // arm64e-ios: [[PTR0:%.*]] = getelementptr inbounds %TSo14FiveByteStructV, %TSo14FiveByteStructV* [[STRUCTPTR]], {{i.*}} 0, {{i.*}} 0 // arm64e-ios: [[PTR1:%.*]] = getelementptr inbounds %T10ObjectiveC8ObjCBoolV, %T10ObjectiveC8ObjCBoolV* [[PTR0]], {{i.*}} 0, {{i.*}} 0 // arm64e-ios: [[PTR2:%.*]] = getelementptr inbounds %TSb, %TSb* [[PTR1]], {{i.*}} 0, {{i.*}} 0 -// arm64e-ios: store i1 false, i1* [[PTR2]], align 8 +// arm64e-ios: [[BYTE_ADDR:%.*]] = bitcast i1* [[PTR2]] to i8* +// arm64e-ios: store i8 0, i8* [[BYTE_ADDR]], align 8 // arm64e-ios: [[ARG:%.*]] = load i64, i64* [[COERCED]] // arm64e-ios: call void bitcast (void ()* @objc_msgSend to void (i8*, i8*, i64)*)(i8* {{.*}}, i8* {{.*}}, i64 [[ARG]]) // arm64-macosx: define swiftcc void @"$s8abitypes14testBOOLStructyyF"() @@ -599,7 +601,8 @@ public func testInlineAgg(_ rect: MyRect) -> Float { // arm64-macosx: [[PTR0:%.*]] = getelementptr inbounds %TSo14FiveByteStructV, %TSo14FiveByteStructV* [[STRUCTPTR]], {{i.*}} 0, {{i.*}} 0 // arm64-macosx: [[PTR1:%.*]] = getelementptr inbounds %T10ObjectiveC8ObjCBoolV, %T10ObjectiveC8ObjCBoolV* [[PTR0]], {{i.*}} 0, {{i.*}} 0 // arm64-macosx: [[PTR2:%.*]] = getelementptr inbounds %TSb, %TSb* [[PTR1]], {{i.*}} 0, {{i.*}} 0 -// arm64-macosx: store i1 false, i1* [[PTR2]], align 8 +// arm64-macosx: [[BYTE_ADDR:%.*]] = bitcast i1* [[PTR2]] to i8* +// arm64-macosx: store i8 0, i8* [[BYTE_ADDR]], align 8 // arm64-macosx: [[ARG:%.*]] = load i64, i64* [[COERCED]] // arm64-macosx: call void bitcast (void ()* @objc_msgSend to void (i8*, i8*, i64)*)(i8* {{.*}}, i8* {{.*}}, i64 [[ARG]]) public func testBOOLStruct() { diff --git a/test/IRGen/big_types_corner_cases_tiny.swift b/test/IRGen/big_types_corner_cases_tiny.swift index 8a9a88b28f9b1..a4fb5a9a6929a 100644 --- a/test/IRGen/big_types_corner_cases_tiny.swift +++ b/test/IRGen/big_types_corner_cases_tiny.swift @@ -4,7 +4,7 @@ // DO NOT ADD ANY MORE CODE TO THIS FILE! -// CHECK-LABEL: define internal void @globalinit +// CHECK-LABEL: define internal void @{{.*}}WZ // CHECK: [[ALLOC:%.*]] = alloca %T27big_types_corner_cases_tiny30LoadableStructWithBiggerStringV // CHECK: call swiftcc void {{.*}}(%T27big_types_corner_cases_tiny30LoadableStructWithBiggerStringV* noalias nocapture sret [[ALLOC]] let model = ClassWithLoadableStructWithBiggerString().f() diff --git a/test/IRGen/builtins.swift b/test/IRGen/builtins.swift index d2dbff0b194c9..43adb03237981 100644 --- a/test/IRGen/builtins.swift +++ b/test/IRGen/builtins.swift @@ -235,21 +235,24 @@ func cmpxchg_test(_ ptr: Builtin.RawPointer, a: Builtin.Int32, b: Builtin.Int32) // CHECK: [[Z_VAL:%.*]] = extractvalue { i32, i1 } [[Z_RES]], 0 // CHECK: [[Z_SUCCESS:%.*]] = extractvalue { i32, i1 } [[Z_RES]], 1 // CHECK: store i32 [[Z_VAL]], i32* {{.*}}, align 4 - // CHECK: store i1 [[Z_SUCCESS]], i1* {{.*}}, align 1 + // CHECK: [[Z_SUCCESS_B:%.*]] = zext i1 [[Z_SUCCESS]] to i8 + // CHECK: store i8 [[Z_SUCCESS_B]], i8* {{.*}}, align 1 var (z, zSuccess) = Builtin.cmpxchg_acquire_acquire_Int32(ptr, a, b) // CHECK: [[Y_RES:%.*]] = cmpxchg volatile i32* {{.*}}, i32 {{.*}}, i32 {{.*}} monotonic monotonic // CHECK: [[Y_VAL:%.*]] = extractvalue { i32, i1 } [[Y_RES]], 0 // CHECK: [[Y_SUCCESS:%.*]] = extractvalue { i32, i1 } [[Y_RES]], 1 // CHECK: store i32 [[Y_VAL]], i32* {{.*}}, align 4 - // CHECK: store i1 [[Y_SUCCESS]], i1* {{.*}}, align 1 + // CHECK: [[Y_SUCCESS_B:%.*]] = zext i1 [[Y_SUCCESS]] to i8 + // CHECK: store i8 [[Y_SUCCESS_B]], i8* {{.*}}, align 1 var (y, ySuccess) = Builtin.cmpxchg_monotonic_monotonic_volatile_Int32(ptr, a, b) // CHECK: [[X_RES:%.*]] = cmpxchg volatile i32* {{.*}}, i32 {{.*}}, i32 {{.*}} syncscope("singlethread") acquire monotonic // CHECK: [[X_VAL:%.*]] = extractvalue { i32, i1 } [[X_RES]], 0 // CHECK: [[X_SUCCESS:%.*]] = extractvalue { i32, i1 } [[X_RES]], 1 // CHECK: store i32 [[X_VAL]], i32* {{.*}}, align 4 - // CHECK: store i1 [[X_SUCCESS]], i1* {{.*}}, align 1 + // CHECK: [[X_SUCCESS_B:%.*]] = zext i1 [[X_SUCCESS]] to i8 + // CHECK: store i8 [[X_SUCCESS_B]], i8* {{.*}}, align 1 var (x, xSuccess) = Builtin.cmpxchg_acquire_monotonic_volatile_singlethread_Int32(ptr, a, b) // CHECK: [[W_RES:%.*]] = cmpxchg volatile i64* {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst @@ -257,7 +260,8 @@ func cmpxchg_test(_ ptr: Builtin.RawPointer, a: Builtin.Int32, b: Builtin.Int32) // CHECK: [[W_SUCCESS:%.*]] = extractvalue { i64, i1 } [[W_RES]], 1 // CHECK: [[W_VAL_PTR:%.*]] = inttoptr i64 [[W_VAL]] to i8* // CHECK: store i8* [[W_VAL_PTR]], i8** {{.*}}, align 8 - // CHECK: store i1 [[W_SUCCESS]], i1* {{.*}}, align 1 + // CHECK: [[W_SUCCESS_B:%.*]] = zext i1 [[W_SUCCESS]] to i8 + // CHECK: store i8 [[W_SUCCESS_B]], i8* {{.*}}, align 1 var (w, wSuccess) = Builtin.cmpxchg_seqcst_seqcst_volatile_singlethread_RawPointer(ptr, ptr, ptr) // CHECK: [[V_RES:%.*]] = cmpxchg weak volatile i64* {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst @@ -265,7 +269,8 @@ func cmpxchg_test(_ ptr: Builtin.RawPointer, a: Builtin.Int32, b: Builtin.Int32) // CHECK: [[V_SUCCESS:%.*]] = extractvalue { i64, i1 } [[V_RES]], 1 // CHECK: [[V_VAL_PTR:%.*]] = inttoptr i64 [[V_VAL]] to i8* // CHECK: store i8* [[V_VAL_PTR]], i8** {{.*}}, align 8 - // CHECK: store i1 [[V_SUCCESS]], i1* {{.*}}, align 1 + // CHECK: [[V_SUCCESS_B:%.*]] = zext i1 [[V_SUCCESS]] to i8 + // CHECK: store i8 [[V_SUCCESS_B]], i8* {{.*}}, align 1 var (v, vSuccess) = Builtin.cmpxchg_seqcst_seqcst_weak_volatile_singlethread_RawPointer(ptr, ptr, ptr) } @@ -558,7 +563,8 @@ struct Pair { var i: Int, b: Bool } // CHECK: [[FLDI:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 0 // CHECK: store i32 0, i32* [[FLDI]] // CHECK: [[FLDB:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 1 -// CHECK: store i1 false, i1* [[FLDB]] +// CHECK: [[BYTE_ADDR:%.*]] = bitcast i1* [[FLDB]] to i8* +// CHECK: store i8 0, i8* [[BYTE_ADDR]] // CHECK: [[RET:%.*]] = getelementptr inbounds {{.*}} [[ALLOCA]], i32 0, i32 0 // CHECK: [[RES:%.*]] = load i64, i64* [[RET]] // CHECK: ret i64 [[RES]] @@ -575,7 +581,8 @@ func zeroInitializer() -> (Empty, Pair) { // CHECK: [[FLDI:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 0 // CHECK: store i32 0, i32* [[FLDI]] // CHECK: [[FLDB:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 1 -// CHECK: store i1 false, i1* [[FLDB]] +// CHECK: [[BYTE_ADDR:%.*]] = bitcast i1* [[FLDB]] to i8* +// CHECK: store i8 0, i8* [[BYTE_ADDR]] // CHECK: [[RET:%.*]] = getelementptr inbounds {{.*}} [[ALLOCA]], i32 0, i32 0 // CHECK: [[RES:%.*]] = load i64, i64* [[RET]] // CHECK: ret i64 [[RES]] @@ -695,14 +702,16 @@ func generic_ispod_test(_: T) { // CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]] // CHECK-NEXT: [[ISNOTPOD:%.*]] = and i32 [[FLAGS]], 65536 // CHECK-NEXT: [[ISPOD:%.*]] = icmp eq i32 [[ISNOTPOD]], 0 - // CHECK-NEXT: store i1 [[ISPOD]], i1* [[S:%.*]] + // CHECK-NEXT: [[BYTE_ADDR:%.*]] = bitcast i1* [[S:%.*]] to i8* + // CHECK-NEXT: [[BYTE:%.*]] = zext i1 [[ISPOD]] to i8 + // CHECK-NEXT: store i8 [[BYTE]], i8* [[BYTE_ADDR]] var s = Builtin.ispod(T.self) } // CHECK-LABEL: define {{.*}} @{{.*}}ispod_test func ispod_test() { - // CHECK: store i1 true, i1* - // CHECK: store i1 false, i1* + // CHECK: store i8 1, i8* + // CHECK: store i8 0, i8* var t = Builtin.ispod(Int.self) var f = Builtin.ispod(Builtin.NativeObject.self) } @@ -713,17 +722,19 @@ func generic_isbitwisetakable_test(_: T) { // CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]] // CHECK-NEXT: [[ISNOTBITWISETAKABLE:%.*]] = and i32 [[FLAGS]], 1048576 // CHECK-NEXT: [[ISBITWISETAKABLE:%.*]] = icmp eq i32 [[ISNOTBITWISETAKABLE]], 0 - // CHECK-NEXT: store i1 [[ISBITWISETAKABLE]], i1* [[S:%.*]] + // CHECK-NEXT: [[BYTE_ADDR:%.*]] = bitcast i1* [[S:%.*]] + // CHECK-NEXT: [[BYTE:%.*]] = zext i1 [[ISBITWISETAKABLE]] to i8 + // CHECK-NEXT: store i8 [[BYTE]], i8* [[BYTE_ADDR]] var s = Builtin.isbitwisetakable(T.self) } // CHECK-LABEL: define {{.*}} @{{.*}}isbitwisetakable_test func isbitwisetakable_test() { - // CHECK: store i1 true, i1* - // CHECK: store i1 true, i1* - // CHECK: store i1 true, i1* - // CHECK: store i1 true, i1* - // CHECK: store i1 false, i1* + // CHECK: store i8 1, i8* + // CHECK: store i8 1, i8* + // CHECK: store i8 1, i8* + // CHECK: store i8 1, i8* + // CHECK: store i8 0, i8* var t1 = Builtin.isbitwisetakable(Int.self) var t2 = Builtin.isbitwisetakable(C.self) var t3 = Builtin.isbitwisetakable(Abc.self) diff --git a/test/IRGen/comdat.swift b/test/IRGen/comdat.swift new file mode 100644 index 0000000000000..e85eb939af45b --- /dev/null +++ b/test/IRGen/comdat.swift @@ -0,0 +1,14 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-ir %S/Inputs/comdat1.swift %S/Inputs/comdat2.swift -O -num-threads 1 -module-name comdat -o %t/comdat1.ll -o %t/comdat2.ll +// RUN: %FileCheck -check-prefix CHECK-1 %s < %t/comdat1.ll +// RUN: %FileCheck -check-prefix CHECK-2 %s < %t/comdat2.ll + +// REQUIRES: OS=windows-msvc + +// Ensure that the definition is marked as COMDAT +// CHECK-1: "$s6comdat1C33_{{.*}}LLCMa" = comdat any +// CHECK-1: "$s6comdat1C33_{{.*}}LLCMn" = comdat any + +// Ensure that no foward declaration is emitted +// CHECK-2-NOT: "$s6comdat1C33_{{.*}}LLCMa" = comdat any +// CHECK-2-NOT: "$s6comdat1C33_{{.*}}LLCMn" = comdat any diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil index b08f0e6587bfd..f17d1036ab376 100644 --- a/test/IRGen/enum.sil +++ b/test/IRGen/enum.sil @@ -1010,7 +1010,9 @@ entry(%0 : $Builtin.Int63): // CHECK-64: entry: // CHECK-64: [[T:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum21SinglePayloadSpareBitO* %1 to i63* -// CHECK-64: store i63 [[T]], i63* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i63 [[T]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: ret void // CHECK-64: } sil @single_payload_spare_bit_inject_x_indirect : $(Builtin.Int63, @inout SinglePayloadSpareBit) -> () { @@ -1784,7 +1786,9 @@ entry(%0 : $Builtin.Int62): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i62* -// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x7FFF_FFFF_FFFF_FFFF @@ -1825,7 +1829,9 @@ entry(%0 : $Builtin.Int63): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i63* -// CHECK-64: store i63 [[NATIVECC_TRUNC]], i63* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i63 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x7FFF_FFFF_FFFF_FFFF @@ -2024,7 +2030,9 @@ entry(%0 : $Builtin.Int62): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i62* -// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x3FFF_FFFF_FFFF_FFFF @@ -2060,7 +2068,9 @@ entry(%0 : $Builtin.Int60): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i60 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i60* -// CHECK-64: store i60 [[NATIVECC_TRUNC]], i60* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i60* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i60 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x3FFF_FFFF_FFFF_FFFF diff --git a/test/IRGen/enum_future.sil b/test/IRGen/enum_future.sil index b538b63093269..48cc72ee09922 100644 --- a/test/IRGen/enum_future.sil +++ b/test/IRGen/enum_future.sil @@ -1014,7 +1014,9 @@ entry(%0 : $Builtin.Int63): // CHECK-64: entry: // CHECK-64: [[T:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future21SinglePayloadSpareBitO* %1 to i63* -// CHECK-64: store i63 [[T]], i63* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i63 [[T]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: ret void // CHECK-64: } sil @single_payload_spare_bit_inject_x_indirect : $(Builtin.Int63, @inout SinglePayloadSpareBit) -> () { @@ -1788,7 +1790,9 @@ entry(%0 : $Builtin.Int62): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i62* -// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64* +// CHECK-64: [[VAL:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x7FFF_FFFF_FFFF_FFFF @@ -1829,7 +1833,9 @@ entry(%0 : $Builtin.Int63): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i63* -// CHECK-64: store i63 [[NATIVECC_TRUNC]], i63* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64* +// CHECK-64: [[VAL:%.*]] = zext i63 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x7FFF_FFFF_FFFF_FFFF @@ -2028,7 +2034,9 @@ entry(%0 : $Builtin.Int62): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i62* -// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64* +// CHECK-64: [[VAL:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x3FFF_FFFF_FFFF_FFFF @@ -2064,7 +2072,9 @@ entry(%0 : $Builtin.Int60): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i60 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i60* -// CHECK-64: store i60 [[NATIVECC_TRUNC]], i60* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i60* [[DATA_ADDR]] to i64* +// CHECK-64: [[VAL:%.*]] = zext i60 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x3FFF_FFFF_FFFF_FFFF diff --git a/test/IRGen/generic_metatypes_future.swift b/test/IRGen/generic_metatypes_future.swift index bf18d17617de0..685eaed727377 100644 --- a/test/IRGen/generic_metatypes_future.swift +++ b/test/IRGen/generic_metatypes_future.swift @@ -1,5 +1,5 @@ -// RUN: %swift -prespecialize-generic-metadata -module-name generic_metatypes -target x86_64-apple-macosx50.99 -emit-ir -disable-legacy-type-info -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 -DINT=i64 %s +// RUN: %swift -prespecialize-generic-metadata -module-name generic_metatypes -target x86_64-apple-macosx99.99 -emit-ir -disable-legacy-type-info -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 -DINT=i64 %s // RUN: %swift -prespecialize-generic-metadata -module-name generic_metatypes -target x86_64-apple-ios99.0 -emit-ir -disable-legacy-type-info -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 -DINT=i64 %s // RUN: %swift -prespecialize-generic-metadata -module-name generic_metatypes -target x86_64-apple-tvos99.0 -emit-ir -disable-legacy-type-info -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 -DINT=i64 %s // RUN: %swift -prespecialize-generic-metadata -module-name generic_metatypes -target i386-apple-watchos9.99 -emit-ir -disable-legacy-type-info -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-32 -DINT=i32 %s diff --git a/test/IRGen/globals.swift b/test/IRGen/globals.swift index 509922e9483ed..b423befb38b6d 100644 --- a/test/IRGen/globals.swift +++ b/test/IRGen/globals.swift @@ -53,6 +53,5 @@ extension A { // CHECK: define{{( dllexport)?}}{{( protected)?}} i32 @main(i32 %0, i8** %1) {{.*}} { // CHECK: store i64 {{.*}}, i64* getelementptr inbounds ([[INT]], [[INT]]* @"$s7globals2g0Sivp", i32 0, i32 0), align 8 -// FIXME: give these initializers a real mangled name -// CHECK: define internal void @globalinit_{{.*}}func0() {{.*}} { +// CHECK: define internal void @"{{.*}}WZ"() {{.*}} { // CHECK: store i64 5, i64* getelementptr inbounds (%TSi, %TSi* @"$s7globals1AV3fooSivpZ", i32 0, i32 0), align 8 diff --git a/test/IRGen/lazy_globals.swift b/test/IRGen/lazy_globals.swift index ce0f387d9e485..8b1d761c70e40 100644 --- a/test/IRGen/lazy_globals.swift +++ b/test/IRGen/lazy_globals.swift @@ -2,12 +2,12 @@ // REQUIRES: CPU=x86_64 -// CHECK: @globalinit_[[T:.*]]_token0 = internal global i64 0, align 8 +// CHECK: @"[[T:.*]]Wz" = internal global i64 0, align 8 // CHECK: @"$s12lazy_globals1xSivp" = hidden global %TSi zeroinitializer, align 8 // CHECK: @"$s12lazy_globals1ySivp" = hidden global %TSi zeroinitializer, align 8 // CHECK: @"$s12lazy_globals1zSivp" = hidden global %TSi zeroinitializer, align 8 -// CHECK: define internal void @globalinit_[[T]]_func0() {{.*}} { +// CHECK: define internal void @"[[T]]WZ"() {{.*}} { // CHECK: entry: // CHECK: store i64 1, i64* getelementptr inbounds (%TSi, %TSi* @"$s12lazy_globals1xSivp", i32 0, i32 0), align 8 // CHECK: store i64 2, i64* getelementptr inbounds (%TSi, %TSi* @"$s12lazy_globals1ySivp", i32 0, i32 0), align 8 @@ -17,17 +17,17 @@ // CHECK: define hidden swiftcc i8* @"$s12lazy_globals1xSivau"() {{.*}} { // CHECK: entry: -// CHECK: call void @swift_once(i64* @globalinit_[[T]]_token0, i8* bitcast (void ()* @globalinit_[[T]]_func0 to i8*), i8* undef) +// CHECK: call void @swift_once(i64* @"[[T]]Wz", i8* bitcast (void ()* @"[[T]]WZ" to i8*), i8* undef) // CHECK: } // CHECK: define hidden swiftcc i8* @"$s12lazy_globals1ySivau"() {{.*}} { // CHECK: entry: -// CHECK: call void @swift_once(i64* @globalinit_[[T]]_token0, i8* bitcast (void ()* @globalinit_[[T]]_func0 to i8*), i8* undef) +// CHECK: call void @swift_once(i64* @"[[T]]Wz", i8* bitcast (void ()* @"[[T]]WZ" to i8*), i8* undef) // CHECK: } // CHECK: define hidden swiftcc i8* @"$s12lazy_globals1zSivau"() {{.*}} { // CHECK: entry: -// CHECK: call void @swift_once(i64* @globalinit_[[T]]_token0, i8* bitcast (void ()* @globalinit_[[T]]_func0 to i8*), i8* undef) +// CHECK: call void @swift_once(i64* @"[[T]]Wz", i8* bitcast (void ()* @"[[T]]WZ" to i8*), i8* undef) // CHECK: } var (x, y, z) = (1, 2, 3) diff --git a/test/IRGen/local_extern.swift b/test/IRGen/local_extern.swift new file mode 100644 index 0000000000000..06c9a3d5e94bd --- /dev/null +++ b/test/IRGen/local_extern.swift @@ -0,0 +1,10 @@ +// RUN: %target-swift-frontend -import-objc-header %S/Inputs/local_extern.h %s -emit-ir | %FileCheck %s +// CHECK: @var = external {{(dso_local )?}}global i32 +// CHECK: @prior_var = internal global i32 +// CHECK: declare {{(dso_local )?}}i32 @func +// CHECK: define internal i32 @prior_func + +print("\(_no_prior_var())") +print("\(_no_prior_func())") +print("\(_prior_var())") +print("\(_prior_func())") diff --git a/test/IRGen/objc_local.swift b/test/IRGen/objc_local.swift index c0d24d2b3fa64..d20e087b0d6f7 100644 --- a/test/IRGen/objc_local.swift +++ b/test/IRGen/objc_local.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %build-irgen-test-overlays // RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) %s -emit-ir | %FileCheck %s +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) %s -emit-ir -O | %FileCheck %s // REQUIRES: objc_interop diff --git a/test/IRGen/opaque_result_type_private_underlying.swift b/test/IRGen/opaque_result_type_private_underlying.swift index 85c975c77a2e0..a1b6f726704b3 100644 --- a/test/IRGen/opaque_result_type_private_underlying.swift +++ b/test/IRGen/opaque_result_type_private_underlying.swift @@ -68,3 +68,11 @@ public struct MyThing { } } #endif + +public struct E { + var body : some P { + var r = R(V.self, getSome()) + r.modify() + return r + } +} diff --git a/test/IRGen/pic.swift b/test/IRGen/pic.swift index 8afc50ec49846..def763b6bb0b1 100644 --- a/test/IRGen/pic.swift +++ b/test/IRGen/pic.swift @@ -3,6 +3,7 @@ // SR-12194 // XFAIL: OS=linux-android, CPU=aarch64 +// UNSUPPORTED: OS=linux-gnu // RUN: %target-swift-frontend %s -module-name main -S -o - | %FileCheck -check-prefix=%target-cpu -check-prefix=%target-cpu-%target-sdk-name %s @@ -61,10 +62,13 @@ public func use_global() -> Int { // armv7k: ldr [[R_ADR]], {{\[}}[[R_ADR]]{{\]}} // arm64-LABEL: {{_?}}$s4main10use_globalSiyF: +// arm64: adrp [[REG3:x[0-9]+]], _$s4main6globalSivp@PAGE // arm64: adrp [[REG1:x[0-9]+]], _$s4main6globalSivp@PAGE // arm64: add [[REG1]], [[REG1]], _$s4main6globalSivp@PAGEOFF +// arm64: str [[REG3]], [sp, #16] // arm64: bl _swift_beginAccess -// arm64: ldr [[REG2:x[0-9]+]], {{\[}}[[REG1]]{{\]}} +// arm64: ldr [[REG4:x[0-9]+]], [sp, #16] +// arm64: ldr [[REG2:x[0-9]+]], {{\[}}[[REG4]], _$s4main6globalSivp@PAGEOFF // arm64: str [[REG2]], [sp] // arm64: bl _swift_endAccess // arm64: ldr x0, [sp] diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_distinct_generic_class.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_distinct_generic_class.swift index 4343391e57e12..8e087b91ceed0 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_distinct_generic_class.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_distinct_generic_class.swift @@ -238,90 +238,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_ARGUMENT1:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT1_METADATA]] to i8* // CHECK: [[ERASED_ARGUMENT2:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT2_METADATA]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// : }>* -// CHECK-SAME: @"$s4main9Argument1[[UNIQUE_ID_1]]LLCySiGMf" -// : to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// CHECK-SAME: ), [[ERASED_ARGUMENT1]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument2[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument2[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// CHECK-SAME: }>* @"$s4main9Argument2[[UNIQUE_ID_1]]LLCySSGMf" to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// : ), [[ERASED_ARGUMENT2]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1]], [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCyAA9Argument1ACLLCySiGAA9Argument2ACLLCySSGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_ARGUMENT1]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_different_value.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_different_value.swift index 782a1c22d4cc7..bc1dd0c10b5fc 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_different_value.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_different_value.swift @@ -228,90 +228,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_ARGUMENT1:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT1_METADATA]] to i8* // CHECK: [[ERASED_ARGUMENT2:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT2_METADATA]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// : }>* -// CHECK-SAME: @"$s4main9Argument1[[UNIQUE_ID_1]]LLCySiGMf" -// : to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// CHECK-SAME: ), [[ERASED_ARGUMENT1]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// CHECK-SAME: }>* @"$s4main9Argument1[[UNIQUE_ID_1]]LLCySSGMf" to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// : ), [[ERASED_ARGUMENT2]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1]], [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCyAA9Argument1ACLLCySiGAFySSGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_ARGUMENT1]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_same_value.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_same_value.swift index 063e19e254d90..d0122ee20739d 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_same_value.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_same_value.swift @@ -228,90 +228,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_ARGUMENT1:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT1_METADATA]] to i8* // CHECK: [[ERASED_ARGUMENT2:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT2_METADATA]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// : }>* -// CHECK-SAME: @"$s4main9Argument1[[UNIQUE_ID_1]]LLCySiGMf" -// : to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// CHECK-SAME: ), [[ERASED_ARGUMENT1]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// CHECK-SAME: }>* @"$s4main9Argument1[[UNIQUE_ID_1]]LLCySiGMf" to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// : ), [[ERASED_ARGUMENT2]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1]], [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCyAA9Argument1ACLLCySiGAGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_ARGUMENT1]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_con_double.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_con_double.swift index 04e01f00adbc6..a6e82b06a8531 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_con_double.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_con_double.swift @@ -239,20 +239,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSdN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_3:[0-9A-Z_]+]]CySdGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -270,20 +256,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_3:[0-9A-Z_]+]]CySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -301,20 +273,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSSN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CySSGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_subclass_arg.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_subclass_arg.swift index 1441ee49f2a05..d31da831d35b7 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_subclass_arg.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_subclass_arg.swift @@ -224,20 +224,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_3:[0-9A-Z_]+]]CySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -255,20 +241,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_3:[0-9A-Z_]+]]CySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -286,20 +258,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSSN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CySSGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subclass_arg-2nd_anc_gen-1st-arg_con_int.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subclass_arg-2nd_anc_gen-1st-arg_con_int.swift index 9cca1c2489be4..571080fd0c496 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subclass_arg-2nd_anc_gen-1st-arg_con_int.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subclass_arg-2nd_anc_gen-1st-arg_con_int.swift @@ -228,20 +228,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -259,20 +245,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSSN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySSGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -290,20 +262,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSSN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySSGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subcls_arg-2nd_anc_gen-1st-arg_subcls_arg.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subcls_arg-2nd_anc_gen-1st-arg_subcls_arg.swift index 1558d95bea74a..0cf8847101f25 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subcls_arg-2nd_anc_gen-1st-arg_subcls_arg.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subcls_arg-2nd_anc_gen-1st-arg_subcls_arg.swift @@ -216,20 +216,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* [[ARGUMENT:%[0-9]+]]) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -247,20 +233,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* [[ARGUMENT:%[0-9]+]]) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -278,20 +250,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* [[ARGUMENT:%[0-9]+]]) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use-1st_argument_generic_class-1argument.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use-1st_argument_generic_class-1argument.swift index 1648484f0de4c..8bf4826b10b70 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use-1st_argument_generic_class-1argument.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use-1st_argument_generic_class-1argument.swift @@ -256,20 +256,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$s4main9Argument1[[UNIQUE_ID_1]]CySiGMf" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CyAA9Argument1ACLLCySiGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use.swift index d1b52bed77166..8ba996f2c6243 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use.swift @@ -101,18 +101,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class.swift index 2cf41486a5b49..b792ac6dfb932 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class.swift @@ -193,55 +193,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main3Box[[UNIQUE_ID_2]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main3Box[[UNIQUE_ID_2]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// : }>* -// CHECK-SAME: @"$s4main3Box[[UNIQUE_ID_1]]LLCySiGMf" -// : to %swift.full_heapmetadata* -// : ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 2 -// CHECK-SAME: ) to i8* -// CHECK-SAME: ), -// CHECK-SAME: [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCyAA3BoxACLLCySiGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class_specialized_at_generic_class.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class_specialized_at_generic_class.swift index 8579ac2e32306..0bdef4eb2cf22 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class_specialized_at_generic_class.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class_specialized_at_generic_class.swift @@ -200,55 +200,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main3Box[[UNIQUE_ID_2]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main3Box[[UNIQUE_ID_2]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// : }>* -// CHECK-SAME: @"$s4main3Box[[UNIQUE_ID_1]]LLCyAA5InnerACLLCySiGGMf" -// : to %swift.full_heapmetadata* -// : ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 2 -// CHECK-SAME: ) to i8* -// CHECK-SAME: ), -// CHECK-SAME: [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCyAA3BoxACLLCyAA5InnerACLLCySiGGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_enum.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_enum.swift index 73d90d620d033..5bbc41092198d 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_enum.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_enum.swift @@ -171,35 +171,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main6Either[[UNIQUE_ID_1]]OySiGMf" to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ) to i8* -// CHECK-SAME: ), -// CHECK-SAME: [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CyAA6EitherACLLOySiGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_struct.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_struct.swift index 5d0d352c4716d..fc7680e252c20 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_struct.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_struct.swift @@ -173,38 +173,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32, -// : [ -// : 4 x i8 -// : ], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main4Left[[UNIQUE_ID_1]]VySiGMf" to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ) to i8* -// CHECK-SAME: ), -// CHECK-SAME: [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CyAA4LeftACLLVySiGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift index 8a7e7f5b64002..3a494d17e3fa8 100644 --- a/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift @@ -58,31 +58,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]OMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5Value[[UNIQUE_ID_1]]OySiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift index 944f264a0642c..f79e24b3e4d70 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift @@ -65,31 +65,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main9NamespaceC5ValueOMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: br i1 [[EQUAL_TYPES_1_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceC5ValueOySi_GMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift index 75f5f86c789c5..630518893d0eb 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift @@ -68,55 +68,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TABLE:%[0-9]+]] = bitcast i8** %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8* [[ERASED_TABLE]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = load i8*, i8** [[ARGUMENT_BUFFER]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS]] -// CHECK: br i1 [[EQUAL_ARGUMENTS]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i8**, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOySiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift index 06214ca5a0df9..9687535123ac3 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift @@ -68,55 +68,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TABLE:%[0-9]+]] = bitcast i8** %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8* [[ERASED_TABLE]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = load i8*, i8** [[ARGUMENT_BUFFER]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS]] -// CHECK: br i1 [[EQUAL_ARGUMENTS]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i8**, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOySiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift index 2a779835e9856..6e84589deff53 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift @@ -62,14 +62,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueOMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i64 }>* @"$s4main5ValueOySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* %2, diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift index 9b30b71caf0cf..21a955c1e2231 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift @@ -66,34 +66,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceC5ValueOySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift index 26b68649a8ab9..c1e0c869f9516 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift @@ -66,34 +66,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceO5ValueOySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift index 31a2ac1032fcc..5919bbbca14f2 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift @@ -66,33 +66,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceV5ValueOySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift index 456565a9e6d8e..a37bd8d51a0f4 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift @@ -81,34 +81,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOyS2iGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift index 5d7a94d8356ec..b354662dc6f2f 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift @@ -86,38 +86,6 @@ doit() // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* // CHECK: [[ERASED_TYPE_3:%[0-9]+]] = bitcast %swift.type* %3 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: [[EQUAL_TYPE_1_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_3]] -// CHECK: [[EQUAL_TYPES_1_3:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_2]], [[EQUAL_TYPE_1_3]] -// CHECK: br i1 [[EQUAL_TYPES_1_3]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOyS3iGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift index 1bdf941808ad3..52928f5303254 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift @@ -87,49 +87,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueOMa"([[INT]] %0, i8** %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_BUFFER:%[0-9]+]] = bitcast i8** %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[ERASED_TYPE_ADDRESS_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 0 -// CHECK: [[ERASED_TYPE_1:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_1]] -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[ERASED_TYPE_ADDRESS_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 -// CHECK: [[ERASED_TYPE_2:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_2]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: [[ERASED_TYPE_ADDRESS_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 -// CHECK: [[ERASED_TYPE_3:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_3]] -// CHECK: [[EQUAL_TYPE_1_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_3]] -// CHECK: [[EQUAL_TYPES_1_3:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_2]], [[EQUAL_TYPE_1_3]] -// CHECK: [[ERASED_TYPE_ADDRESS_4:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 -// CHECK: [[ERASED_TYPE_4:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_4]] -// CHECK: [[EQUAL_TYPE_1_4:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_4]] -// CHECK: [[EQUAL_TYPES_1_4:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_3]], [[EQUAL_TYPE_1_4]] -// CHECK: br i1 [[EQUAL_TYPES_1_4]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOyS4iGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_BUFFER]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift index 2749bacd8e23f..7ff26cd1f62d2 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift @@ -86,54 +86,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueOMa"([[INT]] %0, i8** %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_BUFFER:%[0-9]+]] = bitcast i8** %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[ERASED_TYPE_ADDRESS_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 0 -// CHECK: [[ERASED_TYPE_1:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_1]] -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[ERASED_TYPE_ADDRESS_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 -// CHECK: [[ERASED_TYPE_2:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_2]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: [[ERASED_TYPE_ADDRESS_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 -// CHECK: [[ERASED_TYPE_3:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_3]] -// CHECK: [[EQUAL_TYPE_1_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_3]] -// CHECK: [[EQUAL_TYPES_1_3:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_2]], [[EQUAL_TYPE_1_3]] -// CHECK: [[ERASED_TYPE_ADDRESS_4:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 -// CHECK: [[ERASED_TYPE_4:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_4]] -// CHECK: [[EQUAL_TYPE_1_4:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_4]] -// CHECK: [[EQUAL_TYPES_1_4:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_3]], [[EQUAL_TYPE_1_4]] -// CHECK: [[ERASED_TYPE_ADDRESS_5:%[0-9]+]] = getelementptr i8*, i8** %1, i64 4 -// CHECK: [[ERASED_TYPE_5:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_5]] -// CHECK: [[EQUAL_TYPE_1_5:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_5]] -// CHECK: [[EQUAL_TYPES_1_5:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_4]], [[EQUAL_TYPE_1_5]] -// CHECK: br i1 [[EQUAL_TYPES_1_5]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOyS5iGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_BUFFER]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift index 9e45d4f245786..5215223884858 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift @@ -66,31 +66,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueOMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$s10TestModule7IntegerVN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOy10TestModule7IntegerVGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* %2, diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-payload_size.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-payload_size.swift index 5b944e2618b4a..6a200c420543a 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-payload_size.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-payload_size.swift @@ -78,31 +78,6 @@ doit() // CHECK: define{{( protected)?}} swiftcc %swift.metadata_response @"$s4main5ValueOMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOySiGMf" to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* %2, diff --git a/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift index cdddc211799bb..071cdb03e2b80 100644 --- a/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift @@ -44,14 +44,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]VMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5Value[[UNIQUE_ID_1]]VySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5Value[[UNIQUE_ID_1]]VMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift index 02abab0244ef8..fa465d41a8544 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift @@ -46,14 +46,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main9NamespaceC5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: br i1 [[EQUAL_TYPES_1_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main9NamespaceC5ValueVySi_GMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main9NamespaceC5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift index 9e811bba493b3..80febc5946810 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift @@ -51,37 +51,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TABLE:%[0-9]+]] = bitcast i8** %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8* [[ERASED_TABLE]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = load i8*, i8** [[ARGUMENT_BUFFER]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS]] -// CHECK: br i1 [[EQUAL_ARGUMENTS]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_TABLE]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift index 7dc812bb048c3..7798990de8678 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift @@ -54,53 +54,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5OuterVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32, -// CHECK-SAME: {{(\[4 x i8\],)?}} -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5InnerVySiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ) -// CHECK-SAME: to i8* -// CHECK-SAME: ), -// CHECK-SAME: [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32, -// CHECK-SAME: {{(\[4 x i8\],)?}} -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5OuterVyAA5InnerVySiGGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -117,33 +70,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5InnerVMa"([[INT]] %0, %swift.type* [[TYPE:%[0-9]+]]) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* [[TYPE]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32, -// CHECK-SAME: {{(\[4 x i8\],)?}} -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5InnerVySiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift index fc8e54dcce67a..605c568ca8596 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift @@ -44,14 +44,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift index 18faf8c91f44a..93446c7633952 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift @@ -56,60 +56,6 @@ doit() // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TABLE_1:%[0-9]+]] = bitcast i8** %2 to i8* // CHECK: [[ERASED_TABLE_2:%[0-9]+]] = bitcast i8** %3 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_1:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_1]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_1:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_1]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_1]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] -// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_2:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_2]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_2:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_2]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_2]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1QAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] -// CHECK: br i1 [[EQUAL_ARGUMENTS_2]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_TABLE_1]], i8* [[ERASED_TABLE_2]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift index 09d7aea9c2cc5..4ddadcc18122b 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift @@ -63,20 +63,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: br i1 [[EQUAL_TYPES_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift index 43342719fb133..be61faa0c9c05 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift @@ -58,91 +58,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, i8** %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8** %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[ERASED_TYPE_ADDRESS:%[0-9]+]] = getelementptr i8*, i8** %1, i64 0 -// CHECK: %"load argument at index 0 from buffer" = load i8*, i8** [[ERASED_TYPE_ADDRESS]] -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), %"load argument at index 0 from buffer" -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[POINTER_TO_ERASED_TABLE_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 -// CHECK: [[ERASED_TABLE_1:%"load argument at index 1 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_1]], align 1 -// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_1:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_1]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_1:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_1]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_1]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] -// CHECK: [[POINTER_TO_ERASED_TABLE_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 -// CHECK: [[ERASED_TABLE_2:%"load argument at index 2 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_2]], align 1 -// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_2:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_2]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_2:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_2]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_2]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1QAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] -// CHECK: [[POINTER_TO_ERASED_TABLE_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 -// CHECK: [[ERASED_TABLE_3:%"load argument at index 3 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_3]], align 1 -// CHECK: [[UNERASED_TABLE_3:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_3]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_3]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_3:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_3]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_3:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_3]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_3]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_3:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1RAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_3:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_2]], [[EQUAL_DESCRIPTORS_3]] -// CHECK: br i1 [[EQUAL_ARGUMENTS_3]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift index 614d85ee5a084..94acd09f2848d 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift @@ -84,26 +84,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: br i1 [[EQUAL_TYPES_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_3:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3]] -// CHECK: br i1 [[EQUAL_TYPES_3]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift index 2a680000ea99e..ecc6525d7f0c7 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift @@ -62,116 +62,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, i8** %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8** %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[ERASED_TYPE_ADDRESS:%[0-9]+]] = getelementptr i8*, i8** %1, i64 0 -// CHECK: %"load argument at index 0 from buffer" = load i8*, i8** [[ERASED_TYPE_ADDRESS]] -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), %"load argument at index 0 from buffer" -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[POINTER_TO_ERASED_TABLE_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 -// CHECK: [[ERASED_TABLE_1:%"load argument at index 1 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_1]], align 1 -// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_1:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_1]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_1:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_1]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_1]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] -// CHECK: [[POINTER_TO_ERASED_TABLE_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 -// CHECK: [[ERASED_TABLE_2:%"load argument at index 2 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_2]], align 1 -// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_2:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_2]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_2:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_2]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_2]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1QAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] -// CHECK: [[POINTER_TO_ERASED_TABLE_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 -// CHECK: [[ERASED_TABLE_3:%"load argument at index 3 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_3]], align 1 -// CHECK: [[UNERASED_TABLE_3:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_3]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_3]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_3:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_3]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_3:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_3]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_3]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_3:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1RAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_3:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_2]], [[EQUAL_DESCRIPTORS_3]] -// CHECK: [[POINTER_TO_ERASED_TABLE_4:%[0-9]+]] = getelementptr i8*, i8** %1, i64 4 -// CHECK: [[ERASED_TABLE_4:%"load argument at index 4 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_4]], align 1 -// CHECK: [[UNERASED_TABLE_4:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_4]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_4]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_4:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_4]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_4:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_4]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_4:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_4]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_4:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_4]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_4:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_4]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_4:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_4]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_4:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_4]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_4:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_4]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1SAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_4:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_3]], [[EQUAL_DESCRIPTORS_4]] -// CHECK: br i1 [[EQUAL_ARGUMENTS_4]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift index a60f667a627fe..22eee9e0055db 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift @@ -85,32 +85,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: br i1 [[EQUAL_TYPES_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_3:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3]] -// CHECK: br i1 [[EQUAL_TYPES_3]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[TYPE_COMPARISON_4:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_4]]: -// CHECK: [[EQUAL_TYPE_4:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss5UInt8VN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_4:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_4]] -// CHECK: br i1 [[EQUAL_TYPES_4]], label %[[EXIT_PRESPECIALIZED_4:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_4]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVys5UInt8VGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift index 3bfa8c5834da9..f4dc38b7bdb7f 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift @@ -66,141 +66,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, i8** %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8** %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[ERASED_TYPE_ADDRESS:%[0-9]+]] = getelementptr i8*, i8** %1, i64 0 -// CHECK: %"load argument at index 0 from buffer" = load i8*, i8** [[ERASED_TYPE_ADDRESS]] -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), %"load argument at index 0 from buffer" -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[POINTER_TO_ERASED_TABLE_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 -// CHECK: [[ERASED_TABLE_1:%"load argument at index 1 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_1]], align 1 -// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_1:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_1]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_1:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_1]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_1]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] -// CHECK: [[POINTER_TO_ERASED_TABLE_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 -// CHECK: [[ERASED_TABLE_2:%"load argument at index 2 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_2]], align 1 -// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_2:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_2]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_2:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_2]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_2]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1QAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] -// CHECK: [[POINTER_TO_ERASED_TABLE_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 -// CHECK: [[ERASED_TABLE_3:%"load argument at index 3 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_3]], align 1 -// CHECK: [[UNERASED_TABLE_3:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_3]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_3]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_3:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_3]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_3:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_3]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_3]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_3:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1RAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_3:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_2]], [[EQUAL_DESCRIPTORS_3]] -// CHECK: [[POINTER_TO_ERASED_TABLE_4:%[0-9]+]] = getelementptr i8*, i8** %1, i64 4 -// CHECK: [[ERASED_TABLE_4:%"load argument at index 4 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_4]], align 1 -// CHECK: [[UNERASED_TABLE_4:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_4]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_4]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_4:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_4]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_4:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_4]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_4:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_4]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_4:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_4]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_4:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_4]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_4:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_4]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_4:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_4]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_4:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_4]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1SAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_4:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_3]], [[EQUAL_DESCRIPTORS_4]] -// CHECK: [[POINTER_TO_ERASED_TABLE_5:%[0-9]+]] = getelementptr i8*, i8** %1, i64 5 -// CHECK: [[ERASED_TABLE_5:%"load argument at index 5 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_5]], align 1 -// CHECK: [[UNERASED_TABLE_5:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_5]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_5:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_5]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_5:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_5]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_5:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_5]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_5:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_5]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_5:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_5]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_5:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_5]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_5:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_5]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_5:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_5]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_5:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_5]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_5:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_5]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1TAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_5:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_4]], [[EQUAL_DESCRIPTORS_5]] -// CHECK: br i1 [[EQUAL_ARGUMENTS_5]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift index 3a98fe75c3016..01ce8938f9e44 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift @@ -123,38 +123,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: br i1 [[EQUAL_TYPES_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_3:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3]] -// CHECK: br i1 [[EQUAL_TYPES_3]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[TYPE_COMPARISON_4:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_4]]: -// CHECK: [[EQUAL_TYPE_4:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss5UInt8VN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_4:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_4]] -// CHECK: br i1 [[EQUAL_TYPES_4]], label %[[EXIT_PRESPECIALIZED_4:[0-9]+]], label %[[TYPE_COMPARISON_5:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_5]]: -// CHECK: [[EQUAL_TYPE_5:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss4Int8VN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_5:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_5]] -// CHECK: br i1 [[EQUAL_TYPES_5]], label %[[EXIT_PRESPECIALIZED_5:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_4]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVys5UInt8VGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_5]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVys4Int8VGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift index f4e8311a2ebf1..8353f4754477b 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift @@ -70,35 +70,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32{{(, \[4 x i8\])?}}, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceC5ValueVySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift index 1a789c3b3e237..823d3363802d7 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift @@ -70,35 +70,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32{{(, \[4 x i8\])?}}, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceO5ValueVySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift index 2a28be73413a7..f0146c3df4869 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift @@ -70,34 +70,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, %swift.type*, -// CHECK-SAME: i32{{(, \[4 x i8\])?}}, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceV5ValueVySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift index 9d8885fb6b3da..ce004e7edd3b3 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift @@ -77,36 +77,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* [[TYPE_1]] to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* [[TYPE_2]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32, -// CHECK-SAME: {{(\[4 x i8\],)?}} -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceVAAq_RszrlE5ValueVyS2i_SSGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift index eba0602f76ed8..f05de23860d43 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift @@ -47,16 +47,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVyS2iGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift index 4e862e3793f8b..ecd49ed9f9acd 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift @@ -68,24 +68,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_2_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2_1]] -// CHECK: [[EQUAL_TYPE_2_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_2_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_2_1]], [[EQUAL_TYPE_2_2]] -// CHECK: br i1 [[EQUAL_TYPES_2_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVyS2iGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySdSiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift index c3ca169770277..76c86eeca2c56 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift @@ -89,32 +89,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_2_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2_1]] -// CHECK: [[EQUAL_TYPE_2_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_2_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_2_1]], [[EQUAL_TYPE_2_2]] -// CHECK: br i1 [[EQUAL_TYPES_2_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_3_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3_1]] -// CHECK: [[EQUAL_TYPE_3_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_3_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_3_1]], [[EQUAL_TYPE_3_2]] -// CHECK: br i1 [[EQUAL_TYPES_3_2]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVyS2iGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySdSiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySSSdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift index 47ba39cc3dd87..2f3d4fb8f9fd3 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift @@ -110,40 +110,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_2_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2_1]] -// CHECK: [[EQUAL_TYPE_2_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_2_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_2_1]], [[EQUAL_TYPE_2_2]] -// CHECK: br i1 [[EQUAL_TYPES_2_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_3_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3_1]] -// CHECK: [[EQUAL_TYPE_3_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_3_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_3_1]], [[EQUAL_TYPE_3_2]] -// CHECK: br i1 [[EQUAL_TYPES_3_2]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[TYPE_COMPARISON_4:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_4]]: -// CHECK: [[EQUAL_TYPE_4_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss5UInt8VN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_4_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_4_1]] -// CHECK: [[EQUAL_TYPE_4_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_4_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_4_1]], [[EQUAL_TYPE_4_2]] -// CHECK: br i1 [[EQUAL_TYPES_4_2]], label %[[EXIT_PRESPECIALIZED_4:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVyS2iGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySdSiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySSSdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_4]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVys5UInt8VSSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift index d71408f206a8a..e0b53ad251296 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift @@ -184,48 +184,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_2_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2_1]] -// CHECK: [[EQUAL_TYPE_2_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_2_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_2_1]], [[EQUAL_TYPE_2_2]] -// CHECK: br i1 [[EQUAL_TYPES_2_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_3_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3_1]] -// CHECK: [[EQUAL_TYPE_3_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_3_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_3_1]], [[EQUAL_TYPE_3_2]] -// CHECK: br i1 [[EQUAL_TYPES_3_2]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[TYPE_COMPARISON_4:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_4]]: -// CHECK: [[EQUAL_TYPE_4_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss5UInt8VN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_4_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_4_1]] -// CHECK: [[EQUAL_TYPE_4_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_4_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_4_1]], [[EQUAL_TYPE_4_2]] -// CHECK: br i1 [[EQUAL_TYPES_4_2]], label %[[EXIT_PRESPECIALIZED_4:[0-9]+]], label %[[TYPE_COMPARISON_5:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_5]]: -// CHECK: [[EQUAL_TYPE_5_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss4Int8VN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_5_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_5_1]] -// CHECK: [[EQUAL_TYPE_5_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss5UInt8VN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_5_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_5_1]], [[EQUAL_TYPE_5_2]] -// CHECK: br i1 [[EQUAL_TYPES_5_2]], label %[[EXIT_PRESPECIALIZED_5:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVyS2iGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySdSiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySSSdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_4]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVys5UInt8VSSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_5]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVys4Int8Vs5UInt8VGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift index 670d11205f865..1ebeb321ede26 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift @@ -50,18 +50,6 @@ doit() // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* // CHECK: [[ERASED_TYPE_3:%[0-9]+]] = bitcast %swift.type* %3 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: [[EQUAL_TYPE_1_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_3]] -// CHECK: [[EQUAL_TYPES_1_3:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_2]], [[EQUAL_TYPE_1_3]] -// CHECK: br i1 [[EQUAL_TYPES_1_3]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main9NamespaceC5ValueVySS_SiSdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* [[ERASED_TYPE_3]], %swift.type_descriptor* bitcast ({{.+}}$s4main9NamespaceC5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift index 62294db3ba1c6..b870255458401 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift @@ -3,12 +3,38 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s7Generic11OneArgumentVy0C07IntegerVGMN" = +// CHECK: @"$s7Generic11OneArgumentVy0C07IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s7Generic11OneArgumentVy0C07IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s7Generic11OneArgumentVMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -20,8 +46,31 @@ import Generic import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s7Generic11OneArgumentVy0C07IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s7Generic11OneArgumentVy0C07IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s7Generic11OneArgumentVy0C07IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift index acb5c56c5b943..7eb0f7a6cbc60 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift @@ -2,12 +2,38 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument.swift %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s8Argument03OneA0VyAA7IntegerVGMN" = +// CHECK: @"$s8Argument03OneA0VyAA7IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s8Argument03OneA0VyAA7IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s8Argument03OneA0VMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -18,8 +44,31 @@ func consume(_ t: T) { import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s8Argument03OneA0VyAA7IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s8Argument03OneA0VyAA7IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s8Argument03OneA0VyAA7IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift index 2718c56287e14..7c7b6fee27917 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift @@ -2,12 +2,40 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument-1constraint.swift %S/Inputs/protocol-public-empty.swift %S/Inputs/struct-public-nonfrozen-0argument.swift %S/Inputs/struct-public-nonfrozen-0argument-conformance-empty.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s8Argument03OneA0VyAA7IntegerVGMN" = +// CHECK: @"$s8Argument03OneA0VyAA7IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i8**, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s8Argument03OneA0VyAA7IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s8Argument03OneA0VMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i8** @"$s8Argument7IntegerVAA1PAAWP", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -18,8 +46,31 @@ func consume(_ t: T) { import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s8Argument03OneA0VyAA7IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s8Argument03OneA0VyAA7IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s8Argument03OneA0VyAA7IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift index 1cb2721fcc829..72abaf85836c3 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift @@ -3,12 +3,40 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument-conformance-empty.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule -DIMPORT_MODULE -L %t -I %t -lModule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lModule -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GMN" = +// CHECK: @"$s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i8**, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME:}> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s6Module11OneArgumentVMn +// : ", +// CHECK-SAME: %swift.type* @"$s6Module7IntegerVN", +// CHECK-SAME: i8** @"$s6Module7IntegerVAA1P8ArgumentWP", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME:}>, +// CHECK-SAME:align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -20,8 +48,31 @@ import Module import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift index ed8be0746ef1c..fa2a5a13b909b 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift @@ -2,12 +2,40 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument-1constraint.swift %S/Inputs/protocol-public-empty.swift %S/Inputs/struct-public-nonfrozen-0argument.swift %S/Inputs/struct-public-nonfrozen-0argument-conformance-empty.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s8Argument03OneA0VyAA7IntegerVGMN" = +// CHECK: @"$s8Argument03OneA0VyAA7IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i8**, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s8Argument03OneA0VyAA7IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s8Argument03OneA0VMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i8** @"$s8Argument7IntegerVAA1PAAWP", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -18,8 +46,31 @@ func consume(_ t: T) { import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s8Argument03OneA0VyAA7IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s8Argument03OneA0VyAA7IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s8Argument03OneA0VyAA7IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_inmodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_inmodule.swift index 8eb393cff6030..27e8384319d0e 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_inmodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_inmodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument-1constraint.swift %S/Inputs/struct-public-nonfrozen-0argument.swift %S/Inputs/protocol-public-empty.swift -emit-library -o %t/%target-library-name(Module) -emit-module -module-name Module -emit-module-path %t/Module.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s %S/Inputs/main.swift %S/Inputs/struct-public-nonfrozen-0argument-conformance-empty.swift -module-name main -L %t -I %t -lModule -DIMPORT_MODULE | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift index bf23059dbf86f..274c6720d5d4f 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift @@ -3,12 +3,48 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s6Module11TwoArgumentVyAA7IntegerV0C0ADVGMN" = +// CHECK: @"$s6Module11TwoArgumentVyAA7IntegerV0C0ADVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// : [ +// : 4 x i8 +// : ], +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s6Module11TwoArgumentVyAA7IntegerV0C0ADVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s6Module11TwoArgumentVMn +// : ", +// CHECK-SAME: %swift.type* @"$s6Module7IntegerVN", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i32 {{8|16}}, +// : [ +// : 4 x i8 +// : ] zeroinitializer, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -20,8 +56,31 @@ import Module import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s6Module11TwoArgumentVyAA7IntegerV0C0ADVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s6Module11TwoArgumentVyAA7IntegerV0C0ADVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s6Module11TwoArgumentVyAA7IntegerV0C0ADVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( TwoArgument(Module.Integer(13), Argument.Integer(17)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift index b751ee9562f7e..969903ee58540 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift @@ -2,12 +2,48 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-2argument.swift %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s8Argument03TwoA0VyAA7IntegerVGMN" = +// CHECK: @"$s8Argument03TwoA0VyAA7IntegerVAEGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// : [ +// : 4 x i8 +// : ], +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s8Argument03TwoA0VyAA7IntegerVAEGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s8Argument03TwoA0VMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i32 {{8|16}}, +// : [ +// : 4 x i8 +// : ] zeroinitializer, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -18,8 +54,31 @@ func consume(_ t: T) { import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s8Argument03TwoA0VyAA7IntegerVAEGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s8Argument03TwoA0VyAA7IntegerVAEGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s8Argument03TwoA0VyAA7IntegerVAEGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( TwoArgument(Integer(13), Integer(17)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-inmodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-inmodule.swift index 1a265a9b0f50e..d7aa427dc3a29 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-inmodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-inmodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-frozen-1argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift index cf8a51c1899c2..7c5fff2d942b0 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift @@ -3,12 +3,38 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-frozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s7Generic11OneArgumentVy0C07IntegerVGMN" = +// CHECK: @"$s7Generic11OneArgumentVy0C07IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s7Generic11OneArgumentVy0C07IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s7Generic11OneArgumentVMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -20,8 +46,31 @@ import Generic import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s7Generic11OneArgumentVy0C07IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s7Generic11OneArgumentVy0C07IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s7Generic11OneArgumentVy0C07IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift index c7f22edd10d3d..c04ed4041ee8b 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift @@ -2,12 +2,38 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-frozen-1argument.swift %S/Inputs/struct-public-frozen-0argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s7Generic11OneArgumentVyAA7IntegerVGMN" = +// CHECK: @"$s7Generic11OneArgumentVyAA7IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s7Generic11OneArgumentVyAA7IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s7Generic11OneArgumentVMn +// : ", +// CHECK-SAME: %swift.type* @"$s7Generic7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -18,8 +44,31 @@ func consume(_ t: T) { import Generic // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s7Generic11OneArgumentVyAA7IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s7Generic11OneArgumentVyAA7IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s7Generic11OneArgumentVyAA7IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift index ea1bea95dedea..f74fe5876a098 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift @@ -3,7 +3,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift index d22e9c5cd0b6c..996489fc04bce 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-frozen-1argument.swift %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-inmodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-inmodule.swift index 61c1b5ad442c9..6771fb3b0cd83 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-inmodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-inmodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift index 134583e4f087f..e5208842c7af0 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift @@ -3,7 +3,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-frozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift index e39afa70a6c25..bba412fdb884c 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument.swift %S/Inputs/struct-public-frozen-0argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-othermodule.swift index 1e22b5a2e2881..40f664a6485c5 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-othermodule.swift @@ -3,7 +3,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift index 6748988669cfc..30f5516f3e4e0 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift @@ -3,7 +3,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift index 82a8faad31f3a..13e49953570e0 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument.swift %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift index e02b67617cea8..99d00c6711936 100644 --- a/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift @@ -45,14 +45,6 @@ doit() // CHECK: define{{( protected| dllexport)?}} swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/unused.sil b/test/IRGen/unused.sil index e15b50531c5d1..8b0d06fb0e7a3 100644 --- a/test/IRGen/unused.sil +++ b/test/IRGen/unused.sil @@ -56,7 +56,7 @@ bb0(%0 : $Int32, %1 : $UnsafeMutablePointer> // CHECK-elf: @"\01l_entry_point" = private constant { i32 } { i32 trunc (i64 sub (i64 ptrtoint (i32 (i32, i8**)* @main to i64), i64 ptrtoint ({ i32 }* @"\01l_entry_point" to i64)) to i32) }, section "swift5_entry", align 4 // CHECK-macho: @llvm.used = appending global [4 x i8*] [i8* bitcast (void ()* @frieda to i8*), i8* bitcast (i32 (i32, i8**)* @main to i8*), i8* bitcast ({ i32 }* @"\01l_entry_point" to i8*), i8* bitcast (i16* @__swift_reflection_version to i8*)], section "llvm.metadata", align 8 -// CHECK-elf: @llvm.used = appending global [5 x i8*] [i8* bitcast (void ()* @frieda to i8*), i8* bitcast (i32 (i32, i8**)* @main to i8*), i8* bitcast ({ i32 }* @"\01l_entry_point" to i8*), i8* bitcast (i16* @__swift_reflection_version to i8*), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @_swift1_autolink_entries, i32 0, i32 0)], section "llvm.metadata", align 8 +// CHECK-elf: @llvm.used = appending global [5 x i8*] [i8* bitcast (void ()* @frieda to i8*), i8* bitcast (i32 (i32, i8**)* @main to i8*), i8* bitcast ({ i32 }* @"\01l_entry_point" to i8*), i8* bitcast (i16* @__swift_reflection_version to i8*), i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* @_swift1_autolink_entries, i32 0, i32 0)], section "llvm.metadata", align 8 // CHECK: define linkonce_odr hidden swiftcc void @qux() // CHECK: define hidden swiftcc void @fred() diff --git a/test/Incremental/Verifier/single-file-private/AnyObject.swift b/test/Incremental/Verifier/single-file-private/AnyObject.swift index 2e80b90832cab..ff93b85405252 100644 --- a/test/Incremental/Verifier/single-file-private/AnyObject.swift +++ b/test/Incremental/Verifier/single-file-private/AnyObject.swift @@ -25,7 +25,6 @@ import Foundation // expected-private-conformance {{Swift.CVarArg}} // expected-private-conformance {{Swift.CustomStringConvertible}} // expected-private-member {{Swift._ExpressibleByBuiltinIntegerLiteral.init}} -// expected-private-superclass {{main.LookupFactory}} @objc private class LookupFactory: NSObject { // expected-provides {{AssignmentPrecedence}} // expected-provides {{IntegerLiteralType}} diff --git a/test/Incremental/Verifier/single-file/AnyObject.swift b/test/Incremental/Verifier/single-file/AnyObject.swift index 63a5e55f68007..0130674af6552 100644 --- a/test/Incremental/Verifier/single-file/AnyObject.swift +++ b/test/Incremental/Verifier/single-file/AnyObject.swift @@ -25,7 +25,6 @@ import Foundation // expected-private-conformance {{Swift.CVarArg}} // expected-private-conformance {{Swift.CustomStringConvertible}} // expected-cascading-member {{Swift._ExpressibleByBuiltinIntegerLiteral.init}} -// expected-cascading-superclass {{main.LookupFactory}} @objc private class LookupFactory: NSObject { // expected-provides {{AssignmentPrecedence}} // expected-provides {{IntegerLiteralType}} diff --git a/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h b/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h new file mode 100644 index 0000000000000..b03e3530a4968 --- /dev/null +++ b/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h @@ -0,0 +1,16 @@ +@import Foundation; +@import ctypes; + +#pragma clang assume_nonnull begin + +@interface SlowServer : NSObject +-(void)doSomethingSlow:(NSString *)operation completionHandler:(void (^)(NSInteger))handler; +-(void)doSomethingDangerous:(NSString *)operation completionHandler:(void (^ _Nullable)(NSString *_Nullable, NSError * _Nullable))handler; +-(void)checkAvailabilityWithCompletionHandler:(void (^)(BOOL isAvailable))completionHandler; +-(void)findAnswerAsynchronously:(void (^)(NSString *_Nullable, NSError * _Nullable))handler __attribute__((swift_name("findAnswer(completionHandler:)"))); +-(BOOL)findAnswerFailinglyWithError:(NSError * _Nullable * _Nullable)error completion:(void (^)(NSString *_Nullable, NSError * _Nullable))handler __attribute__((swift_name("findAnswerFailingly(completionHandler:)"))); +-(void)doSomethingFun:(NSString *)operation then:(void (^)(void))completionHandler; +@property(readwrite) void (^completionHandler)(NSInteger); +@end + +#pragma clang assume_nonnull end diff --git a/test/Inputs/clang-importer-sdk/usr/include/module.map b/test/Inputs/clang-importer-sdk/usr/include/module.map index 61b062ab524eb..366101cbbb723 100644 --- a/test/Inputs/clang-importer-sdk/usr/include/module.map +++ b/test/Inputs/clang-importer-sdk/usr/include/module.map @@ -136,3 +136,8 @@ module WinBOOL { header "winbool.h" export * } + +module ObjCConcurrency { + header "ObjCConcurrency.h" + export * +} \ No newline at end of file diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift index fcbf32cff73d5..c0a48574a1493 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift @@ -29,7 +29,6 @@ public func testStructWithCopyConstructorAndValue() -> Bool { // CHECK: [[MEMBER_ELEMENT:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], i32 0, i32 0 // CHECK: [[MEMBER_VALUE:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[MEMBER_ELEMENT]], i32 0, i32 0 // CHECK: store i32 42, i32* [[MEMBER_VALUE]] -// CHECK: %obj.member = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 // CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TMP]], i32 0, i32 0 // CHECK: [[TEMP_MEMBER_VALUE:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[TEMP_MEMBER]], i32 0, i32 0 // CHECK: [[LHS:%.*]] = load i32, i32* [[TEMP_MEMBER_VALUE]] diff --git a/test/Interop/Cxx/reference/reference.swift b/test/Interop/Cxx/reference/reference.swift index 71d211b04761c..278f06a23281e 100644 --- a/test/Interop/Cxx/reference/reference.swift +++ b/test/Interop/Cxx/reference/reference.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-clang -c %S/Inputs/reference.cpp -I %S/Inputs -o %t/reference.o -std=c++17 -// RUN: %target-build-swift %s -I %S/Inputs -o %t/reference %t/reference.o -Xfrontend -enable-cxx-interop -Xcc -std=c++17 +// RUN: %target-build-swift %s -I %S/Inputs -o %t/reference %t/reference.o -Xfrontend -enable-cxx-interop // RUN: %target-codesign %t/reference // RUN: %target-run %t/reference // diff --git a/test/Interop/Cxx/static/constexpr-static-member-var.swift b/test/Interop/Cxx/static/constexpr-static-member-var.swift index e40cddf397282..77f15f321666f 100644 --- a/test/Interop/Cxx/static/constexpr-static-member-var.swift +++ b/test/Interop/Cxx/static/constexpr-static-member-var.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-clang -c %S/Inputs/static-member-var.cpp -I %S/Inputs -o %t/static-member-var.o -std=c++17 -// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-member-var.o -Xfrontend -enable-cxx-interop -Xcc -std=c++17 +// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-member-var.o -Xfrontend -enable-cxx-interop // RUN: %target-codesign %t/statics // RUN: %target-run %t/statics // diff --git a/test/Interop/Cxx/static/inline-static-member-var.swift b/test/Interop/Cxx/static/inline-static-member-var.swift index 76e7a1d9b09f0..052f362840329 100644 --- a/test/Interop/Cxx/static/inline-static-member-var.swift +++ b/test/Interop/Cxx/static/inline-static-member-var.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-clang -c %S/Inputs/inline-static-member-var.cpp -I %S/Inputs -o %t/inline-static-member-var.o -std=c++17 -// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/inline-static-member-var.o -Xfrontend -enable-cxx-interop -Xcc -std=c++17 +// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/inline-static-member-var.o -Xfrontend -enable-cxx-interop // RUN: %target-codesign %t/statics // RUN: %target-run %t/statics 2&>1 // diff --git a/test/Interop/Cxx/static/static-var.swift b/test/Interop/Cxx/static/static-var.swift index 0528af17f35a2..9b66cadf22501 100644 --- a/test/Interop/Cxx/static/static-var.swift +++ b/test/Interop/Cxx/static/static-var.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-clang -c %S/Inputs/static-var.cpp -I %S/Inputs -o %t/static-var.o -std=c++17 -// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-var.o -Xfrontend -enable-cxx-interop -Xcc -std=c++17 +// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-var.o -Xfrontend -enable-cxx-interop // RUN: %target-codesign %t/statics // RUN: %target-run %t/statics // diff --git a/test/Interop/Cxx/templates/Inputs/canonical-types.h b/test/Interop/Cxx/templates/Inputs/canonical-types.h new file mode 100644 index 0000000000000..865c85a882cf9 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/canonical-types.h @@ -0,0 +1,18 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +typedef MagicWrapper WrappedMagicNumberA; +typedef MagicWrapper WrappedMagicNumberB; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h b/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h new file mode 100644 index 0000000000000..4c772c9dfaca0 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h @@ -0,0 +1,26 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +inline int forceInstantiation() { + auto t = MagicWrapper(); + return t.getValuePlusArg(14); +} + +// The ClassTemplateSpecializationDecl node for MagicWrapper already has a definition +// because function above forced the instantiation. Its members are fully +// instantiated, so nothing needs to be explicitly instantiated by the Swift +// compiler. +typedef MagicWrapper FullyDefinedMagicallyWrappedInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-definition.h b/test/Interop/Cxx/templates/Inputs/decl-with-definition.h new file mode 100644 index 0000000000000..d8fb7b56f676b --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-definition.h @@ -0,0 +1,24 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +inline MagicWrapper forceInstantiation() { + return MagicWrapper(); +} + +// The ClassTemplateSpecializationDecl node for MagicWrapper already has a definition +// because function above forced the instantiation. Its members are not +// instantiated though, the Swift compiler needs to instantiate them. +typedef MagicWrapper PartiallyDefinedMagicallyWrappedInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h b/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h new file mode 100644 index 0000000000000..2bba7d493e342 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h @@ -0,0 +1,12 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t + arg; } +}; + +typedef MagicWrapper WrappedMagicInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-without-definition.h b/test/Interop/Cxx/templates/Inputs/decl-without-definition.h new file mode 100644 index 0000000000000..a4eb3506672b2 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-without-definition.h @@ -0,0 +1,20 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +// The ClassTemplateSpecializationDecl node for MagicWrapper doesn't have a +// definition in Clang because nothing in this header required the +// instantiation. Therefore, the Swift compiler must trigger instantiation. +typedef MagicWrapper MagicallyWrappedIntWithoutDefinition; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H diff --git a/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h b/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h new file mode 100644 index 0000000000000..5992054ae9d3d --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h @@ -0,0 +1,24 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H + +struct MagicNumber { + int getInt() const { return 42; } +}; + +template +struct MagicWrapper { + void callGetInt() const { + T::getIntDoesNotExist(); + } + + template int sfinaeGetInt(A a, decltype(&A::getInt)) { + return a.getInt(); + } + template int sfinaeGetInt(A a, ...) { + return -42; + } +}; + +typedef MagicWrapper BrokenMagicWrapper; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H diff --git a/test/Interop/Cxx/templates/Inputs/explicit-specialization.h b/test/Interop/Cxx/templates/Inputs/explicit-specialization.h new file mode 100644 index 0000000000000..62b9f7aa030af --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/explicit-specialization.h @@ -0,0 +1,29 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H + +struct SpecializedIntWrapper { + int value; + int getValue() const { return value; } +}; + +struct NonSpecializedIntWrapper { + int value; + int getValue() const { return value; } +}; + +template +struct MagicWrapper { + T t; + int doubleIfSpecializedElseTriple() const { return 3 * t.getValue(); } +}; + +template <> +struct MagicWrapper { + SpecializedIntWrapper t; + int doubleIfSpecializedElseTriple() const { return 2 * t.getValue(); } +}; + +typedef MagicWrapper WrapperWithSpecialization; +typedef MagicWrapper WrapperWithoutSpecialization; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H diff --git a/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h b/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h new file mode 100644 index 0000000000000..d700209d93873 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h @@ -0,0 +1,21 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H + +template +struct MagicWrapper { + T t; + int callGetInt() const { + return t.getInt() + 5; + } +}; + +struct MagicNumber { + // Swift runtime defines many value witness tables for types with some common layouts. + // This struct's uncommon size forces the compiler to define a new value witness table instead of reusing one from the runtime. + char forceVWTableCreation[57]; + int getInt() const { return 12; } +}; + +typedef MagicWrapper WrappedMagicNumber; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H diff --git a/test/Interop/Cxx/templates/Inputs/mangling.h b/test/Interop/Cxx/templates/Inputs/mangling.h new file mode 100644 index 0000000000000..f135b52747600 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/mangling.h @@ -0,0 +1,11 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H + +template +struct MagicWrapper {}; + +typedef MagicWrapper WrappedMagicInt; +typedef MagicWrapper WrappedMagicBool; + + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H diff --git a/test/Interop/Cxx/templates/Inputs/module.modulemap b/test/Interop/Cxx/templates/Inputs/module.modulemap new file mode 100644 index 0000000000000..af6d28e675a40 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/module.modulemap @@ -0,0 +1,39 @@ +module DeclWithPrimitiveArgument { + header "decl-with-primitive-argument.h" +} + +module DeclWithoutDefinition { + header "decl-without-definition.h" +} + +module DeclWithDefinition { + header "decl-with-definition.h" +} + +module DeclWithDefinitionIncludingMembers { + header "decl-with-definition-including-members.h" +} + +module CanonicalTypes { + header "canonical-types.h" +} + +module ExplicitSpecialization { + header "explicit-specialization.h" +} + +module UsingDirective { + header "using-directive.h" +} + +module EagerInstantiationProblems { + header "eager-instantiation-problems.h" +} + +module Mangling { + header "mangling.h" +} + +module LinkageOfSwiftSymbolsForImportedTypes { + header "linkage-of-swift-symbols-for-imported-types.h" +} diff --git a/test/Interop/Cxx/templates/Inputs/using-directive.h b/test/Interop/Cxx/templates/Inputs/using-directive.h new file mode 100644 index 0000000000000..076660e8a19e4 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/using-directive.h @@ -0,0 +1,17 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +using UsingWrappedMagicNumber = MagicWrapper; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H diff --git a/test/Interop/Cxx/templates/canonical-types-module-interface.swift b/test/Interop/Cxx/templates/canonical-types-module-interface.swift new file mode 100644 index 0000000000000..3a90d1d44311a --- /dev/null +++ b/test/Interop/Cxx/templates/canonical-types-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=CanonicalTypes -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias WrappedMagicNumberA = __CxxTemplateInst12MagicWrapperI10IntWrapperE +// CHECK: typealias WrappedMagicNumberB = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/canonical-types.swift b/test/Interop/Cxx/templates/canonical-types.swift new file mode 100644 index 0000000000000..6f11ea61ca8e5 --- /dev/null +++ b/test/Interop/Cxx/templates/canonical-types.swift @@ -0,0 +1,15 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import CanonicalTypes +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("canonical-types") { + // Different typedefs with the same C++ canonical type must have the same type from Swift's perspective as well. + expectEqualType(WrappedMagicNumberA.self, WrappedMagicNumberB.self) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-definition-including-members.swift b/test/Interop/Cxx/templates/decl-with-definition-including-members.swift new file mode 100644 index 0000000000000..8c7dcf7013557 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-including-members.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import DeclWithDefinitionIncludingMembers +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("fully-defined") { + let myInt = IntWrapper(value: 10) + var magicInt = FullyDefinedMagicallyWrappedInt(t: myInt) + expectEqual(magicInt.getValuePlusArg(5), 15) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-definition-irgen.swift b/test/Interop/Cxx/templates/decl-with-definition-irgen.swift new file mode 100644 index 0000000000000..d69ece5914b55 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-irgen.swift @@ -0,0 +1,33 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s +// REQUIRES: rdar67257133 +import DeclWithDefinition + +public func getWrappedMagicInt() -> CInt { + let myInt = IntWrapper(value: 7) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + return magicInt.getValuePlusArg(13) +} + +// CHECK: define {{(protected |dllexport )?}}swiftcc i32 @"$s4main18getWrappedMagicInts5Int32VyF"() +// CHECK: %magicInt = alloca %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV, align 4 +// CHECK: %magicInt.t = getelementptr inbounds %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV, %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV* %magicInt, i32 0, i32 0 +// CHECK: [[MAGIC_WRAPPER:%.*]] = bitcast %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV* %magicInt to %struct.MagicWrapper* +// CHECK: call i32 @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|"\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z"}}(%struct.MagicWrapper* [[MAGIC_WRAPPER]], i32 13) + +// CHECK: define weak_odr{{( dso_local)?}} i32 @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|"\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z"}}(%struct.MagicWrapper* %this, i32 %arg) +// CHECK: %this.addr = alloca %struct.MagicWrapper*, align {{4|8}} +// CHECK: store %struct.MagicWrapper* %this, %struct.MagicWrapper** %this.addr, align {{4|8}} +// CHECK: %this1 = load %struct.MagicWrapper*, %struct.MagicWrapper** %this.addr, align {{4|8}} +// CHECK: %t = getelementptr inbounds %struct.MagicWrapper, %struct.MagicWrapper* %this1, i32 0, i32 0 +// CHECK: %call = call i32 @{{_ZNK10IntWrapper8getValueEv|"\?getValue@IntWrapper@@QEBAHXZ"}}(%struct.IntWrapper* %t) +// CHECK: [[ARG:%.*]] = load i32, i32* %arg.addr, align 4 +// CHECK: %add = add nsw i32 %call, [[ARG]] +// CHECK: ret i32 %add + +// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_ZNK10IntWrapper8getValueEv|"\?getValue@IntWrapper@@QEBAHXZ"}}(%struct.IntWrapper* %this) +// CHECK: %this.addr = alloca %struct.IntWrapper*, align {{4|8}} +// CHECK: store %struct.IntWrapper* %this, %struct.IntWrapper** %this.addr, align {{4|8}} +// CHECK: %this1 = load %struct.IntWrapper*, %struct.IntWrapper** %this.addr, align {{4|8}} +// CHECK: %value = getelementptr inbounds %struct.IntWrapper, %struct.IntWrapper* %this1, i32 0, i32 0 +// CHECK: [[VALUE:%.*]] = load i32, i32* %value, align 4 +// CHECK: ret i32 [[VALUE]] diff --git a/test/Interop/Cxx/templates/decl-with-definition-silgen.swift b/test/Interop/Cxx/templates/decl-with-definition-silgen.swift new file mode 100644 index 0000000000000..a9481f6ac9d6c --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-silgen.swift @@ -0,0 +1,21 @@ +// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import DeclWithDefinition + +public func getWrappedMagicInt() -> CInt { + let myInt = IntWrapper(value: 21) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + return magicInt.getValuePlusArg(32) +} + +// CHECK: // getWrappedMagicInt() +// CHECK: sil @$s4main18getWrappedMagicInts5Int32VyF : $@convention(thin) () -> Int32 { +// CHECK: [[INT_WRAPPER:%.*]] = struct $IntWrapper ([[_:%.*]] : $Int32) +// CHECK: [[_:%.*]] = struct $__CxxTemplateInst12MagicWrapperI10IntWrapperE ([[INT_WRAPPER]] : $IntWrapper) +// CHECK: // function_ref {{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} +// CHECK: [[_:%.*]] = function_ref @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} : $@convention(c) (@inout __CxxTemplateInst12MagicWrapperI10IntWrapperE, Int32) -> Int32 + +// CHECK: // {{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} +// CHECK: MagicWrapper::getValuePlusArg + +// CHECK: sil [clang __CxxTemplateInst12MagicWrapperI10IntWrapperE.getValuePlusArg] @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} : $@convention(c) (@inout __CxxTemplateInst12MagicWrapperI10IntWrapperE, Int32) -> Int32 diff --git a/test/Interop/Cxx/templates/decl-with-definition.swift b/test/Interop/Cxx/templates/decl-with-definition.swift new file mode 100644 index 0000000000000..3772cd4f7a99a --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import DeclWithDefinition +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("has-partial-definition") { + let myInt = IntWrapper(value: 32) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + expectEqual(magicInt.getValuePlusArg(5), 37) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-primitive-argument.swift b/test/Interop/Cxx/templates/decl-with-primitive-argument.swift new file mode 100644 index 0000000000000..951c49c0fb814 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-primitive-argument.swift @@ -0,0 +1,15 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import DeclWithPrimitiveArgument +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("int-argument") { + var wrappedMagicInt = WrappedMagicInt(t: 42) + expectEqual(wrappedMagicInt.getValuePlusArg(5), 47) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift b/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift new file mode 100644 index 0000000000000..ca12841f96cb9 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=DeclWithoutDefinition -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: init(value: Int32) +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias MagicallyWrappedIntWithoutDefinition = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/decl-without-definition.swift b/test/Interop/Cxx/templates/decl-without-definition.swift new file mode 100644 index 0000000000000..23eca83c31d85 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-without-definition.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import DeclWithoutDefinition +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("without-definition") { + let myInt = IntWrapper(value: 17) + var magicInt = MagicallyWrappedIntWithoutDefinition(t: myInt) + expectEqual(magicInt.getValuePlusArg(11), 28) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/eager-instatiation-problems.swift b/test/Interop/Cxx/templates/eager-instatiation-problems.swift new file mode 100644 index 0000000000000..f341c8c68c87c --- /dev/null +++ b/test/Interop/Cxx/templates/eager-instatiation-problems.swift @@ -0,0 +1,32 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import EagerInstantiationProblems +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("eager-instantiation-of-members") { + // This will fail with: + // + // error: type 'int' cannot be used prior to '::' because it has no members + // T::getIntDoesNotExist(); + // + // whereas in C++ this compiles. This is caused by ClangImporter eagerly + // instantiating typedeffed templates and also their members. + // TODO(scentini): Fix this + // let _brokenMagicWrapper = BrokenMagicWrapper() +} + +TemplatesTestSuite.test("sfinae-example") { + // This will fail since we are currently not instantiating function templates. + // In C++ the first sfinaeGetInt should fail to instantiate, therefore get + // ignored, and only the second sfinaeGetInt is used. + // TODO(SR-12541): Fix this + // let magicNumber = MagicNumber() + // var brokenMagicWrapper = BrokenMagicWrapper() + // expectEqual(42, brokenMagicWrapper.sfinaeGetInt(magicNumber, 0)) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/explicit-specialization.swift b/test/Interop/Cxx/templates/explicit-specialization.swift new file mode 100644 index 0000000000000..b8e02faefe85b --- /dev/null +++ b/test/Interop/Cxx/templates/explicit-specialization.swift @@ -0,0 +1,20 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import ExplicitSpecialization +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("explicit-specialization") { + let specializedInt = SpecializedIntWrapper(value: 7) + var specializedMagicInt = WrapperWithSpecialization(t: specializedInt) + expectEqual(specializedMagicInt.doubleIfSpecializedElseTriple(), 14) + + let nonSpecializedInt = NonSpecializedIntWrapper(value: 7) + var nonSpecializedMagicInt = WrapperWithoutSpecialization(t: nonSpecializedInt) + expectEqual(nonSpecializedMagicInt.doubleIfSpecializedElseTriple(), 21) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift b/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift new file mode 100644 index 0000000000000..f3a2ae75d69ba --- /dev/null +++ b/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift @@ -0,0 +1,28 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import LinkageOfSwiftSymbolsForImportedTypes + +public func forceValueWitnessTableCreation() -> Any { + let magicNumber = MagicNumber() + return WrappedMagicNumber(t: magicNumber) +} + +public func getMagicNumberForLinkageComparison() -> Any { + return MagicNumber() +} + +// CHECK: $sSo11MagicNumberVWV" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMn" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMf" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVML" = linkonce_odr hidden global + +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVWV" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMn" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMf" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVML" = linkonce_odr hidden global + +// CHECK: $sSo11MagicNumberVMB" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMF" = linkonce_odr hidden constant + +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMB" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMF" = linkonce_odr hidden constant diff --git a/test/Interop/Cxx/templates/mangling-irgen.swift b/test/Interop/Cxx/templates/mangling-irgen.swift new file mode 100644 index 0000000000000..c55feb8b5dc47 --- /dev/null +++ b/test/Interop/Cxx/templates/mangling-irgen.swift @@ -0,0 +1,20 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import Mangling + +public func receiveInstantiation(_ i: inout WrappedMagicInt) {} + +// Don't forget to update manglings.txt when changing s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF"(%TSo34__CxxTemplateInst12MagicWrapperIiEV* nocapture dereferenceable(1) %0) + +public func receiveInstantiation(_ i: inout WrappedMagicBool) {} + +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIbEVzF"(%TSo34__CxxTemplateInst12MagicWrapperIbEV* nocapture dereferenceable(1) %0) + +public func returnInstantiation() -> WrappedMagicInt { + return WrappedMagicInt() +} + +// Don't forget to update manglings.txt when changing s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF"() + diff --git a/test/Interop/Cxx/templates/mangling-silgen.swift b/test/Interop/Cxx/templates/mangling-silgen.swift new file mode 100644 index 0000000000000..7d4cc6f7e3c39 --- /dev/null +++ b/test/Interop/Cxx/templates/mangling-silgen.swift @@ -0,0 +1,20 @@ +// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import Mangling + +public func recvInstantiation(_ i: inout WrappedMagicInt) {} + +// CHECK: // recvInstantiation(_:) +// CHECK: sil @$s4main17recvInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF : $@convention(thin) (@inout __CxxTemplateInst12MagicWrapperIiE) -> () + +public func recvInstantiation(_ i: inout WrappedMagicBool) {} + +// CHECK: // recvInstantiation(_:) +// CHECK: sil @$s4main17recvInstantiationyySo34__CxxTemplateInst12MagicWrapperIbEVzF : $@convention(thin) (@inout __CxxTemplateInst12MagicWrapperIbE) -> () + +public func returnInstantiation() -> WrappedMagicInt { + return WrappedMagicInt() +} + +// CHECK: // returnInstantiation() +// CHECK: sil @$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF : $@convention(thin) () -> __CxxTemplateInst12MagicWrapperIiE diff --git a/test/Interop/Cxx/templates/using-directive-module-interface.swift b/test/Interop/Cxx/templates/using-directive-module-interface.swift new file mode 100644 index 0000000000000..81b445d21e3d7 --- /dev/null +++ b/test/Interop/Cxx/templates/using-directive-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=UsingDirective -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: init(value: Int32) +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias UsingWrappedMagicNumber = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/using-directive.swift b/test/Interop/Cxx/templates/using-directive.swift new file mode 100644 index 0000000000000..3bae7a8454b33 --- /dev/null +++ b/test/Interop/Cxx/templates/using-directive.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import StdlibUnittest +import UsingDirective + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("using-directive") { + let myInt = IntWrapper(value: 333) + var magicInt = UsingWrappedMagicNumber(t: myInt) + expectEqual(magicInt.getValuePlusArg(111), 444) +} + +runAllTests() diff --git a/test/Interpreter/SDK/protocol_lookup_foreign.swift b/test/Interpreter/SDK/protocol_lookup_foreign.swift index e0836c4cfa31d..ae864b08efc1e 100644 --- a/test/Interpreter/SDK/protocol_lookup_foreign.swift +++ b/test/Interpreter/SDK/protocol_lookup_foreign.swift @@ -1,47 +1,66 @@ -// RUN: %target-run-simple-swift | %FileCheck %s +// RUN: %target-run-simple-swift // REQUIRES: executable_test // REQUIRES: objc_interop // REQUIRES: OS=macosx -// rdar://20990451 is tracking the fix for compiling this test optimized. -// XFAIL: swift_test_mode_optimize -// XFAIL: swift_test_mode_optimize_size -// XFAIL: swift_test_mode_optimize_unchecked - import Foundation +import StdlibUnittest protocol Fooable { - func foo() + func foo() -> String } -func fooify(_ x: T) { +func fooify(_ x: T) -> String { if let foo = x as? Fooable { - foo.foo() + return foo.foo() } else { - print("not fooable") + return "not fooable" } } extension NSRect: Fooable { - func foo() { print("NSRect") } + func foo() -> String { return "NSRect" } } extension CFSet: Fooable { - func foo() { print("CFSet") } + func foo() -> String { return "CFSet" } } extension NSString: Fooable { - func foo() { print("NSString") } + func foo() -> String { return "NSString" } +} + +var ProtocolLookupForeign = TestSuite("ProtocolLookupForeign") + +ProtocolLookupForeign.test("NSRect") { + expectEqual("NSRect", fooify(NSRect())) +} + +ProtocolLookupForeign.test("NSPoint") { + expectEqual("not fooable", fooify(NSPoint())) +} + +ProtocolLookupForeign.test("CFSet") { + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectEqual("CFSet", fooify(CFSetCreate(kCFAllocatorDefault, nil, 0, nil)!)) + } +} + +ProtocolLookupForeign.test("CFArray") { + expectEqual("not fooable", fooify(CFArrayCreate(kCFAllocatorDefault, nil, 0, nil)!)) +} + +ProtocolLookupForeign.test("NSString") { + expectEqual("NSString", fooify(NSString())) +} + +ProtocolLookupForeign.test("NSMutableString") { + expectEqual("NSString", fooify(NSMutableString())) } -fooify(NSRect()) // CHECK: NSRect -fooify(NSPoint()) // CHECK-NEXT: not fooable -// FIXME: CF types get their ObjC class dynamically looked up during dynamic -// casting. -fooify(CFSetCreate(kCFAllocatorDefault, nil, 0, nil)!) // TODO-NEXT: CFSet CHECK-NEXT: not fooable -fooify(CFArrayCreate(kCFAllocatorDefault, nil, 0, nil)!) // CHECK-NEXT: not fooable -fooify(NSString()) // CHECK-NEXT: NSString -fooify(NSMutableString()) // CHECK-NEXT: NSString -fooify(NSSet()) // CHECK-NEXT: not fooable +ProtocolLookupForeign.test("NSSet") { + expectEqual("not fooable", fooify(NSSet())) +} +runAllTests() diff --git a/test/Interpreter/enum.swift b/test/Interpreter/enum.swift index da9f6c4b17cf6..b2b66b761e743 100644 --- a/test/Interpreter/enum.swift +++ b/test/Interpreter/enum.swift @@ -698,3 +698,49 @@ func testCase() { // CHECK: Container(storage: a.MultiIndirectRef.ind(5)) testCase() + + +enum BitEnum { + case first + case second +} +protocol Init { + init() +} +struct TrailingByte : Init { + var x = 2 + var y = BitEnum.first + init() { + x = 2 + y = BitEnum.first + } +} + +@inline(never) +func capture(_ t: inout T) { + print("captured \(t)") +} + +@inline(never) +func reproduction(_ x: Int, _ y: Int, _ t: T) { + var o : Optional = nil + + + for i in 0 ..< x { + if i == y { + o = T() + } + } + + capture(&o) + + if var byte = o { + print("there is a byte (failure)") + print(byte) + } else { + print("there is no byte") + } +} + +// CHECK: there is no byte +reproduction(2, 3, TrailingByte()) diff --git a/test/Interpreter/failable_initializers_root_class.swift b/test/Interpreter/failable_initializers_root_class.swift new file mode 100644 index 0000000000000..9caa08da0001e --- /dev/null +++ b/test/Interpreter/failable_initializers_root_class.swift @@ -0,0 +1,176 @@ +// RUN: %target-run-simple-swift + +// REQUIRES: executable_test + +import StdlibUnittest + + +var FailableInitTestSuite = TestSuite("FailableInit") + +var deinitCalled = 0 + +func mustFail(f: () -> T?) { + if f() != nil { + preconditionFailure("Didn't fail") + } +} + +func mustSucceed(f: () -> T?) { + if f() == nil { + preconditionFailure("Didn't succeed") + } +} + +class FirstClass { + var x: LifetimeTracked + + init?(n: Int) { + if n == 0 { + return nil + } + + x = LifetimeTracked(0) + + if n == 1 { + return nil + } + } + + deinit { + deinitCalled += 1 + } +} + +FailableInitTestSuite.test("FirstClass") { + deinitCalled = 0 + + mustFail { FirstClass(n: 0) } + expectEqual(0, deinitCalled) + + mustFail { FirstClass(n: 1) } + expectEqual(1, deinitCalled) + + mustSucceed { FirstClass(n: 2) } + expectEqual(2, deinitCalled) +} + +class FirstClassTrivial { + var x: Int + + init?(n: Int) { + if n == 0 { + return nil + } + + x = 0 + + if n == 1 { + return nil + } + } + + deinit { + deinitCalled += 1 + } +} + +FailableInitTestSuite.test("FirstClassTrivial") { + deinitCalled = 0 + + mustFail { FirstClassTrivial(n: 0) } + expectEqual(0, deinitCalled) + + mustFail { FirstClassTrivial(n: 1) } + expectEqual(1, deinitCalled) + + mustSucceed { FirstClassTrivial(n: 2) } + expectEqual(2, deinitCalled) +} + +class SecondClass { + var x: LifetimeTracked + var y: LifetimeTracked + + init?(n: Int) { + if n == 0 { + return nil + } + + x = LifetimeTracked(0) + + if n == 1 { + return nil + } + + y = LifetimeTracked(0) + + if n == 2 { + return nil + } + } + + deinit { + deinitCalled += 1 + } +} + +FailableInitTestSuite.test("SecondClass") { + deinitCalled = 0 + + mustFail { SecondClass(n: 0) } + expectEqual(0, deinitCalled) + + mustFail { SecondClass(n: 1) } + expectEqual(0, deinitCalled) + + mustFail { SecondClass(n: 2) } + expectEqual(1, deinitCalled) + + mustSucceed { SecondClass(n: 3) } + expectEqual(2, deinitCalled) +} + +class SecondClassTrivial { + var x: Int + var y: Int + + init?(n: Int) { + if n == 0 { + return nil + } + + x = 0 + + if n == 1 { + return nil + } + + y = 0 + + if n == 2 { + return nil + } + } + + deinit { + deinitCalled += 1 + } +} + +FailableInitTestSuite.test("SecondClassTrivial") { + deinitCalled = 0 + + mustFail { SecondClassTrivial(n: 0) } + expectEqual(0, deinitCalled) + + mustFail { SecondClassTrivial(n: 1) } + expectEqual(0, deinitCalled) + + mustFail { SecondClassTrivial(n: 2) } + expectEqual(1, deinitCalled) + + mustSucceed { SecondClassTrivial(n: 3) } + expectEqual(2, deinitCalled) +} + +runAllTests() diff --git a/test/Interpreter/multiple_varargs.swift b/test/Interpreter/multiple_varargs.swift new file mode 100644 index 0000000000000..372b49640a3f4 --- /dev/null +++ b/test/Interpreter/multiple_varargs.swift @@ -0,0 +1,85 @@ +// RUN: %target-run-simple-swift | %FileCheck %s + +// REQUIRES: executable_test + +func vf(x: Int..., y: Int...) { + print(x, y) +} + +vf(x: 1, 2, 3, y: 4, 5, 6) +// CHECK: [1, 2, 3] [4, 5, 6] +vf(y: 1, 2) +// CHECK: [] [1, 2] +vf(x: 3, 4) +// CHECK: [3, 4] [] + +func vf2(_ x: Int..., y: Int, _ z: Int...) { + print(x, y, z) +} + +vf2(1, 2, 3, y: 4, 5, 6, 7) +// CHECK: [1, 2, 3] 4 [5, 6, 7] +vf2(y: 4, 5, 6, 7) +// CHECK: [] 4 [5, 6, 7] +vf2(1, 2, 3, y: 4) +// CHECK: [1, 2, 3] 4 [] +vf2(y: 4) +// CHECK: [] 4 [] + +func vf3(_ x: Int..., y: Int = 42, _ z: Int...) { + print(x, y, z) +} + +vf3(1, 2, 3, y: 4, 5, 6, 7) +// CHECK: [1, 2, 3] 4 [5, 6, 7] +vf3(y: 4, 5, 6, 7) +// CHECK: [] 4 [5, 6, 7] +vf3(1, 2, 3, y: 4) +// CHECK: [1, 2, 3] 4 [] +vf3(y: 4) +// CHECK: [] 4 [] + +vf3() +// CHECK: [] 42 [] +vf3(1, 2, 3) +// CHECK: [1, 2, 3] 42 [] + +func foo(a: Int..., b: Int, c: Int..., d: Int) { + print("one") +} + +func foo(a: [Int], b: Int, c: [Int], d: Int) { + print("two") +} + +func foo(a: Int..., b: Int, c: [Int], d: Int) { + print("three") +} + +foo(a: 1, 2, 3, b: 4, c: 5, 6, 7, d: 8) +// CHECK: one +foo(a: [1, 2, 3], b: 4, c: [5, 6, 7], d: 8) +// CHECK: two +foo(a: 1, 2, 3, b: 4, c: [5, 6, 7], d: 8) +// CHECK: three + +struct Baz { + init(a: Int..., b: Int...) { + print(a, b) + } + + init(_ a: Int..., b: String, _ c: Int...) { + print(a, b, c) + } + + subscript(a: Int..., b b: Int...) -> [Int] { a + b } +} + +let baz1 = Baz(a: 1, 2, 3, b: 4, 5, 6) +// CHECK: [1, 2, 3] [4, 5, 6] + +let baz2 = Baz(1, 2, 3, b: "hello, world!", 3, 2, 1) +// CHECK: [1, 2, 3] hello, world! [3, 2, 1] + +print(baz1[1, 2, b: 3, 4]) +// CHECK: [1, 2, 3, 4] diff --git a/test/Interpreter/tuple_casts.swift b/test/Interpreter/tuple_casts.swift index 4c0dacafa57f9..0f662932ed6e7 100644 --- a/test/Interpreter/tuple_casts.swift +++ b/test/Interpreter/tuple_casts.swift @@ -1,7 +1,13 @@ // RUN: %target-run-simple-swift -// RUN: %target-build-swift -O %s -o %t/a.out.optimized -// RUN: %target-codesign %t/a.out.optimized -// RUN: %target-run %t/a.out.optimized +// +// RUN: %target-build-swift -swift-version 5 -O %s -o %t/a.swift5.O.out +// RUN: %target-codesign %t/a.swift5.O.out +// RUN: %target-run %t/a.swift5.O.out +// +// RUN: %target-build-swift -swift-version 5 -Onone %s -o %t/a.swift5.Onone.out +// RUN: %target-codesign %t/a.swift5.Onone.out +// RUN: %target-run %t/a.swift5.Onone.out +// // REQUIRES: executable_test import StdlibUnittest @@ -31,15 +37,31 @@ tupleCastTests.test("Adding/removing labels") { String(describing: anyToIntPoint((3, 4)))) expectEqual("(x: 5, y: 6)", String(describing: anyToIntPoint((x: 5, 6)))) + expectEqual("(x: 5, y: 6)", + String(describing: anyToIntPoint((5, y: 6)))) expectEqual("(1, 2)", String(describing: anyToInt2((1, 2)))) expectEqual("(3, 4)", String(describing: anyToInt2((x: 3, y: 4)))) expectEqual("(5, 6)", String(describing: anyToInt2((x: 5, 6)))) + expectEqual("(7, 8)", String(describing: anyToInt2((7, y: 8)))) expectEqual("(first: 1, 2, third: 3)", String(describing: anyToPartlyLabeled((1, 2, 3)))) } +tupleCastTests.test("Label checks on casting") { + expectTrue((x: 1, y: 2) is (Int, Int)) + expectTrue((x: 1, y: 2) is (x: Int, Int)) + expectTrue((x: 1, y: 2) is (Int, y: Int)) + expectTrue((x: 1, y: 2) is (x: Int, y: Int)) + + expectFalse((x: 1, y: 2) is (x: Int, z: Int)) + expectFalse((x: 1, y: 2) is (a: Int, y: Int)) + expectFalse((x: 1, y: 2) is (a: Int, z: Int)) + expectFalse((x: 1, y: 2) is (Int, z: Int)) + expectFalse((x: 1, y: 2) is (a: Int, Int)) +} + tupleCastTests.test("Incorrect labels conditional cast") { expectNil(anyToIntPointOpt((x: 1, z: 2))) expectEqual("Optional((x: 1, y: 2))", diff --git a/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.1.plist b/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.1.plist new file mode 100644 index 0000000000000..a7775b7bc9349 --- /dev/null +++ b/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.1.plist @@ -0,0 +1,6 @@ + + + ProductBuildVersion + 11111 + + diff --git a/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.2.plist b/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.2.plist new file mode 100644 index 0000000000000..bfe4278c694dc --- /dev/null +++ b/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.2.plist @@ -0,0 +1,6 @@ + + + ProductBuildVersion + 22222 + + diff --git a/test/ModuleInterface/ModuleCache/RebuildRemarks/out-of-date-forwarding-module.swift b/test/ModuleInterface/ModuleCache/RebuildRemarks/out-of-date-forwarding-module.swift index 680dbb1ddd648..269314d8d0f9d 100644 --- a/test/ModuleInterface/ModuleCache/RebuildRemarks/out-of-date-forwarding-module.swift +++ b/test/ModuleInterface/ModuleCache/RebuildRemarks/out-of-date-forwarding-module.swift @@ -1,6 +1,10 @@ // RUN: %empty-directory(%t/ModuleCache) // RUN: %empty-directory(%t/Build) // RUN: %empty-directory(%t/PrebuiltCache) +// RUN: %empty-directory(%t/System/Library/CoreServices) + +// RUN: cp %S/../Inputs/sdk-build-ver.1.plist %t/System/Library/CoreServices/SystemVersion.plist +// RUN: cp %S/../Inputs/sdk-build-ver.2.plist %t/PrebuiltCache/SystemVersion.plist // 1. Create a dummy module // RUN: echo 'public func publicFunction() {}' > %t/TestModule.swift @@ -30,3 +34,4 @@ import TestModule // expected-remark {{rebuilding module 'TestModule' from inter // expected-note @-2 {{dependency is out of date}} // expected-note @-3 {{prebuilt module is out of date}} // expected-note @-4 {{dependency is out of date}} +// expected-note @-5 {{SDK build version is '11111'; prebuilt modules were built using SDK build version: '22222'}} diff --git a/test/ModuleInterface/empty-extension.swift b/test/ModuleInterface/empty-extension.swift new file mode 100644 index 0000000000000..65323afcbcf86 --- /dev/null +++ b/test/ModuleInterface/empty-extension.swift @@ -0,0 +1,49 @@ +// Test that we don't print extensions to implementation-only imported types. + +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend -emit-module %s -DIOI_LIB -module-name IOILib -emit-module-path %t/IOILib.swiftmodule +// RUN: %target-swift-frontend -emit-module %s -DEXPORTED_LIB -module-name IndirectLib -emit-module-path %t/IndirectLib.swiftmodule -I %t +// RUN: %target-swift-frontend -emit-module %s -DLIB -module-name Lib -emit-module-path %t/Lib.swiftmodule -I %t + +// RUN: %target-swift-frontend-typecheck -emit-module-interface-path %t/out.swiftinterface %s -I %t -swift-version 5 -enable-library-evolution +// RUN: %FileCheck %s < %t/out.swiftinterface + +#if IOI_LIB + +public struct IOIImportedType { + public func foo() {} +} + +#elseif EXPORTED_LIB + +public struct ExportedType { + public func foo() {} +} + +#elseif LIB + +@_exported import IndirectLib + +public struct NormalImportedType { + public func foo() {} +} + +#else // Client + +import Lib +@_implementationOnly import IOILib + +public protocol PublicProto { + func foo() +} +extension IOIImportedType : PublicProto {} +// CHECK-NOT: IOIImportedType + +extension NormalImportedType : PublicProto {} +// CHECK: extension NormalImportedType + +extension ExportedType : PublicProto {} +// CHECK: extension ExportedType + +#endif diff --git a/test/ModuleInterface/inherited-generic-parameters.swift b/test/ModuleInterface/inherited-generic-parameters.swift index 1be75a69d7311..ecaebf59237e8 100644 --- a/test/ModuleInterface/inherited-generic-parameters.swift +++ b/test/ModuleInterface/inherited-generic-parameters.swift @@ -19,6 +19,8 @@ public class Base { // CHECK-NEXT: public init(_: A, _: A) public init(_: A, _: A) {} +// CHECK-NEXT: public init(_: C) where C : main.Base + public init(_: C) where C : Base {} // CHECK: } } @@ -27,6 +29,7 @@ public class Derived : Base { // CHECK-NEXT: {{(@objc )?}}deinit // CHECK-NEXT: override public init(x: @escaping (T) -> T) // CHECK-NEXT: override public init(_ argument: A, _ argument: A) +// CHECK-NEXT: override public init(_ argument: C) where C : main.Base // CHECK-NEXT: } } diff --git a/test/ModuleInterface/unbuildable.swift b/test/ModuleInterface/unbuildable.swift index 42506ad70770f..3c1606164cfc7 100644 --- a/test/ModuleInterface/unbuildable.swift +++ b/test/ModuleInterface/unbuildable.swift @@ -14,8 +14,15 @@ // // And finally, test: // -// RUN: not %target-swift-frontend -typecheck %s -I %t -DCURRENT 2>&1 | %FileCheck -check-prefix=CURRENT %s -// RUN: not %target-swift-frontend -typecheck %s -I %t -DFUTURE 2>&1 | %FileCheck -check-prefix=FUTURE %s +// RUN: not %target-swift-frontend -typecheck %s -I %t -DCURRENT 2>&1 | %FileCheck -check-prefixes=ALL,CURRENT %s +// RUN: not %target-swift-frontend -typecheck %s -I %t -DFUTURE 2>&1 | %FileCheck -check-prefixes=ALL,FUTURE %s +// +// Test that we get the same results when typechecking the interface: +// +// RUN: not %target-swift-frontend -typecheck-module-from-interface %t/UnbuildableCurrent.swiftinterface 2>&1 | %FileCheck -check-prefixes=ALL,CURRENT-VERIFY %s +// RUN: not %target-swift-frontend -typecheck-module-from-interface %t/UnbuildableFuture.swiftinterface 2>&1 | %FileCheck -check-prefixes=ALL,FUTURE-VERIFY %s + +// ALL: Unbuildable{{[^.]+}}.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: use of unknown directive '#somethingYouveNeverHeardOf' #if CURRENT import UnbuildableCurrent @@ -25,3 +32,5 @@ import UnbuildableFuture // FUTURE: unbuildable.swift:[[@LINE-1]]:8: error: failed to build module 'UnbuildableFuture' from its module interface; the compiler that produced it, 'NeoTokyoSwift 2000.42', may have used features that aren't supported by this compiler, '{{.*Swift version.*}}' #endif +// CURRENT-VERIFY: UnbuildableCurrent.swiftinterface:1:1: error: failed to verify module interface of 'UnbuildableCurrent'; it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced +// FUTURE-VERIFY: UnbuildableFuture.swiftinterface:1:1: error: failed to verify module interface of 'UnbuildableFuture'; the compiler that produced it, 'NeoTokyoSwift 2000.42', may have used features that aren't supported by this compiler, '{{.*Swift version.*}}' diff --git a/test/ModuleInterface/verify-module-interfaces.swift b/test/ModuleInterface/verify-module-interfaces.swift new file mode 100644 index 0000000000000..191360f2bfb90 --- /dev/null +++ b/test/ModuleInterface/verify-module-interfaces.swift @@ -0,0 +1,15 @@ +// RUN: %empty-directory(%t) + +// Check that verification won't reject a valid interface: +// RUN: %target-build-swift -emit-library -enable-library-evolution -emit-module-interface -emit-module -swift-version 5 -o %t/MyModule.o -verify-emitted-module-interface -module-name MyModule %s + +// Check that verification will reject an invalid interface: +// RUN: not %target-build-swift -emit-library -enable-library-evolution -emit-module-interface -emit-module -swift-version 5 -o %t/MyModule.o -verify-emitted-module-interface -module-name MyModule -Xfrontend -debug-emit-invalid-swiftinterface-syntax %s 2>&1 | %FileCheck %s + +// ...but not if verification is off. +// RUN: %target-build-swift -emit-library -enable-library-evolution -emit-module-interface -emit-module -swift-version 5 -o %t/MyModule.o -no-verify-emitted-module-interface -module-name MyModule -Xfrontend -debug-emit-invalid-swiftinterface-syntax %s + +public struct MyStruct {} + +// CHECK: MyModule.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: use of unknown directive '#__debug_emit_invalid_swiftinterface_syntax__' +// CHECK: MyModule.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: failed to verify module interface of 'MyModule'; it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced diff --git a/test/NameLookup/Inputs/custom_attrs_A.swift b/test/NameLookup/Inputs/custom_attrs_A.swift new file mode 100644 index 0000000000000..c8035b4fa167e --- /dev/null +++ b/test/NameLookup/Inputs/custom_attrs_A.swift @@ -0,0 +1,13 @@ +@propertyWrapper +public struct Wrapper { + public var wrappedValue: Value + + public init(wrappedValue: Value) { + self.wrappedValue = wrappedValue + } +} + +@_functionBuilder +public struct Builder { + static func buildBlock(_ component: T) -> T { component } +} diff --git a/test/NameLookup/Inputs/custom_attrs_B.swift b/test/NameLookup/Inputs/custom_attrs_B.swift new file mode 100644 index 0000000000000..c8035b4fa167e --- /dev/null +++ b/test/NameLookup/Inputs/custom_attrs_B.swift @@ -0,0 +1,13 @@ +@propertyWrapper +public struct Wrapper { + public var wrappedValue: Value + + public init(wrappedValue: Value) { + self.wrappedValue = wrappedValue + } +} + +@_functionBuilder +public struct Builder { + static func buildBlock(_ component: T) -> T { component } +} diff --git a/test/NameLookup/custom_attrs_ambiguous.swift b/test/NameLookup/custom_attrs_ambiguous.swift new file mode 100644 index 0000000000000..b549e34e273ba --- /dev/null +++ b/test/NameLookup/custom_attrs_ambiguous.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -I %t -o %t %S/Inputs/custom_attrs_A.swift +// RUN: %target-swift-frontend -emit-module -I %t -o %t %S/Inputs/custom_attrs_B.swift +// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unknown -I %t %s +import custom_attrs_A +import custom_attrs_B + +// SR-13470 + +struct Test { + @Wrapper var x: Int = 17 + // expected-error@-1 {{ambiguous use of attribute 'Wrapper'}} + // expected-note@-2 {{use 'custom_attrs_A.' to reference the attribute 'Wrapper' in module 'custom_attrs_A'}} {{4-4=custom_attrs_A.}} + // expected-note@-3 {{use 'custom_attrs_B.' to reference the attribute 'Wrapper' in module 'custom_attrs_B'}} {{4-4=custom_attrs_B.}} + + init(@Builder closure: () -> Int) {} + // expected-error@-1 {{ambiguous use of attribute 'Builder'}} + // expected-note@-2 {{use 'custom_attrs_A.' to reference the attribute 'Builder' in module 'custom_attrs_A'}} {{9-9=custom_attrs_A.}} + // expected-note@-3 {{use 'custom_attrs_B.' to reference the attribute 'Builder' in module 'custom_attrs_B'}} {{9-9=custom_attrs_B.}} +} + diff --git a/test/NameLookup/member_type_shadowing.swift b/test/NameLookup/member_type_shadowing.swift index 3ce67db444956..0e3b4f7a81b9d 100644 --- a/test/NameLookup/member_type_shadowing.swift +++ b/test/NameLookup/member_type_shadowing.swift @@ -29,3 +29,17 @@ class B: A { _ = B.Reusable.option2 // expected-error {{type 'B.Reusable' has no member 'option2'; did you mean 'option1'?}} } } + +protocol Q { + typealias A = Int +} + +struct S : Q { + typealias A = String +} + +func usesA(_: S.A) {} // should resolve to the typealias inside S + +func callsA() { + usesA("hello") +} diff --git a/test/NameLookup/subscript-generic-conjuction-astscope.swift b/test/NameLookup/subscript-generic-conjuction-astscope.swift index 60cdc1991e46a..8fb1fc04f27bf 100644 --- a/test/NameLookup/subscript-generic-conjuction-astscope.swift +++ b/test/NameLookup/subscript-generic-conjuction-astscope.swift @@ -1,7 +1,5 @@ // Check that ASTScope lookup works for a construction found in GRDB's Row.swift -// RUN: %target-swift-frontend -typecheck %s -enable-astscope-lookup -warn-if-astscope-lookup 2>%t.out -// RUN: %FileCheck %s <%t.out -// CHECK: WARNING: TRYING Scope exclusively +// RUN: %target-swift-frontend -typecheck %s protocol P1 {} protocol P2 {} diff --git a/test/NameLookup/warn-if-astscope.swift b/test/NameLookup/warn-if-astscope.swift deleted file mode 100644 index f101cf0775033..0000000000000 --- a/test/NameLookup/warn-if-astscope.swift +++ /dev/null @@ -1,13 +0,0 @@ -// Verify the action of -warn-if-astscope-lookup -// -// RUN: not %target-swift-frontend -typecheck %s -enable-astscope-lookup 2>&1 | %FileCheck %s --check-prefix=CHECK-NO-WARN -// RUN: not %target-swift-frontend -typecheck %s -disable-astscope-lookup 2>&1 | %FileCheck %s --check-prefix=CHECK-NO-WARN -// RUN: not %target-swift-frontend -typecheck %s -enable-astscope-lookup -warn-if-astscope-lookup 2>&1 | %FileCheck %s --check-prefix=CHECK-WARN -// RUN: not %target-swift-frontend -typecheck %s -disable-astscope-lookup -warn-if-astscope-lookup 2>&1 | %FileCheck %s --check-prefix=CHECK-NO-WARN - -func foo() -> Int { - return bar() // create an error so the input to fileCheck isn't empty -} - -// CHECK-NO-WARN-NOT: WARNING: TRYING Scope exclusively -// CHECK-WARN: WARNING: TRYING Scope exclusively diff --git a/test/Parse/async-syntax.swift b/test/Parse/async-syntax.swift index 54c1bac839969..c305fc44dd67b 100644 --- a/test/Parse/async-syntax.swift +++ b/test/Parse/async-syntax.swift @@ -12,5 +12,15 @@ func testTypeExprs() { } func testAwaitOperator() async { - let _ = __await asyncGlobal1() + let _ = await asyncGlobal1() +} + +func testAsyncClosure() { + let _ = { () async in 5 } + let _ = { () throws in 5 } + let _ = { () async throws in 5 } +} + +func testAwait() async { + let _ = await asyncGlobal1() } diff --git a/test/Parse/async.swift b/test/Parse/async.swift index 6fee5c0bfdee6..657048a27aec6 100644 --- a/test/Parse/async.swift +++ b/test/Parse/async.swift @@ -41,3 +41,14 @@ func testTypeExprs() { let _ = [() -> async ()]() // expected-error{{'async' may only occur before '->'}}{{18-24=}}{{15-15=async }} } + +// Parsing await syntax. +struct MyFuture { + func await() -> Int { 0 } +} + +func testAwaitExpr() async { + let _ = await asyncGlobal1() + let myFuture = MyFuture() + let _ = myFuture.await() +} diff --git a/test/Parse/toplevel_library_invalid.swift b/test/Parse/toplevel_library_invalid.swift index 7b2eb68d5cdea..1206a42b422a4 100644 --- a/test/Parse/toplevel_library_invalid.swift +++ b/test/Parse/toplevel_library_invalid.swift @@ -1,5 +1,4 @@ // RUN: %target-typecheck-verify-swift -parse-as-library -// RUN: %target-typecheck-verify-swift -parse-as-library -enable-astscope-lookup let x = 42 x + x; // expected-error {{expressions are not allowed at the top level}} expected-warning {{result of operator '+' is unused}} diff --git a/test/PrintAsObjC/Inputs/custom-modules/CompatibilityAlias.h b/test/PrintAsObjC/Inputs/custom-modules/CompatibilityAlias.h index 0d8ec65a05288..45e6515b4bf73 100644 --- a/test/PrintAsObjC/Inputs/custom-modules/CompatibilityAlias.h +++ b/test/PrintAsObjC/Inputs/custom-modules/CompatibilityAlias.h @@ -1,5 +1,7 @@ // This file is meant to be included with modules turned off, compiled against // the fake clang-importer-sdk. #import +#import @compatibility_alias StringCheese NSString; +@compatibility_alias GymClass GenericClass; diff --git a/test/PrintAsObjC/async.swift b/test/PrintAsObjC/async.swift new file mode 100644 index 0000000000000..bfa69136a9e54 --- /dev/null +++ b/test/PrintAsObjC/async.swift @@ -0,0 +1,30 @@ +// REQUIRES: objc_interop + +// RUN: %empty-directory(%t) + +// FIXME: BEGIN -enable-source-import hackaround +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/ObjectiveC.swift -disable-objc-attr-requires-foundation-module +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/CoreGraphics.swift +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/Foundation.swift +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/AppKit.swift +// FIXME: END -enable-source-import hackaround + + +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -parse-as-library %s -typecheck -I %S/Inputs/custom-modules -emit-objc-header-path %t/async.h -import-objc-header %S/../Inputs/empty.h -enable-experimental-concurrency -typecheck +// RUN: %FileCheck %s < %t/async.h +// RUN: %check-in-clang -I %S/Inputs/custom-modules/ %t/async.h + +import Foundation + +// CHECK-LABEL: @interface BarClass : NSObject +@objc @objcMembers class BarClass: NSObject { + // CHECK: (void)doSomethingBigWithCompletionHandler:(void (^)(NSInteger))completionHandler; + func doSomethingBig() async -> Int { 0 } + + // CHECK: - (void)longRunningWithString:(NSString * _Nonnull)string completionHandler:(void (^)(BarClass * _Nullable, NSError * _Nullable))completionHandler; + func longRunning(string: String) async throws -> BarClass { return self } + + // CHECK: - (void)magicTupleReturnWithCompletionHandler:(void (^)(BarClass * _Nonnull, NSInteger))completionHandler; + func magicTupleReturn() async -> (BarClass, Int) { return (self, 0) } +} +// CHECK: @end diff --git a/test/PrintAsObjC/classes.swift b/test/PrintAsObjC/classes.swift index 025bef7fb4d5d..69c2beae96e5a 100644 --- a/test/PrintAsObjC/classes.swift +++ b/test/PrintAsObjC/classes.swift @@ -49,8 +49,26 @@ import SingleGenericClass // CHECK-NEXT: @end @objc class B1 : A1 {} +// Used in BridgedTypes test case +struct Notification: _ObjectiveCBridgeable { + func _bridgeToObjectiveC() -> NSNotification { fatalError() } + static func _forceBridgeFromObjectiveC( + _ source: NSNotification, + result: inout Self? + ) { fatalError() } + @discardableResult + static func _conditionallyBridgeFromObjectiveC( + _ source: NSNotification, + result: inout Self? + ) -> Bool { fatalError() } + @_effects(readonly) + static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) + -> Self { fatalError() } +} + // CHECK-LABEL: @interface BridgedTypes // CHECK-NEXT: - (NSDictionary * _Nonnull)dictBridge:(NSDictionary * _Nonnull)x SWIFT_WARN_UNUSED_RESULT; +// CHECK-NEXT: - (NSNotification * _Nonnull)noteBridge:(NSNotification * _Nonnull)x SWIFT_WARN_UNUSED_RESULT; // CHECK-NEXT: - (NSSet * _Nonnull)setBridge:(NSSet * _Nonnull)x SWIFT_WARN_UNUSED_RESULT; // CHECK-NEXT: init // CHECK-NEXT: @end @@ -59,6 +77,10 @@ import SingleGenericClass return x } + @objc func noteBridge(_ x: Notification) -> Notification { + return x + } + @objc func setBridge(_ x: Set) -> Set { return x } @@ -798,6 +820,9 @@ public class NonObjCClass { } // CHECK-NEXT: - (StringCheese * _Nullable)foo SWIFT_WARN_UNUSED_RESULT; @objc func foo() -> StringCheese? { return nil } + // CHECK-NEXT: - (GymClass * _Nullable)foosball SWIFT_WARN_UNUSED_RESULT; + @objc func foosball() -> GymClass? { return nil } + // CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; } // CHECK-NEXT: @end diff --git a/test/SIL/Parser/async.sil b/test/SIL/Parser/async.sil index 694f66de78175..f65cee1ca6e16 100644 --- a/test/SIL/Parser/async.sil +++ b/test/SIL/Parser/async.sil @@ -1,8 +1,31 @@ // RUN: %target-sil-opt -enable-sil-verify-all=true %s | %target-sil-opt -enable-sil-verify-all=true | %FileCheck %s -// CHECK: sil [async] @async_test -sil [async] @async_test : $() -> () { +import Builtin + +// CHECK: sil @not_async_test : $@convention(thin) () -> () { +sil @not_async_test : $() -> () { +bb0: + %0 = tuple () + return %0 : $() +} + +// CHECK: sil @not_async_test2 : $@convention(thin) (Builtin.Int32) -> () { +sil @not_async_test2 : $(Builtin.Int32) -> () { +bb0(%int : $Builtin.Int32): + %0 = tuple () + return %0 : $() +} + +// CHECK: sil @async_test : $@convention(thin) @async +sil @async_test : $@async () -> () { bb0: %0 = tuple () return %0 : $() } + +// CHECK: sil @take_async : $@convention(thin) (@async () -> ()) -> () +sil @take_async : $(@async () -> ()) -> () { +bb0(%fn : $@async () -> ()): + %0 = tuple () + return %0 : $() +} diff --git a/test/SIL/Serialization/basic.sil b/test/SIL/Serialization/basic.sil index dd7f9ba3a54d4..f6950e30ab2a5 100644 --- a/test/SIL/Serialization/basic.sil +++ b/test/SIL/Serialization/basic.sil @@ -15,8 +15,8 @@ bb0(%0 : @guaranteed $Builtin.NativeObject): return undef : $() } -// CHECK-LABEL: sil [async] @async_test -sil [async] @async_test : $() -> () { +// CHECK-LABEL: sil @async_test : $@convention(thin) @async +sil @async_test : $@async () -> () { bb0: %0 = tuple () return %0 : $() diff --git a/test/SILGen/arguments.swift b/test/SILGen/arguments.swift index fdd26f1594c9a..0c16ad45910c9 100644 --- a/test/SILGen/arguments.swift +++ b/test/SILGen/arguments.swift @@ -82,6 +82,14 @@ func variadic_arg_3(_ y: Float..., x: Int) {} // CHECK-LABEL: sil hidden [ossa] @$ss14variadic_arg_3{{[_0-9a-zA-Z]*}}F // CHECK: bb0([[Y:%[0-9]+]] : $Array, [[X:%[0-9]+]] : $Int): +func variadic_arg_4(_ y: Float..., x: Int...) {} +// CHECK-LABEL: sil hidden [ossa] @$ss14variadic_arg_4{{[_0-9a-zA-Z]*}}F +// CHECK: bb0([[Y:%[0-9]+]] : $Array, [[X:%[0-9]+]] : $Array): + +func variadic_arg_5(a: Int, b: Float..., c: Int, d: Int...) {} +// CHECK-LABEL: sil hidden [ossa] @$ss14variadic_arg_5{{[_0-9a-zA-Z]*}}F +// CHECK: bb0([[A:%[0-9]+]] : $Int, [[B:%[0-9]+]] : $Array, [[C:%[0-9]+]] : $Int, [[D:%[0-9]+]] : $Array): + variadic_arg_3(x: i) variadic_arg_3(f, x: i) variadic_arg_3(f, f, f, x: i) diff --git a/test/SILGen/async.swift b/test/SILGen/async.swift deleted file mode 100644 index 901978a7ac493..0000000000000 --- a/test/SILGen/async.swift +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: %target-swift-frontend -emit-silgen -enable-experimental-concurrency -module-name Async -Xllvm -sil-full-demangle -parse-as-library %s | %FileCheck %s - -import Swift - -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async04testA0yyYF : $@convention(thin) () -> () { -func testAsync() async {} -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async11testAsyncp1SiyYF : $@convention(thin) () -> Int { -func testAsyncp1() async -> Int { return 0 } - -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async5test2yyYKF : $@convention(thin) () -> @error Error { -func test2() async throws {} -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async7test2p1SiyYKF : $@convention(thin) () -> (Int, @error Error) { -func test2p1() async throws -> Int { return 0 } - -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async5test3yyyyKXEYKF : $@convention(thin) (@noescape @callee_guaranteed () -> @error Error) -> @error Error { -func test3(_ cl: () throws -> ()) async rethrows {} -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async7test3p1yS2iyKXEYKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error) { -func test3p1(_ cl: () throws -> Int) async rethrows -> Int { return try cl() } - - diff --git a/test/SILGen/default_arguments.swift b/test/SILGen/default_arguments.swift index 8fc06fb8ed67a..0895a9a0f018a 100644 --- a/test/SILGen/default_arguments.swift +++ b/test/SILGen/default_arguments.swift @@ -156,7 +156,7 @@ class Foo { return x } - // CHECK-LABEL: sil private [ossa] @globalinit_33_E52D764B1F2009F2390B2B8DF62DAEB8_func0 + // CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ // CHECK: string_literal utf8 "Foo" static let x = Foo(int:0) diff --git a/test/SILGen/fragile_globals.swift b/test/SILGen/fragile_globals.swift index 0a4ace7ffa3a1..c6c6e412eece0 100644 --- a/test/SILGen/fragile_globals.swift +++ b/test/SILGen/fragile_globals.swift @@ -11,7 +11,7 @@ var mygg = 29 // Check if we have one token: from mygg. // Initializers from other modules are never fragile. -// CHECK: sil_global private{{.*}} @globalinit_[[T3:.*]]_token0 +// CHECK: sil_global private{{.*}} @[[T3:.*]]Wz //@inlinable public func sum() -> Int { @@ -21,8 +21,8 @@ public func sum() -> Int { // Check if all the addressors are inlined. // CHECK-LABEL: sil {{.*}}@$s15fragile_globals3sumSiyF -// CHECK-DAG: global_addr @globalinit_[[T1:.*]]_token0 -// CHECK-DAG: function_ref @globalinit_[[T1]]_func0 +// CHECK-DAG: global_addr @[[T1:.*]]Wz +// CHECK-DAG: function_ref @[[T1]]WZ // CHECK-DAG: global_addr @$s15fragile_globals4myggSivp // CHECK-DAG: function_ref @$s7ModuleA2ggSivau // CHECK-DAG: function_ref @$s7ModuleB2ggSivau diff --git a/test/SILGen/global_resilience.swift b/test/SILGen/global_resilience.swift index 78b425a9ed684..2f5ea45c549e8 100644 --- a/test/SILGen/global_resilience.swift +++ b/test/SILGen/global_resilience.swift @@ -43,21 +43,21 @@ public var myEmptyGlobal = MyEmptyStruct() // Mutable addressor for fixed-layout global -// CHECK-LABEL: sil private [ossa] @globalinit_{{.*}}_func1 +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ // CHECK: alloc_global @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK: return // CHECK-LABEL: sil [global_init] [ossa] @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVvau -// CHECK: function_ref @globalinit_{{.*}}_func1 +// CHECK: function_ref @{{.*}}WZ // CHECK: global_addr @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK: return -// CHECK-OPT-LABEL: sil private @globalinit_{{.*}}_func1 +// CHECK-OPT-LABEL: sil private [global_init_once_fn] @{{.*}}WZ // CHECK-OPT: alloc_global @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK-OPT: return // CHECK-OPT-LABEL: sil [global_init] @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVvau -// CHECK-OPT: function_ref @globalinit_{{.*}}_func1 +// CHECK-OPT: function_ref @{{.*}}WZ // CHECK-OPT: global_addr @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVvp // CHECK-OPT: return diff --git a/test/SILGen/keypaths_objc.swift b/test/SILGen/keypaths_objc.swift index 215847db3e443..b5603386f5876 100644 --- a/test/SILGen/keypaths_objc.swift +++ b/test/SILGen/keypaths_objc.swift @@ -113,3 +113,47 @@ class OverrideFrameworkObjCProperty: A { func overrideFrameworkObjCProperty() { let _ = \OverrideFrameworkObjCProperty.counter } + +@dynamicMemberLookup +class DynamicClass { + init() {} + subscript(dynamicMember member: KeyPath) -> DynamicClass { + fatalError() + } +} + +// CHECK-LABEL: sil hidden [ossa] @{{.*}}dynamicMemberLookupSimple +func dynamicMemberLookupSimple(foo: DynamicClass, nonobjc: DynamicClass) { + // CHECK: keypath $KeyPath, (objc "bar" + _ = foo.bar + // CHECK: keypath $KeyPath, (objc "int" + _ = foo.int + // CHECK: keypath $KeyPath, (objc "bar" + // CHECK: keypath $KeyPath, (objc "foo" + _ = foo.bar.foo + // CHECK: keypath $KeyPath, (root + _ = foo.nonobjc + // CHECK: keypath $KeyPath, (objc "thisIsADifferentName" + _ = foo.differentName + // CHECK: keypath $KeyPath, (root + _ = nonobjc.x + // CHECK: keypath $KeyPath, (root + _ = nonobjc.y +} + +// CHECK-LABEL: sil hidden [ossa] @{{.*}}dynamicMemberLookupNestedKeypaths +func dynamicMemberLookupNestedKeypaths(foo: DynamicClass) { + // CHECK: keypath $KeyPath, (objc "bar" + // CHECK: keypath $KeyPath, (objc "foo" + // CHECK: keypath $KeyPath, (objc "bar" + _ = foo.bar.foo.bar +} + +// CHECK-LABEL: sil hidden [ossa] @{{.*}}dynamicMemberLookupMixedKeypaths +func dynamicMemberLookupMixedKeypaths(foo: DynamicClass) { + // CHECK: keypath $KeyPath, (objc "bar" + // CHECK: keypath $KeyPath, (objc "foo" + // CHECK: keypath $KeyPath, (root + // CHECK: keypath $KeyPath, (root + _ = foo.bar.foo.nonobjc.y +} \ No newline at end of file diff --git a/test/SILGen/lazy_globals.swift b/test/SILGen/lazy_globals.swift index 4e1cc299c3468..c5604dc5a159a 100644 --- a/test/SILGen/lazy_globals.swift +++ b/test/SILGen/lazy_globals.swift @@ -1,14 +1,14 @@ // RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s -// CHECK: sil private [ossa] @globalinit_[[T:.*]]_func0 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*]]WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals1xSiv // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals1xSivp : $*Int // CHECK: store {{%.*}} to [trivial] [[XADDR]] : $*Int // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals1xSivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @globalinit_[[T]]_token0 : $*Builtin.Word +// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @[[T]]Wz : $*Builtin.Word // CHECK: [[TOKEN_PTR:%.*]] = address_to_pointer [[TOKEN_ADDR]] : $*Builtin.Word to $Builtin.RawPointer -// CHECK: [[INIT_FUNC:%.*]] = function_ref @globalinit_[[T]]_func0 : $@convention(c) () -> () +// CHECK: [[INIT_FUNC:%.*]] = function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: builtin "once"([[TOKEN_PTR]] : $Builtin.RawPointer, [[INIT_FUNC]] : $@convention(c) () -> ()) : $() // CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s12lazy_globals1xSivp : $*Int // CHECK: [[GLOBAL_PTR:%.*]] = address_to_pointer [[GLOBAL_ADDR]] : $*Int to $Builtin.RawPointer @@ -16,7 +16,7 @@ // CHECK: } var x: Int = 0 -// CHECK: sil private [ossa] @globalinit_[[T:.*]]_func1 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*]]WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals3FooV3fooSivpZ // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals3FooV3fooSivpZ : $*Int // CHECK: store {{.*}} to [trivial] [[XADDR]] : $*Int @@ -24,9 +24,9 @@ var x: Int = 0 struct Foo { // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals3FooV3fooSivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @globalinit_[[T]]_token1 : $*Builtin.Word +// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @[[T]]Wz : $*Builtin.Word // CHECK: [[TOKEN_PTR:%.*]] = address_to_pointer [[TOKEN_ADDR]] : $*Builtin.Word to $Builtin.RawPointer -// CHECK: [[INIT_FUNC:%.*]] = function_ref @globalinit_[[T]]_func1 : $@convention(c) () -> () +// CHECK: [[INIT_FUNC:%.*]] = function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: builtin "once"([[TOKEN_PTR]] : $Builtin.RawPointer, [[INIT_FUNC]] : $@convention(c) () -> ()) : $() // CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s12lazy_globals3FooV3fooSivpZ : $*Int // CHECK: [[GLOBAL_PTR:%.*]] = address_to_pointer [[GLOBAL_ADDR]] : $*Int to $Builtin.RawPointer @@ -40,7 +40,7 @@ struct Foo { static var initialized: Int = 57 } -// CHECK: sil private [ossa] @globalinit_[[T:.*]]_func3 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*3bar.*]]WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals3BarO3barSivpZ // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals3BarO3barSivpZ : $*Int // CHECK: store {{.*}} to [trivial] [[XADDR]] : $*Int @@ -48,9 +48,9 @@ struct Foo { enum Bar { // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals3BarO3barSivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @globalinit_[[T]]_token3 : $*Builtin.Word +// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @[[T]]Wz : $*Builtin.Word // CHECK: [[TOKEN_PTR:%.*]] = address_to_pointer [[TOKEN_ADDR]] : $*Builtin.Word to $Builtin.RawPointer -// CHECK: [[INIT_FUNC:%.*]] = function_ref @globalinit_[[T]]_func3 : $@convention(c) () -> () +// CHECK: [[INIT_FUNC:%.*]] = function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: builtin "once"([[TOKEN_PTR]] : $Builtin.RawPointer, [[INIT_FUNC]] : $@convention(c) () -> ()) : $() // CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s12lazy_globals3BarO3barSivpZ : $*Int // CHECK: [[GLOBAL_PTR:%.*]] = address_to_pointer [[GLOBAL_ADDR]] : $*Int to $Builtin.RawPointer @@ -63,13 +63,13 @@ enum Bar { func f() -> (Int, Int) { return (1, 2) } -// CHECK: sil private [ossa] @globalinit_[[T]]_func4 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*2a1.*2b1.*]]WZ : $@convention(c) () -> () { // CHECK: function_ref @$s12lazy_globals1fSi_SityF : $@convention(thin) () -> (Int, Int) // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals2a1Sivau : $@convention(thin) () -> Builtin.RawPointer -// CHECK: function_ref @globalinit_[[T]]_func4 : $@convention(c) () -> () +// CHECK: function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: global_addr @$s12lazy_globals2a1Sivp : $*Int // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals2b1Sivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: function_ref @globalinit_[[T]]_func4 : $@convention(c) () -> () +// CHECK: function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: global_addr @$s12lazy_globals2b1Sivp : $*Int var (a1, b1) = f() diff --git a/test/SILGen/lazy_globals_multiple_vars.swift b/test/SILGen/lazy_globals_multiple_vars.swift index 0c415d5c20231..059cfa8267cbf 100644 --- a/test/SILGen/lazy_globals_multiple_vars.swift +++ b/test/SILGen/lazy_globals_multiple_vars.swift @@ -1,34 +1,34 @@ // RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s -// CHECK: sil private [ossa] [[INIT_A_B:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_A_B:@.*1a.*1b.*WZ]] : // CHECK: alloc_global @$s26lazy_globals_multiple_vars1aSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1aSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1bSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1bSiv // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1aSivau -// CHECK: global_addr [[TOKEN_A_B:@globalinit_.*]] : +// CHECK: global_addr [[TOKEN_A_B:@.*1a.*1b.*Wz]] : // CHECK: function_ref [[INIT_A_B]] // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1bSivau // CHECK: global_addr [[TOKEN_A_B]] // CHECK: function_ref [[INIT_A_B]] var (a, b) = (1, 2) -// CHECK: sil private [ossa] [[INIT_C:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_C:@.*1c.*WZ]] : // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1dSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1cSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1cSiv // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1dSiv // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1cSivau -// CHECK: global_addr [[TOKEN_C:@globalinit_.*]] : +// CHECK: global_addr [[TOKEN_C:@.*1c.*Wz]] : // CHECK: function_ref [[INIT_C]] -// CHECK: sil private [ossa] [[INIT_D:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_D:@.*1d.*WZ]] : // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1cSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1dSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1dSiv // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1cSiv // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1dSivau // CHECK-NOT: global_addr [[TOKEN_C]] -// CHECK: global_addr [[TOKEN_D:@globalinit_.*]] : +// CHECK: global_addr [[TOKEN_D:@.*1d.*Wz]] : // CHECK-NOT: global_addr [[TOKEN_C]] // CHECK: function_ref [[INIT_D]] var c = 1, d = 2 diff --git a/test/SILGen/local_recursion.swift b/test/SILGen/local_recursion.swift index d408a4c983c93..09c83bda8220d 100644 --- a/test/SILGen/local_recursion.swift +++ b/test/SILGen/local_recursion.swift @@ -1,5 +1,4 @@ // RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s -// RUN: %target-swift-emit-silgen -enable-astscope-lookup -parse-as-library %s | %FileCheck %s // CHECK-LABEL: sil hidden [ossa] @$s15local_recursionAA_1yySi_SitF : $@convention(thin) (Int, Int) -> () { // CHECK: bb0([[X:%0]] : $Int, [[Y:%1]] : $Int): diff --git a/test/SILGen/observers.swift b/test/SILGen/observers.swift index 3051c0a1126c7..6b6c6d4503fa1 100644 --- a/test/SILGen/observers.swift +++ b/test/SILGen/observers.swift @@ -171,7 +171,7 @@ public struct DidSetWillSetTests { var global_observing_property : Int = zero { // The variable is initialized with "zero". - // CHECK-LABEL: sil private [ossa] @globalinit_{{.*}}_func1 : $@convention(c) () -> () { + // CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: bb0: // CHECK-NEXT: alloc_global @$s9observers25global_observing_propertySiv // CHECK-NEXT: %1 = global_addr @$s9observers25global_observing_propertySivp : $*Int diff --git a/test/SILGen/opaque_result_type_private.swift b/test/SILGen/opaque_result_type_private.swift new file mode 100644 index 0000000000000..25cff253f4d59 --- /dev/null +++ b/test/SILGen/opaque_result_type_private.swift @@ -0,0 +1,34 @@ +// RUN: %target-swift-emit-silgen -primary-file %s -disable-availability-checking | %FileCheck %s +// RUN: %target-swift-emit-sil -primary-file %s -O -disable-availability-checking + +// CHECK-LABEL: sil [ossa] @main : $@convention(c) (Int32, UnsafeMutablePointer>>) -> Int32 { + +// CHECK: [[BOX:%.*]] = alloc_stack $PrivateClass +// CHECK: [[FN:%.*]] = function_ref @$s26opaque_result_type_private19returnPrivateOpaqueQryF : $@convention(thin) () -> @out PrivateClass +// CHECK: apply [[FN]]([[BOX]]) : $@convention(thin) () -> @out PrivateClass +// CHECK: [[RESULT:%.*]] = load [take] [[BOX]] : $*PrivateClass +// CHECK: destroy_value [[RESULT]] : $PrivateClass +// CHECK: dealloc_stack [[BOX]] : $*PrivateClass +_ = returnPrivateOpaque() + +// CHECK: [[BOX:%.*]] = alloc_stack $LocalClass +// CHECK: [[FN:%.*]] = function_ref @$s26opaque_result_type_private17returnLocalOpaqueQryF : $@convention(thin) () -> @out LocalClass +// CHECK: apply [[FN]]([[BOX]]) : $@convention(thin) () -> @out LocalClass +// CHECK: [[RESULT:%.*]] = load [take] [[BOX]] : $*LocalClass +// CHECK: destroy_value [[RESULT]] : $LocalClass +// CHECK: dealloc_stack [[BOX]] : $*LocalClass +_ = returnLocalOpaque() + +fileprivate class PrivateClass {} + +// CHECK-LABEL: sil hidden [ossa] @$s26opaque_result_type_private19returnPrivateOpaqueQryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s26opaque_result_type_private19returnPrivateOpaqueQryF", 0) 🦸 +func returnPrivateOpaque() -> some Any { + return PrivateClass() +} + +// CHECK-LABEL: sil hidden [ossa] @$s26opaque_result_type_private17returnLocalOpaqueQryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s26opaque_result_type_private17returnLocalOpaqueQryF", 0) 🦸 +func returnLocalOpaque() -> some Any { + class LocalClass {} + + return LocalClass() +} diff --git a/test/SILGen/switch_fallthrough.swift b/test/SILGen/switch_fallthrough.swift index 77b5c5cf3e626..4be37a1adf6c4 100644 --- a/test/SILGen/switch_fallthrough.swift +++ b/test/SILGen/switch_fallthrough.swift @@ -165,3 +165,20 @@ func test5() { e() } +// rdar://problem/67704651 - crash due to nested fallthrough +func testNestedFallthrough(x: (Int, String), y: (Int, Int)) { + switch x { + case (17, let s): + switch y { + case (42, let i): + print("the answer") + default: + print("nope") + } + fallthrough + case (42, let s): + print("42 and \(s)") + default: + print("done") + } +} diff --git a/test/SILGen/unreachable_code.swift b/test/SILGen/unreachable_code.swift index 79c3fb0837f44..799a27a49eefc 100644 --- a/test/SILGen/unreachable_code.swift +++ b/test/SILGen/unreachable_code.swift @@ -67,8 +67,7 @@ func testUnreachableCase1(a : Tree) { case let Leaf: _ = Leaf return - case .Branch(_): // expected-warning {{case will never be executed}} - // expected-warning@-1 {{case is already handled by previous patterns; consider removing it}} + case .Branch(_): // expected-warning {{case is already handled by previous patterns; consider removing it}} return } } @@ -87,8 +86,7 @@ func testUnreachableCase3(a : Tree) { switch a { case _: break - case .Branch(_): // expected-warning {{case will never be executed}} - // expected-warning@-1 {{case is already handled by previous patterns; consider removing it}} + case .Branch(_): // expected-warning {{case is already handled by previous patterns; consider removing it}} return } } @@ -137,3 +135,14 @@ func sr6141() { return; bar?.append("x") // expected-warning{{code after 'return' will never be executed}} } + +func testUnreachableCatchClause() { + enum ErrorEnum: Error { case someError } + do { + throw ErrorEnum.someError + } catch let error { + print(error) + } catch ErrorEnum.someError { // expected-warning {{case will never be executed}} + print("some error") + } +} diff --git a/test/SILOptimizer/Inputs/definite_init_cross_module/OtherModule.swift b/test/SILOptimizer/Inputs/definite_init_cross_module/OtherModule.swift index 3e449b357336c..e3568a71bdc25 100644 --- a/test/SILOptimizer/Inputs/definite_init_cross_module/OtherModule.swift +++ b/test/SILOptimizer/Inputs/definite_init_cross_module/OtherModule.swift @@ -41,3 +41,14 @@ public struct Empty { public struct GenericEmpty { public init() {} } + +open class VisibleNoArgsDesignatedInit { + var x: Float + public init() { x = 0.0 } + + // Add some designated inits the subclass cannot see. + private init(x: Float) { self.x = x } + fileprivate init(y: Float) { self.x = y } + internal init(z: Float) { self.x = z } +} + diff --git a/test/SILOptimizer/OSLogFullOptTest.swift b/test/SILOptimizer/OSLogFullOptTest.swift index 4dbf39e3e886c..8cc72d891f5e1 100644 --- a/test/SILOptimizer/OSLogFullOptTest.swift +++ b/test/SILOptimizer/OSLogFullOptTest.swift @@ -126,6 +126,7 @@ func testNSObjectInterpolation(nsArray: NSArray) { // CHECK-NEXT: bitcast %TSo7NSArrayC* %0 to i8* // CHECK-NEXT: tail call i8* @llvm.objc.retain // CHECK-NEXT: [[NSARRAY_ARG:%.+]] = tail call i8* @llvm.objc.retain + // CHECK: tail call %swift.refcounted* @swift_retain // CHECK: tail call swiftcc i1 @"${{.*}}isLoggingEnabled{{.*}}"() // CHECK-NEXT: br i1 {{%.*}}, label %[[ENABLED:[0-9]+]], label %[[NOT_ENABLED:[0-9]+]] @@ -136,6 +137,7 @@ func testNSObjectInterpolation(nsArray: NSArray) { // CHECK: [[EXIT]]: // CHECK-NEXT: tail call void @llvm.objc.release(i8* [[NSARRAY_ARG]]) + // CHECK-NEXT: tail call void @swift_release // CHECK-NEXT: ret void // CHECK: [[ENABLED]]: diff --git a/test/SILOptimizer/access_marker_verify.swift b/test/SILOptimizer/access_marker_verify.swift index 1ed6f62f84fdd..6062f4116579f 100644 --- a/test/SILOptimizer/access_marker_verify.swift +++ b/test/SILOptimizer/access_marker_verify.swift @@ -627,17 +627,17 @@ func testShims() -> UInt32 { // --- global variable initialization. var globalString1 = "⓪" // start non-empty -// CHECK-LABEL: sil private [ossa] @globalinit_33_{{.*}}_func0 : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify13globalString1SSvp // CHECK: [[GA:%.*]] = global_addr @$s20access_marker_verify13globalString1SSvp : $*String // CHECK: apply // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[GA]] : $*String // CHECK: store %{{.*}} to [init] [[ACCESS]] : $*String // CHECK: end_access -// CHECK-LABEL: } // end sil function 'globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func0' +// CHECK-LABEL: } // end sil function '{{.*}}WZ' var globalString2 = globalString1 -// CHECK-LABEL: sil private [ossa] @globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1 : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify13globalString2SSvp // CHECK: [[GA:%.*]] = global_addr @$s20access_marker_verify13globalString2SSvp : $*String // CHECK: apply @@ -648,7 +648,7 @@ var globalString2 = globalString1 // CHECK: end_access [[INIT]] : $*String // CHECK: end_access [[ACCESS]] : $*String // CHECK-NOT: end_access -// CHECK-LABEL: } // end sil function 'globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1' +// CHECK-LABEL: } // end sil function '{{.*}}WZ' // --- getter. @@ -1037,13 +1037,13 @@ func testPointerInit(x: Int, y: UnsafeMutablePointer) { class testInitExistentialGlobal { static var testProperty: P = StructP() } -// CHECK-LABEL: sil private [ossa] @globalinit{{.*}} : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ // CHECK: [[GADR:%.*]] = global_addr @$s20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ : $*P // CHECK: %{{.*}} = apply %{{.*}}({{.*}}) : $@convention(method) (@thin StructP.Type) -> StructP // CHECK: [[EADR:%.*]] = init_existential_addr [[GADR]] : $*P, $StructP // CHECK: store %{{.*}} to [trivial] [[EADR]] : $*StructP -// CHECK-LABEL: } // end sil function 'globalinit +// CHECK-LABEL: } // end sil function '{{.*}}WZ public enum SomeError: Swift.Error { case error diff --git a/test/SILOptimizer/access_marker_verify_objc.swift b/test/SILOptimizer/access_marker_verify_objc.swift index b9fc5fbaa7c0e..c3e1ed48efe35 100644 --- a/test/SILOptimizer/access_marker_verify_objc.swift +++ b/test/SILOptimizer/access_marker_verify_objc.swift @@ -12,14 +12,14 @@ import Foundation // --- initializer `let` of CFString. // The verifier should ignore this. -// CHECK_LABEL: sil private @globalinit{{.*}} : $@convention(c) () -> () { +// CHECK_LABEL: sil private @{{.*}}WZ : $@convention(c) () -> () { // CHECK: bb0: // CHECK: alloc_global @$s25access_marker_verify_objc12testCFStringC8cfStringSo0F3RefavpZ // CHECK: [[GA:%.*]] = global_addr @$s25access_marker_verify_objc12testCFStringC8cfStringSo0F3RefavpZ : $*CFString // CHECK-NOT: begin_access // CHECK: store %{{.*}} to [init] [[GA]] : $*CFString // CHECK: return %{{.*}} : $() -// CHECK-LABEL: } // end sil function 'globalinit{{.*}}' +// CHECK-LABEL: } // end sil function '{{.*}}WZ' class testCFString { public static let cfString: CFString = "" as CFString } diff --git a/test/SILOptimizer/arcsequenceopts.sil b/test/SILOptimizer/arcsequenceopts.sil index 8825d9cbae7f0..b12c341ed0de9 100644 --- a/test/SILOptimizer/arcsequenceopts.sil +++ b/test/SILOptimizer/arcsequenceopts.sil @@ -405,6 +405,12 @@ bb0(%0 : $<τ_0_0> { var τ_0_0 } ): return %1 : $() } +sil @guaranteed_box_throwing_use : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> @error Error { +bb0(%0 : $<τ_0_0> { var τ_0_0 } ): + %1 = tuple () + return %1 : $() +} + // CHECK_LABEL: sil hidden [noinline] @$test_guaranteed_call : // CHECK: bb1{{.*}}: // CHECK-NOT: strong_retain @@ -2157,6 +2163,30 @@ bb2(%4 : $Error): throw %4 : $Error } +// CHECK_LABEL: sil hidden [noinline] @$try_apply_test_3 : +// CHECK-NOT: strong_retain +// CHECK-NOT: strong_release +// CHECK_LABEL: } // end sil function '$try_apply_test_3' +sil hidden [noinline] @$try_apply_test_3 : $@convention(thin) () -> @error Error { +bb0: + %box = alloc_box $<τ_0_0> { var τ_0_0 } + %proj = project_box %box : $<τ_0_0> { var τ_0_0 } , 0 + %funcref = function_ref @guaranteed_box_throwing_use : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> @error Error + br bb1 + +bb1: + strong_retain %box : $<τ_0_0> { var τ_0_0 } + try_apply %funcref (%box) : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> @error Error, normal bbs, error bbe + +bbs(%s : $()): + strong_release %box : $<τ_0_0> { var τ_0_0 } + return undef : $() + +bbe(%e : $Error): + strong_release %box : $<τ_0_0> { var τ_0_0 } + throw %e : $Error +} + // In this control flow, ARC runs multiple iterations to get rid of and move the retain and releases. // In the first iteration, we will try to move id1/id3 towards each other. // we create new instructions and remove the old ones. However we had a bug to insert these newly created diff --git a/test/SILOptimizer/arcsequenceopts_knownsafebugs.sil b/test/SILOptimizer/arcsequenceopts_knownsafebugs.sil new file mode 100644 index 0000000000000..25be828929ef6 --- /dev/null +++ b/test/SILOptimizer/arcsequenceopts_knownsafebugs.sil @@ -0,0 +1,205 @@ +// RUN: %target-sil-opt -enable-sil-verify-all -enable-loop-arc=0 -arc-sequence-opts %s | %FileCheck %s +sil_stage canonical + +import Builtin +import Swift + +final class ChildCls { + var id: Int + init(_ i:Int) +} + +struct S { + var child1 : ChildCls + var child2 : ChildCls + init() +} + +class Cls { + var child1 : ChildCls + var child2 : ChildCls + init() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_subobject : +// CHECK: bb0(%0 : $S): +// CHECK: retain_value %0 : $S +// CHECK: bb2: +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK-LABEL: } // end sil function '$unmatched_rr_subobject' +sil hidden @$unmatched_rr_subobject : $@convention(thin) (@owned S) -> () { +bb0(%0 : $S): + retain_value %0 : $S + br bb1 + +bb1: + %1 = struct_extract %0 : $S, #S.child1 + strong_release %1 : $ChildCls + strong_retain %1 : $ChildCls + br bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_subobject : +// CHECK: bb0(%0 : $S): +// CHECK-NOT: retain_value %0 : $S +// CHECK: bb2: +// CHECK-NEXT: release_value %0 : $S +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_subobject' +sil hidden @$matched_rr_subobject : $@convention(thin) (@owned S) -> () { +bb0(%0 : $S): + retain_value %0 : $S + br bb1 + +bb1: + %1 = struct_extract %0 : $S, #S.child1 + strong_retain %1 : $ChildCls + strong_release %1 : $ChildCls + br bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_aliasing : +// CHECK: bb0(%0 : $S, %1 : $ChildCls): +// CHECK: retain_value %0 : $S +// CHECK: bb2: +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK-LABEL: } // end sil function '$unmatched_rr_aliasing' +sil hidden @$unmatched_rr_aliasing : $@convention(thin) (@owned S, ChildCls) -> () { +bb0(%0 : $S, %1 : $ChildCls): + retain_value %0 : $S + br bb1 + +bb1: + strong_release %1 : $ChildCls + strong_retain %1 : $ChildCls + br bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_aliasing : +// CHECK: bb0(%0 : $S, %1 : $ChildCls): +// CHECK-NOT: retain_value %0 : $S +// CHECK: bb2: +// CHECK-NEXT: release_value %0 : $S +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_aliasing' +sil hidden @$matched_rr_aliasing : $@convention(thin) (@owned S, ChildCls) -> () { +bb0(%0 : $S, %1 : $ChildCls): + retain_value %0 : $S + br bb1 + +bb1: + strong_retain %1 : $ChildCls + strong_release %1 : $ChildCls + br bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_cls_subobject : +// CHECK: bb0(%0 : $Cls): +// CHECK: retain_value %0 : $Cls +// CHECK: bb2: +// CHECK: release_value %0 : $Cls +// CHECK: release_value %0 : $Cls +// CHECK-LABEL: } // end sil function '$unmatched_rr_cls_subobject' +sil hidden @$unmatched_rr_cls_subobject : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + retain_value %0 : $Cls + br bb1 + +bb1: + %1 = ref_element_addr %0 : $Cls, #Cls.child1 + %2 = load %1 : $*ChildCls + strong_release %2 : $ChildCls + strong_retain %2 : $ChildCls + br bb2 + +bb2: + release_value %0 : $Cls + release_value %0 : $Cls + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_cls_subobject : +// CHECK: bb0(%0 : $Cls): +// CHECK-NOT: retain_value %0 : $Cls +// CHECK: bb2: +// CHECK-NEXT: release_value %0 : $Cls +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_cls_subobject' +sil hidden @$matched_rr_cls_subobject : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + retain_value %0 : $Cls + br bb1 + +bb1: + %1 = ref_element_addr %0 : $Cls, #Cls.child1 + %2 = load %1 : $*ChildCls + strong_retain %2 : $ChildCls + strong_release %2 : $ChildCls + br bb2 + +bb2: + release_value %0 : $Cls + release_value %0 : $Cls + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_subobject_nested_knownsafety : +// CHECK: bb0(%0 : $S): +// CHECK: retain_value %0 : $S +// CHECK: retain_value %0 : $S +// CHECK: bb2: +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK-LABEL: } // end sil function '$unmatched_rr_subobject_nested_knownsafety' +sil hidden @$unmatched_rr_subobject_nested_knownsafety : $@convention(thin) (@owned S) -> () { +bb0(%0 : $S): + retain_value %0 : $S + retain_value %0 : $S + br bb1 + +bb1: + %1 = struct_extract %0 : $S, #S.child1 + strong_release %1 : $ChildCls + strong_retain %1 : $ChildCls + br bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + diff --git a/test/SILOptimizer/arcsequenceopts_knownsafebugs_loop.sil b/test/SILOptimizer/arcsequenceopts_knownsafebugs_loop.sil new file mode 100644 index 0000000000000..2ba87e801f5b9 --- /dev/null +++ b/test/SILOptimizer/arcsequenceopts_knownsafebugs_loop.sil @@ -0,0 +1,323 @@ +// RUN: %target-sil-opt -enable-sil-verify-all -enable-loop-arc=1 -arc-sequence-opts %s | %FileCheck %s +sil_stage canonical + +import Builtin +import Swift + +final class ChildCls { + var id: Int + init(_ i:Int) +} +struct S { + var child1 : ChildCls + var child2 : ChildCls + init() +} +class Cls { + var child1 : ChildCls + var child2 : ChildCls + init() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_loop : +// CHECK: bb0(%0 : $Cls): +// CHECK: strong_retain %0 : $Cls +// CHECK: bb2: +// CHECK: strong_release %0 : $Cls +// CHECK: strong_release %0 : $Cls +// CHECK-LABEL: } // end sil function '$unmatched_rr_loop' +sil hidden @$unmatched_rr_loop : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_release %0 : $Cls + strong_retain %0 : $Cls + cond_br undef, bb1, bb2 + +bb2: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_loop : +// CHECK: bb0(%0 : $Cls): +// CHECK-NOT: strong_retain %0 : $Cls +// CHECK: bb2: +// CHECK-NEXT: strong_release %0 : $Cls +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_loop' +sil hidden @$matched_rr_loop : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_retain %0 : $Cls + strong_release %0 : $Cls + cond_br undef, bb1, bb2 + +bb2: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_aliasing_loop : +// CHECK: bb0(%0 : $S, %1 : $ChildCls): +// CHECK: retain_value %0 : $S +// CHECK: bb2: +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK-LABEL: } // end sil function '$unmatched_rr_aliasing_loop' +sil hidden @$unmatched_rr_aliasing_loop : $@convention(thin) (@owned S, ChildCls) -> () { +bb0(%0 : $S, %1 : $ChildCls): + retain_value %0 : $S + br bb1 + +bb1: + strong_release %1 : $ChildCls + strong_retain %1 : $ChildCls + cond_br undef, bb1, bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_aliasing_loop : +// CHECK: bb0(%0 : $S, %1 : $ChildCls): +// CHECK-NOT: retain_value %0 : $S +// CHECK: bb2: +// CHECK-NEXT: release_value %0 : $S +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_aliasing_loop' +sil hidden @$matched_rr_aliasing_loop : $@convention(thin) (@owned S, ChildCls) -> () { +bb0(%0 : $S, %1 : $ChildCls): + retain_value %0 : $S + br bb1 + +bb1: + strong_retain %1 : $ChildCls + strong_release %1 : $ChildCls + cond_br undef, bb1, bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_subobject_loop : +// CHECK: bb0(%0 : $Cls): +// CHECK: retain_value %0 : $Cls +// CHECK: bb2: +// CHECK: release_value %0 : $Cls +// CHECK: release_value %0 : $Cls +// CHECK-LABEL: } // end sil function '$unmatched_rr_subobject_loop' +sil hidden @$unmatched_rr_subobject_loop : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + retain_value %0 : $Cls + br bb1 + +bb1: + %1 = ref_element_addr %0 : $Cls, #Cls.child1 + %2 = load %1 : $*ChildCls + strong_release %2 : $ChildCls + strong_retain %2 : $ChildCls + cond_br undef, bb1, bb2 + +bb2: + release_value %0 : $Cls + release_value %0 : $Cls + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_subobject_loop : +// CHECK: bb0(%0 : $Cls): +// CHECK-NOT: retain_value %0 : $Cls +// CHECK: bb2: +// CHECK-NEXT: release_value %0 : $Cls +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_subobject_loop' +sil hidden @$matched_rr_subobject_loop : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + retain_value %0 : $Cls + br bb1 + +bb1: + %1 = ref_element_addr %0 : $Cls, #Cls.child1 + %2 = load %1 : $*ChildCls + strong_retain %2 : $ChildCls + strong_release %2 : $ChildCls + cond_br undef, bb1, bb2 + +bb2: + release_value %0 : $Cls + release_value %0 : $Cls + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_subobject_nested_knownsafety_loop : +// CHECK: bb0(%0 : $S): +// CHECK: retain_value %0 : $S +// CHECK: retain_value %0 : $S +// CHECK: bb2: +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK-LABEL: } // end sil function '$unmatched_rr_subobject_nested_knownsafety_loop' +sil hidden @$unmatched_rr_subobject_nested_knownsafety_loop : $@convention(thin) (@owned S) -> () { +bb0(%0 : $S): + retain_value %0 : $S + retain_value %0 : $S + br bb1 + +bb1: + %1 = struct_extract %0 : $S, #S.child1 + strong_release %1 : $ChildCls + strong_retain %1 : $ChildCls + cond_br undef, bb1, bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_loop_early_exit : +// CHECK: bb1 +// CHECK: strong_release %0 : $Cls +// CHECK: cond_br undef, bb3, bb2 +// CHECK: bb3: +// CHECK: strong_retain %0 : $Cls +// CHECK: cond_br undef, bb1, bb4 +// CHECK-LABEL: } // end sil function '$unmatched_rr_loop_early_exit' +sil hidden @$unmatched_rr_loop_early_exit : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_release %0 : $Cls + cond_br undef, bb2, bb3 + +bb2: + strong_retain %0 : $Cls + cond_br undef, bb1, bb3 + +bb3: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} + +// This case does not get optimized by KnownSafety as well. +// This is because the ref count state gets cleared due to non local successors while merging successors of bb1. +// So the retain/release within the loop do not get matched. And KnownSafety outside the loop gets cleared. +// CHECK-LABEL: sil hidden @$matched_rr_loop_early_exit : +// CHECK: bb1 +// CHECK: strong_retain %0 : $Cls +// CHECK: cond_br undef, bb3, bb2 +// CHECK: bb3: +// CHECK: strong_release %0 : $Cls +// CHECK: cond_br undef, bb1, bb4 +// CHECK-LABEL: } // end sil function '$matched_rr_loop_early_exit' +sil hidden @$matched_rr_loop_early_exit : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_retain %0 : $Cls + cond_br undef, bb2, bb3 + +bb2: + strong_release %0 : $Cls + cond_br undef, bb1, bb3 + +bb3: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_loop_early_exit_allowsleaks : +// CHECK: bb1 +// CHECK: strong_release %0 : $Cls +// CHECK: cond_br undef, bb2, bb3 +// CHECK: bb2: +// CHECK: strong_retain %0 : $Cls +// CHECK: cond_br undef, bb1, bb4 +// CHECK-LABEL: } // end sil function '$unmatched_rr_loop_early_exit_allowsleaks' +sil hidden @$unmatched_rr_loop_early_exit_allowsleaks : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_release %0 : $Cls + cond_br undef, bb2, bb3 + +bb2: + strong_retain %0 : $Cls + cond_br undef, bb1, bb4 + +bb3: + unreachable + +bb4: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} + +// Unlike $matched_rr_loop_early_exit this case gets optimized due to KnownSafety +// Since AllowsLeaks is set, we do not clear ref count state on seeing the non local successor in bb1 +// CHECK-LABEL: sil hidden @$matched_rr_loop_early_exit_allowsleaks : +// CHECK: bb1 +// CHECK-NOT: strong_release %0 : $Cls +// CHECK: cond_br undef, bb2, bb3 +// CHECK: bb2: +// CHECK-NOT: strong_retain %0 : $Cls +// CHECK: cond_br undef, bb1, bb4 +// CHECK-LABEL: } // end sil function '$matched_rr_loop_early_exit_allowsleaks' +sil hidden @$matched_rr_loop_early_exit_allowsleaks : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_retain %0 : $Cls + cond_br undef, bb2, bb3 + +bb2: + strong_release %0 : $Cls + cond_br undef, bb1, bb4 + +bb3: + unreachable + +bb4: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} diff --git a/test/SILOptimizer/cse.sil b/test/SILOptimizer/cse.sil index 60df4ccb7d4a6..dc56c783ec8e2 100644 --- a/test/SILOptimizer/cse.sil +++ b/test/SILOptimizer/cse.sil @@ -1306,3 +1306,53 @@ bb0(%0 : $@thick SpecialEnum.Type): %4 = struct $Bool (%3 : $Builtin.Int1) return %4 : $Bool } + +struct StructWithLazyProperty { + var lazyProperty: Int64 { mutating get set } + @_hasStorage @_hasInitialValue var lazyPropertyStorage : Int64? { get set } +} + +sil private [lazy_getter] [noinline] @lazy_getter : $@convention(method) (@inout StructWithLazyProperty) -> Int64 { +bb0(%0 : $*StructWithLazyProperty): + %2 = struct_element_addr %0 : $*StructWithLazyProperty, #StructWithLazyProperty.lazyPropertyStorage + %3 = load %2 : $*Optional + switch_enum %3 : $Optional, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2 + +bb1(%5 : $Int64): + br bb3(%5 : $Int64) + +bb2: + %9 = integer_literal $Builtin.Int64, 27 + %10 = struct $Int64 (%9 : $Builtin.Int64) + %12 = enum $Optional, #Optional.some!enumelt, %10 : $Int64 + store %12 to %2 : $*Optional + br bb3(%10 : $Int64) + +bb3(%15 : $Int64): + return %15 : $Int64 +} + +sil @take_int : $@convention(thin) (Int64) -> () + +// CHECK-LABEL: sil @dont_cse_lazy_property_of_overwritten_struct : $@convention(thin) () -> () { +// CHECK: [[GETTER:%[0-9]+]] = function_ref @lazy_getter +// CHECK: apply [[GETTER]] +// CHECK: apply [[GETTER]] +// CHECK: } // end sil function 'dont_cse_lazy_property_of_overwritten_struct' +sil @dont_cse_lazy_property_of_overwritten_struct : $@convention(thin) () -> () { +bb0: + %0 = alloc_stack $StructWithLazyProperty + %4 = enum $Optional, #Optional.none!enumelt + %5 = struct $StructWithLazyProperty (%4 : $Optional) + store %5 to %0 : $*StructWithLazyProperty + %7 = function_ref @lazy_getter : $@convention(method) (@inout StructWithLazyProperty) -> Int64 + %8 = apply %7(%0) : $@convention(method) (@inout StructWithLazyProperty) -> Int64 + %9 = function_ref @take_int : $@convention(thin) (Int64) -> () + %10 = apply %9(%8) : $@convention(thin) (Int64) -> () + store %5 to %0 : $*StructWithLazyProperty + %18 = apply %7(%0) : $@convention(method) (@inout StructWithLazyProperty) -> Int64 + %20 = apply %9(%18) : $@convention(thin) (Int64) -> () + dealloc_stack %0 : $*StructWithLazyProperty + %22 = tuple () + return %22 : $() +} diff --git a/test/SILOptimizer/definite_init_cross_module.swift b/test/SILOptimizer/definite_init_cross_module.swift index 2201cbf12c436..6a7f9debbbd1b 100644 --- a/test/SILOptimizer/definite_init_cross_module.swift +++ b/test/SILOptimizer/definite_init_cross_module.swift @@ -254,3 +254,27 @@ extension GenericEmpty { init(xx: Double) { } // expected-error {{'self.init' isn't called on all paths before returning from initializer}} } + +class AcceptsVisibleNoArgsDesignatedInit: VisibleNoArgsDesignatedInit { + var y: Float + init(y: Float) { + self.y = y + // no error + } +} + +open class InModuleVisibleNoArgsDesignatedInit { + var x: Float + public init() { x = 0.0 } + + // Add a designated init the subclass cannot see. + private init(x: Float) { self.x = x } +} + +class AcceptsInModuleVisibleNoArgsDesignatedInit: InModuleVisibleNoArgsDesignatedInit { + var y: Float + init(y: Float) { + self.y = y + // no error + } +} diff --git a/test/SILOptimizer/definite_init_root_class.swift b/test/SILOptimizer/definite_init_root_class.swift new file mode 100644 index 0000000000000..89d304d3c2169 --- /dev/null +++ b/test/SILOptimizer/definite_init_root_class.swift @@ -0,0 +1,214 @@ +// RUN: %target-swift-frontend -emit-sil %s | %FileCheck %s + +class OtherClass {} + +class FirstClass { + var x: OtherClass + + // CHECK-LABEL: sil hidden @$s24definite_init_root_class10FirstClassC1nACSgs5Int32V_tcfc : $@convention(method) (Int32, @owned FirstClass) -> @owned Optional + init?(n: Int32) { + // CHECK: [[CONTROL:%.*]] = alloc_stack $Builtin.Int1 + // CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int1, 0 + // CHECK: store [[ZERO]] to [[CONTROL]] : $*Builtin.Int1 + + // CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int32, 0 + // CHECK: [[N:%.*]] = struct_extract %0 : $Int32, #Int32._value + // CHECK: [[CMP:%.*]] = builtin "cmp_eq_Int32"([[N]] : $Builtin.Int32, [[ZERO]] : $Builtin.Int32) : $Builtin.Int1 + // CHECK: cond_br [[CMP]], bb1, bb2 + if n == 0 { + return nil + } + + // CHECK: bb1: + // CHECK: br bb5 + + // CHECK: bb2: + // CHECK: [[METATYPE:%.*]] = metatype $@thick OtherClass.Type + // CHECK: [[INIT:%.*]] = function_ref @$s24definite_init_root_class10OtherClassCACycfC : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[OTHER:%.*]] = apply [[INIT]]([[METATYPE]]) : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $FirstClass, #FirstClass.x + // CHECK: [[X_ACCESS:%.*]] = begin_access [modify] [dynamic] %15 : $*OtherClass + // CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int1, -1 + // CHECK: store [[ONE]] to [[CONTROL]] : $*Builtin.Int1 + // CHECK: store [[OTHER]] to [[X_ACCESS]] : $*OtherClass + // CHECK: end_access [[X_ACCESS]] : $*OtherClass + x = OtherClass() + + // CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int32, 1 + // CHECK: [[N:%.*]] = struct_extract %0 : $Int32, #Int32._value + // CHECK: [[CMP:%.*]] = builtin "cmp_eq_Int32"([[N]] : $Builtin.Int32, [[ONE]] : $Builtin.Int32) : $Builtin.Int1 + // CHECK: cond_br [[CMP]], bb3, bb4 + if n == 1 { + return nil + } + + // CHECK: bb3: + // CHECK: br bb5 + + // CHECK: bb4: + // CHECK: [[RESULT:%.*]] = enum $Optional, #Optional.some!enumelt, %1 : $FirstClass + // CHECK: br bb12([[RESULT]] : $Optional) + + // CHECK: bb5: + // CHECK: [[BIT:%.*]] = load [[CONTROL]] : $*Builtin.Int1 + // CHECK: cond_br [[BIT]], bb6, bb7 + + // CHECK: bb6: + // CHECK: strong_release %1 : $FirstClass + // CHECK: br bb11 + + // CHECK: bb7: + // CHECK: [[BIT:%.*]] = load [[CONTROL]] : $*Builtin.Int1 + // CHECK: cond_br [[BIT]], bb8, bb9 + + // CHECK: bb8: + // CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $FirstClass, #FirstClass.x + // CHECK: [[X_ACCESS:%.*]] = begin_access [deinit] [static] [[X_ADDR]] : $*OtherClass + // CHECK: destroy_addr [[X_ACCESS]] : $*OtherClass + // CHECK: end_access [[X_ACCESS]] : $*OtherClass + // CHECK: br bb10 + + // CHECK: bb9: + // CHECK: br bb10 + + // CHECK: [[METATYPE:%.*]] = metatype $@thick FirstClass.Type + // CHECK: dealloc_partial_ref %1 : $FirstClass, [[METATYPE]] : $@thick FirstClass.Type + // CHECK: br bb11 + + // CHECK: bb11: + // CHECK: [[NIL:%.*]] = enum $Optional, #Optional.none!enumelt + // CHECK: br bb12([[NIL]] : $Optional) + + // CHECK: bb12([[RESULT:%.*]] : $Optional): + // CHECK: dealloc_stack [[CONTROL]] : $*Builtin.Int1 + // CHECK: return [[RESULT]] : $Optional + } +} + +class SecondClass { + var x: OtherClass + var y: OtherClass + + // CHECK-LABEL: sil hidden @$s24definite_init_root_class11SecondClassC1nACSgs5Int32V_tcfc : $@convention(method) (Int32, @owned SecondClass) -> @owned Optional { + init?(n: Int32) { + // CHECK: [[CONTROL:%.*]] = alloc_stack $Builtin.Int2 + // CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int2, 0 + // CHECK: store [[ZERO]] to [[CONTROL]] : $*Builtin.Int2 + + // CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int32, 0 + // CHECK: [[N:%.*]] = struct_extract %0 : $Int32, #Int32._value + // CHECK: [[CMP:%.*]] = builtin "cmp_eq_Int32"([[N]] : $Builtin.Int32, [[ZERO]] : $Builtin.Int32) : $Builtin.Int1 + // CHECK: cond_br [[CMP]], bb1, bb2 + if n == 0 { + return nil + } + + // CHECK: bb1: + // CHECK: br bb7 + + // CHECK: bb2: + // CHECK: [[METATYPE:%.*]] = metatype $@thick OtherClass.Type + // CHECK: [[INIT:%.*]] = function_ref @$s24definite_init_root_class10OtherClassCACycfC : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[OTHER:%.*]] = apply [[INIT]]([[METATYPE]]) : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.x + // CHECK: [[X_ACCESS:%.*]] = begin_access [modify] [dynamic] [[X_ADDR]] : $*OtherClass + // CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int2, 1 + // CHECK: store [[ONE]] to [[CONTROL]] : $*Builtin.Int2 + // CHECK: store [[OTHER]] to [[X_ACCESS]] : $*OtherClass + // CHECK: end_access [[X_ACCESS]] : $*OtherClass + x = OtherClass() + + // CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int32, 1 + // CHECK: [[N:%.*]] = struct_extract %0 : $Int32, #Int32._value + // CHECK: [[CMP:%.*]] = builtin "cmp_eq_Int32"([[N]] : $Builtin.Int32, [[ONE]] : $Builtin.Int32) : $Builtin.Int1 + // CHECK: cond_br [[CMP]], bb3, bb4 + if n == 1 { + return nil + } + + // CHECK: bb3: + // CHECK: br bb7 + + // CHECK: bb4: + // CHECK: [[METATYPE:%.*]] = metatype $@thick OtherClass.Type + // CHECK: [[INIT:%.*]] = function_ref @$s24definite_init_root_class10OtherClassCACycfC : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[OTHER:%.*]] = apply [[INIT]]([[METATYPE]]) : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[Y_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.y + // CHECK: [[Y_ACCESS:%.*]] = begin_access [modify] [dynamic] [[Y_ADDR]] : $*OtherClass + // CHECK: [[THREE:%.*]] = integer_literal $Builtin.Int2, -1 + // CHECK: store [[THREE]] to [[CONTROL]] : $*Builtin.Int2 + // CHECK: store [[OTHER]] to [[Y_ACCESS]] : $*OtherClass + // CHECK: end_access [[Y_ACCESS]] : $*OtherClass + y = OtherClass() + + // CHECK: [[TWO:%.*]] = integer_literal $Builtin.Int32, 2 + // CHECK: [[N:%.*]] = struct_extract %0 : $Int32, #Int32._value + // CHECK: [[CMP:%.*]] = builtin "cmp_eq_Int32"([[N]] : $Builtin.Int32, [[TWO]] : $Builtin.Int32) : $Builtin.Int1 + // CHECK: cond_br [[CMP]], bb5, bb6 + if n == 2 { + return nil + } + + // CHECK: bb5: + // CHECK: br bb7 + + // CHECK: bb6: + // CHECK: [[RESULT:%.*]] = enum $Optional, #Optional.some!enumelt, %1 : $SecondClass + // CHECK: br bb17([[RESULT]] : $Optional) + + // CHECK: bb7: + // CHECK: [[BITS:%.*]] = load [[CONTROL]] : $*Builtin.Int2 + // CHECK: [[THREE:%.*]] = integer_literal $Builtin.Int2, -1 + // CHECK: [[BIT:%.*]] = builtin "cmp_eq_Int2"([[BITS]] : $Builtin.Int2, [[THREE]] : $Builtin.Int2) : $Builtin.Int1 + // CHECK: cond_br [[BIT]], bb8, bb9 + + // CHECK: bb8: + // CHECK: strong_release %1 : $SecondClass + // CHECK: br bb16 + + // CHECK: bb9: + // CHECK: [[BITS:%.*]] = load [[CONTROL]] : $*Builtin.Int2 + // CHECK: [[BIT:%.*]] = builtin "trunc_Int2_Int1"([[BITS]] : $Builtin.Int2) : $Builtin.Int1 + // CHECK: cond_br [[BIT]], bb10, bb11 + + // CHECK: bb10: + // CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.x + // CHECK: [[X_ACCESS:%.*]] = begin_access [deinit] [static] [[X_ADDR]] : $*OtherClass + // CHECK: destroy_addr [[X_ACCESS]] : $*OtherClass + // CHECK: end_access [[X_ACCESS]] : $*OtherClass + // CHECK: br bb12 + + // CHECK: bb11: + // CHECK: br bb12 + + // CHECK: bb12: + // CHECK: [[BITS:%.*]] = load [[CONTROL]] : $*Builtin.Int2 + // CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int2, 1 + // CHECK: [[TMP:%.*]] = builtin "lshr_Int2"([[BITS]] : $Builtin.Int2, [[ONE]] : $Builtin.Int2) : $Builtin.Int2 + // CHECK: [[BIT:%.*]] = builtin "trunc_Int2_Int1"([[TMP]] : $Builtin.Int2) : $Builtin.Int1 + // CHECK: cond_br [[BIT]], bb13, bb14 + + // CHECK: bb13: + // CHECK: [[Y_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.y + // CHECK: [[Y_ACCESS:%.*]] = begin_access [deinit] [static] [[Y_ADDR]] : $*OtherClass + // CHECK: destroy_addr [[Y_ACCESS]] : $*OtherClass + // CHECK: end_access [[Y_ACCESS]] : $*OtherClass + // CHECK: br bb15 + + // CHECK: bb14: + // CHECK: br bb15 + + // CHECK: bb15: + // CHECK: [[METATYPE:%.*]] = metatype $@thick SecondClass.Type + // CHECK: dealloc_partial_ref %1 : $SecondClass, [[METATYPE]] : $@thick SecondClass.Type + // CHECK: br bb16 + + // CHECK: bb16: + // CHECK: [[NIL:%.*]] = enum $Optional, #Optional.none!enumelt + // CHECK: br bb17([[NIL]] : $Optional) + + // CHECK: bb17([[RESULT:%.*]] : $Optional): + // CHECK: dealloc_stack [[CONTROL]] : $*Builtin.Int2 + // CHECK: return [[RESULT]] : $Optional + } +} diff --git a/test/SILOptimizer/escape_analysis.sil b/test/SILOptimizer/escape_analysis.sil index bc8b42ba2426d..21944bbe21603 100644 --- a/test/SILOptimizer/escape_analysis.sil +++ b/test/SILOptimizer/escape_analysis.sil @@ -1983,3 +1983,27 @@ bb4: %z = tuple () return %z : $() } + +// Test CGNode mapping for result of an apply to no return function +// CHECK-LABEL:CG of $testcaller +// CHECK: Arg [ref] %0 Esc: A, Succ: (%0.1) +// CHECK: Con [int] %0.1 Esc: A, Succ: (%0.2) +// CHECK: Con [ref] %0.2 Esc: A, Succ: +// CHECK-LABEL:End +sil hidden [noinline] @$testcaller : $@convention(thin) (@owned Z) -> () { +bb0(%0 : $Z): + %2 = function_ref @$noreturncallee : $@convention(thin) (@guaranteed Z) -> @owned Z + %3 = apply %2(%0) : $@convention(thin) (@guaranteed Z) -> @owned Z + dealloc_ref %3 : $Z + %5 = tuple () + return %5 : $() +} + +// CHECK-LABEL:CG of $noreturncallee +// CHECK: Arg [ref] %0 Esc: A, Succ: +// CHECK-LABEL:End +sil hidden [noinline] @$noreturncallee : $@convention(thin) (@guaranteed Z) -> @owned Z { +bb0(%0 : $Z): + unreachable +} + diff --git a/test/SILOptimizer/floating_point_conversion.swift b/test/SILOptimizer/floating_point_conversion.swift new file mode 100644 index 0000000000000..fb3c84fdc05b0 --- /dev/null +++ b/test/SILOptimizer/floating_point_conversion.swift @@ -0,0 +1,25 @@ +// RUN: %target-swift-frontend -O -module-name=test -emit-sil %s | %FileCheck %s + +func convert< + T: BinaryFloatingPoint, U: BinaryFloatingPoint + >(_ value: T, to: U.Type) -> U { + U(value) +} + +// Check that the follwing functions can be optimized to no-ops. + +// CHECK-LABEL: sil @$s4test0A6DoubleyS2dF +// CHECK: return %0 +// CHECK: } // end sil function '$s4test0A6DoubleyS2dF' +public func testDouble(_ x: Double) -> Double { + return convert(x, to: Double.self) +} + +// CHECK-LABEL: sil @$s4test0A5FloatyS2fF +// CHECK: return %0 +// CHECK: } // end sil function '$s4test0A5FloatyS2fF' +public func testFloat(_ x: Float) -> Float { + return convert(x, to: Float.self) +} + + diff --git a/test/SILOptimizer/globalopt_trivial_nontrivial.sil b/test/SILOptimizer/globalopt_trivial_nontrivial.sil index 3625c10946211..8f094f633febb 100644 --- a/test/SILOptimizer/globalopt_trivial_nontrivial.sil +++ b/test/SILOptimizer/globalopt_trivial_nontrivial.sil @@ -38,7 +38,7 @@ sil_global private @globalinit_nontrivialglobal_token : $Builtin.Word sil_global hidden [let] @$nontrivialglobal : $TClass -sil private @globalinit_trivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] @globalinit_trivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$trivialglobal %1 = global_addr @$trivialglobal : $*TStruct @@ -83,13 +83,13 @@ bb0: return %4 : $Int32 } -// CHECK-LABEL: sil private @globalinit_nontrivialglobal_func : +// CHECK-LABEL: sil private [global_init_once_fn] @globalinit_nontrivialglobal_func : // CHECK: alloc_global @$nontrivialglobal // CHECK: [[GLOBL_ADDR:%.*]] = global_addr @$nontrivialglobal : $*TClass // CHECK: [[REF:%.*]] = alloc_ref $TClass // CHECK: store [[REF]] to [[GLOBL_ADDR]] : $*TClass // CHECK: } // end sil function 'globalinit_nontrivialglobal_func' -sil private @globalinit_nontrivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] @globalinit_nontrivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$nontrivialglobal %1 = global_addr @$nontrivialglobal : $*TClass diff --git a/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil b/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil index 182210cb2671e..433aff21f011f 100644 --- a/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil +++ b/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil @@ -32,7 +32,7 @@ sil_global private @globalinit_nontrivialglobal_token : $Builtin.Word sil_global hidden [let] @$nontrivialglobal : $TClass -sil private [ossa] @globalinit_trivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] [ossa] @globalinit_trivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$trivialglobal %1 = global_addr @$trivialglobal : $*TStruct @@ -75,13 +75,13 @@ bb0: return %4 : $Int32 } -// CHECK-LABEL: sil private [ossa] @globalinit_nontrivialglobal_func : +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_nontrivialglobal_func : // CHECK: alloc_global @$nontrivialglobal // CHECK: [[GLOBL_ADDR:%.*]] = global_addr @$nontrivialglobal : $*TClass // CHECK: [[REF:%.*]] = alloc_ref $TClass // CHECK: store [[REF]] to [init] [[GLOBL_ADDR]] : $*TClass // CHECK: } // end sil function 'globalinit_nontrivialglobal_func' -sil private [ossa] @globalinit_nontrivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] [ossa] @globalinit_nontrivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$nontrivialglobal %1 = global_addr @$nontrivialglobal : $*TClass diff --git a/test/SILOptimizer/ignore-always-inline.sil b/test/SILOptimizer/ignore-always-inline.sil new file mode 100644 index 0000000000000..49d98e870a4f1 --- /dev/null +++ b/test/SILOptimizer/ignore-always-inline.sil @@ -0,0 +1,71 @@ +// RUN: %target-sil-opt -enable-sil-verify-all %s -inline -dce | %FileCheck %s -check-prefix=REGULAR +// RUN: %target-sil-opt -enable-sil-verify-all %s -inline -dce -ignore-always-inline | %FileCheck %s -check-prefix=IGNORED + +sil_stage canonical + +// REGULAR: sil [Osize] @caller +// IGNORED: sil [Osize] @caller +sil [Osize] @caller : $@convention(thin) () -> () { +bb0: + // REGULAR-NOT: function_ref @callee + // REGULAR: function_ref @foobar + // IGNORED: function_ref @callee + %d1 = function_ref @callee : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + + %9999 = tuple() + return %9999 : $() +} + +sil @foobar : $@convention(thin) () -> () + +// callee is "expensive" enough to not get inlined unless [always_inline] is used +// REGULAR: sil [always_inline] [Osize] @callee +// IGNORED: sil [always_inline] [Osize] @callee +sil [always_inline] [Osize] @callee : $@convention(thin) () -> () { +bb0: + %d1 = function_ref @foobar : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + + %9999 = tuple() + return %9999 : $() +} diff --git a/test/SILOptimizer/inline_addressor.swift b/test/SILOptimizer/inline_addressor.swift index c78e0a25c5f41..369799a725370 100644 --- a/test/SILOptimizer/inline_addressor.swift +++ b/test/SILOptimizer/inline_addressor.swift @@ -11,10 +11,10 @@ var totalsum = nonTrivialInit(true) //CHECK-LABEL: sil {{.*}}testit //CHECK: {{^bb0}} -//CHECK: globalinit_ +//CHECK: WZ //CHECK-NOT: {{^bb0}} //CHECK: {{^bb1}} -//CHECK-NOT: globalinit +//CHECK-NOT: WZ //CHECK-NOT: totalsum //CHECK-NOT: inputval //CHECK: {{^}$}} diff --git a/test/SILOptimizer/inline_generics.sil b/test/SILOptimizer/inline_generics.sil index 5ba0af36fdfbb..2ca1b70b7b188 100644 --- a/test/SILOptimizer/inline_generics.sil +++ b/test/SILOptimizer/inline_generics.sil @@ -47,55 +47,6 @@ bb0(%0 : $*T, %1 : $*T): return %9 : $() } // end sil function 'testInliningOfGenerics' -sil hidden @P_combine : $@convention(method) (@in T, @guaranteed Self) -> @owned @callee_owned (@in T) -> Bool { -bb0(%0 : $*T, %1 : $Self): - // function_ref P.(combine (first : A1) -> (A1) -> Bool).(closure #1) - %4 = function_ref @_TFFE50generic_inlining_partial_apply_opened_existentialsPS_1P7combineurFT5firstqd___Fqd__SbU_Fqd__Sb : $@convention(thin) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0) -> Bool - %5 = partial_apply %4() : $@convention(thin) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0) -> Bool - destroy_addr %0 : $*T - return %5 : $@callee_owned (@in T) -> Bool -} // end sil function 'P_combine' - -// P.(combine (first : A1) -> (A1) -> Bool).(closure #1) -sil shared @_TFFE50generic_inlining_partial_apply_opened_existentialsPS_1P7combineurFT5firstqd___Fqd__SbU_Fqd__Sb : $@convention(thin) (@in T) -> Bool { -bb0(%0 : $*T): - %2 = integer_literal $Builtin.Int1, -1 - %3 = struct $Bool (%2 : $Builtin.Int1) - destroy_addr %0 : $*T - return %3 : $Bool -} // end sil function '_TFFE50generic_inlining_partial_apply_opened_existentialsPS_1P7combineurFT5firstqd___Fqd__SbU_Fqd__Sb' - - -// Check that P_combine is not inlined into the generic function, because -// doing so would result in a partial_apply instruction, with an opened existential -// in the substitution list. And this cannot be handled by the IRGen yet. -// CHECK-LABEL: sil @dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list -// CHECK: [[FUN_REF:%[0-9]+]] = function_ref @P_combine -// CHECK: apply [[FUN_REF]] -// CHECK: end sil function 'dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list' -sil @dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list : $@convention(thin) (@owned P) -> @owned @callee_owned (@owned T) -> Bool { -bb0(%0 : $P): - %2 = open_existential_ref %0 : $P to $@opened("41B148C8-F49C-11E6-BE69-A45E60E99281") P - // function_ref P.combine (first : A1) -> (A1) -> Bool - %3 = function_ref @P_combine : $@convention(method) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0, @guaranteed τ_0_0) -> @owned @callee_owned (@in τ_1_0) -> Bool - %4 = open_existential_ref %0 : $P to $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P - %5 = witness_method $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P, #P.getSelf : (Self) -> () -> Self, %4 : $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0 - %6 = apply %5<@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P>(%4) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0 - %7 = init_existential_ref %6 : $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P : $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P, $P - %8 = alloc_stack $P - store %7 to %8 : $*P - %10 = apply %3<@opened("41B148C8-F49C-11E6-BE69-A45E60E99281") P, P>(%8, %2) : $@convention(method) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0, @guaranteed τ_0_0) -> @owned @callee_owned (@in τ_1_0) -> Bool - // function_ref thunk - %11 = function_ref @thunk1 : $@convention(thin) (@owned P, @owned @callee_owned (@in P) -> Bool) -> Bool - %12 = partial_apply %11(%10) : $@convention(thin) (@owned P, @owned @callee_owned (@in P) -> Bool) -> Bool - // function_ref thunk - %13 = function_ref @thunk2 : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned τ_0_0, @owned @callee_owned (@owned P) -> Bool) -> Bool - %14 = partial_apply %13(%12) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned τ_0_0, @owned @callee_owned (@owned P) -> Bool) -> Bool - dealloc_stack %8 : $*P - strong_release %0 : $P - return %14 : $@callee_owned (@owned T) -> Bool -} // end sil function 'dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list' - // thunk sil shared [transparent] [reabstraction_thunk] @thunk1 : $@convention(thin) (@owned P, @owned @callee_owned (@in P) -> Bool) -> Bool { bb0(%0 : $P, %1 : $@callee_owned (@in P) -> Bool): diff --git a/test/SILOptimizer/lazy_property_getters.swift b/test/SILOptimizer/lazy_property_getters.swift index e3e8b9d1eb7b1..2880d06cd8758 100644 --- a/test/SILOptimizer/lazy_property_getters.swift +++ b/test/SILOptimizer/lazy_property_getters.swift @@ -88,20 +88,42 @@ func test_no_hoisting(_ c: Myclass, _ b: Bool) -> Int { return v } +// This test is disabled, because for structs, it does not work yet. +// CSE is too conservative to handle indirect getter arguments currently. + // CHECK-LABEL: sil {{.*}} @$s4test0A7_structySiAA8MystructVF +// CHECK-DISABLED: [[GETTER:%[0-9]+]] = function_ref @$s4test8MystructV4lvarSivg +// CHECK-DISABLED: [[V1:%[0-9]+]] = apply [[GETTER]]({{.*}}) +// CHECK-DISABLED: [[V2OPT:%[0-9]+]] = load +// CHECK-DISABLED: [[V2:%[0-9]+]] = unchecked_enum_data [[V2OPT]] +// CHECK-DISABLED: [[V1VAL:%[0-9]+]] = struct_extract [[V1]] +// CHECK-DISABLED: [[V2VAL:%[0-9]+]] = struct_extract [[V2]] +// CHECK-DISABLED: builtin "sadd{{.*}}"([[V1VAL]] {{.*}}, [[V2VAL]] +// CHECK-DISABLED: } // end sil function '$s4test0A7_structySiAA8MystructVF' +@inline(never) +func test_struct(_ s: Mystruct) -> Int { + var sm = s + g = 42 + let v1 = sm.lvar + let v2 = sm.lvar + return v1 &+ v2 +} + +// CHECK-LABEL: sil {{.*}} @$s4test0A19_overwritten_structySiAA8MystructVF // CHECK: [[GETTER:%[0-9]+]] = function_ref @$s4test8MystructV4lvarSivg // CHECK: [[V1:%[0-9]+]] = apply [[GETTER]]({{.*}}) -// CHECK: [[V2OPT:%[0-9]+]] = load -// CHECK: [[V2:%[0-9]+]] = unchecked_enum_data [[V2OPT]] +// CHECK: [[V2:%[0-9]+]] = apply [[GETTER]]({{.*}}) // CHECK: [[V1VAL:%[0-9]+]] = struct_extract [[V1]] // CHECK: [[V2VAL:%[0-9]+]] = struct_extract [[V2]] // CHECK: builtin "sadd{{.*}}"([[V1VAL]] {{.*}}, [[V2VAL]] -// CHECK: } // end sil function '$s4test0A7_structySiAA8MystructVF' +// CHECK: } // end sil function '$s4test0A19_overwritten_structySiAA8MystructVF' @inline(never) -func test_struct(_ s: Mystruct) -> Int { +func test_overwritten_struct(_ s: Mystruct) -> Int { var sm = s g = 42 let v1 = sm.lvar + sm = s + g = 43 let v2 = sm.lvar return v1 &+ v2 } @@ -133,6 +155,13 @@ func calltests() { // CHECK-OUTPUT-NEXT: lvar init // CHECK-OUTPUT-NEXT: 84 print(test_struct(Mystruct())) + + // CHECK-OUTPUT-LABEL: test_overwritten_struct + print("test_overwritten_struct") + // CHECK-OUTPUT-NEXT: lvar init + // CHECK-OUTPUT-NEXT: lvar init + // CHECK-OUTPUT-NEXT: 85 + print(test_overwritten_struct(Mystruct())) } calltests() diff --git a/test/SILOptimizer/licm.sil b/test/SILOptimizer/licm.sil index 6823dda54a085..9ac8ae2492cba 100644 --- a/test/SILOptimizer/licm.sil +++ b/test/SILOptimizer/licm.sil @@ -854,3 +854,82 @@ bb9(%39 : $Builtin.Int64): // Preds: bb7 dealloc_stack %3 : $*Index // id: %41 return %40 : $Int64 // id: %42 } + +// testConditionalTrapInInfiniteSyncLoop and +// testConditionalTrapDominatingSyncLoopExit +// +// It's legal for the optimizer to consider code after the loop as +// always reachable, but when a loop has no exits, or when the loops +// exits are dominated by a conditional statement we should not +// consider conditional statements within the loop as dominating all +// possible execution paths through the loop. At least not when there +// is at least one path through the loop that contains a +// "synchronization point", such as a function that may contain a +// memory barrier, perform I/O, or exit the program. +sil @mayExit : $@convention(thin) () -> () + +// CHECK-LABEL: sil @testConditionalTrapInInfiniteSyncLoop : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () { +// CHECK: bb0 +// CHECK-NOT: cond_fail +// CHECK: br bb1 +// CHECK: bb1: +// CHECK: cond_br %0, bb2, bb3 +// CHECK: bb2: +// CHECK: cond_fail %1 : $Builtin.Int1, "arithmetic overflow" +// CHECK-LABEL: } // end sil function 'testConditionalTrapInInfiniteSyncLoop' +sil @testConditionalTrapInInfiniteSyncLoop : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () { +bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1): + br bb1 + +bb1: // loop head + cond_br %0, bb2, bb3 + +bb2: // maybe never executed + cond_fail %1 : $Builtin.Int1, "arithmetic overflow" + br bb4 + +bb3: + // synchronization point: has "real" side-effects that we can't + // reorder with traps + %f = function_ref @mayExit : $@convention(thin) () -> () + apply %f() : $@convention(thin) () -> () + br bb4 + +bb4: // latch + br bb1 +} + +// CHECK-LABEL: sil @testConditionalTrapDominatingSyncLoopExit : $@convention(thin) (Builtin.Int1, Builtin.Int1, Builtin.Int1) -> () { +// CHECK: bb0 +// CHECK-NOT: cond_fail +// CHECK: br bb1 +// CHECK: bb1: +// CHECK: cond_br %0, bb2, bb4 +// CHECK: bb2: +// CHECK: cond_fail %1 : $Builtin.Int1, "arithmetic overflow" +// CHECK-LABEL: } // end sil function 'testConditionalTrapDominatingSyncLoopExit' +sil @testConditionalTrapDominatingSyncLoopExit : $@convention(thin) (Builtin.Int1, Builtin.Int1, Builtin.Int1) -> () { +bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1, %2 : $Builtin.Int1): + br bb1 + +bb1: // loop head + cond_br %0, bb2, bb4 + +bb2: // maybe never executed + cond_fail %1 : $Builtin.Int1, "arithmetic overflow" + cond_br %2, bb3, bb5 + +bb3: // tail + br bb1 + +bb4: + // synchronization point: has "real" side-effects that we can't + // reorder with traps + %f = function_ref @mayExit : $@convention(thin) () -> () + apply %f() : $@convention(thin) () -> () + br bb1 + +bb5: + %99 = tuple () + return %99 : $() +} diff --git a/test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift b/test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift new file mode 100644 index 0000000000000..9c49cd002cf51 --- /dev/null +++ b/test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift @@ -0,0 +1,16 @@ +// RUN: %target-swiftc_driver -O -Rpass-missed=sil-opt-remark-gen -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil %s -o /dev/null -Xfrontend -verify -Xllvm -optremarkgen-visit-implicit-autogen-funcs=1 + +// From the constructor. +class Klass {} // expected-remark {{heap allocated ref of type 'Klass'}} + +struct KlassPair { + var lhs: Klass // expected-remark {{retain of type 'Klass'}} + // expected-note @-1 {{of 'self.lhs'}} + // expected-remark @-2 {{release of type 'Klass'}} + // expected-note @-3 {{of 'self.lhs'}} + var rhs: Klass // expected-remark {{retain of type 'Klass'}} + // expected-note @-1 {{of 'self.rhs'}} + // expected-remark @-2 {{release of type 'Klass'}} + // expected-note @-3 {{of 'self.rhs'}} +} + diff --git a/test/SILOptimizer/opt-remark-generator-semantics.swift b/test/SILOptimizer/opt-remark-generator-semantics.swift index 513d7d3ef7cb3..ab39837098cb2 100644 --- a/test/SILOptimizer/opt-remark-generator-semantics.swift +++ b/test/SILOptimizer/opt-remark-generator-semantics.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-sil %s -verify -Osize +// RUN: %target-swift-frontend -emit-sil %s -verify -Osize -o /dev/null -module-name main // // NOTE: We only emit opt-remarks with -Osize,-O today! -O does drop way more // stuff though, so we test with -Osize. @@ -7,29 +7,41 @@ public class Klass {} public var mySingleton = Klass() +@inline(never) +func getGlobal() -> Klass { + return mySingleton +} + +@inline(never) +func useKlass(_ k: Klass) {} + @_semantics("optremark") @inline(never) -public func forceOptRemark() -> Klass { - return mySingleton // expected-remark {{retain}} - // expected-note @-6 {{of 'mySingleton'}} +public func forceOptRemark() { + let x = getGlobal() + useKlass(x) // expected-remark {{release of type 'Klass'}} + // expected-note @-2 {{of 'x'}} } @_semantics("optremark.sil-opt-remark-gen") @inline(never) -public func forceOptRemark2() -> Klass { - return mySingleton // expected-remark {{retain}} - // expected-note @-13 {{of 'mySingleton'}} +public func forceOptRemark2() { + let x = getGlobal() + useKlass(x) // expected-remark {{release of type 'Klass'}} + // expected-note @-2 {{of 'x'}} } @_semantics("optremark.fail") @inline(never) -public func failMatch() -> Klass { - return mySingleton +public func failMatch() { + let x = getGlobal() + useKlass(x) } @_semantics("optremark") public func allocateInlineCallee() -> Klass { return Klass() // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} + // expected-remark @-1 {{heap allocated ref of type 'Klass'}} } @_semantics("optremark.sil-inliner") @@ -45,29 +57,31 @@ public func allocateInlineCallee3() -> Klass { @_semantics("optremark.sil-inliner") @_semantics("optremark.sil-opt-remark-gen") public func mix1() -> (Klass, Klass) { - return (mySingleton, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} - // expected-remark @-1:5 {{retain}} - // expected-note @-42:12 {{of 'mySingleton'}} + let x = getGlobal() + return (x, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} + // expected-remark @-1:16 {{heap allocated ref of type 'Klass'}} } @_semantics("optremark.sil-inliner") public func mix2() -> (Klass, Klass) { - return (mySingleton, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} + let x = getGlobal() + return (x, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} } @_semantics("optremark.sil-opt-remark-gen") public func mix3() -> (Klass, Klass) { - return (mySingleton, Klass()) // expected-remark @:5 {{retain}} - // expected-note @-53:12 {{of 'mySingleton'}} + let x = getGlobal() + return (x, Klass()) // expected-remark {{heap allocated ref of type 'Klass'}} } @_semantics("optremark") public func mix4() -> (Klass, Klass) { - return (mySingleton, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} - // expected-remark @-1:5 {{retain}} - // expected-note @-60:12 {{of 'mySingleton'}} + let x = getGlobal() + return (x, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} + // expected-remark @-1 {{heap allocated ref of type 'Klass'}} } public func mix5() -> (Klass, Klass) { - return (mySingleton, Klass()) + let x = getGlobal() + return (x, Klass()) } diff --git a/test/SILOptimizer/opt-remark-generator-yaml.swift b/test/SILOptimizer/opt-remark-generator-yaml.swift index 11e3dbb7f9d25..13a9301f1546d 100644 --- a/test/SILOptimizer/opt-remark-generator-yaml.swift +++ b/test/SILOptimizer/opt-remark-generator-yaml.swift @@ -1,4 +1,3 @@ -// REQUIRES: rdar66330768 // RUN: %target-swiftc_driver -O -Rpass-missed=sil-opt-remark-gen -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil %s -o /dev/null -Xfrontend -verify // RUN: %empty-directory(%t) @@ -10,7 +9,18 @@ public class Klass {} -public var global = Klass() +// CHECK: --- !Missed +// CHECK-NEXT: Pass: sil-opt-remark-gen +// CHECK-NEXT: Name: sil.memory +// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift', +// CHECK-NEXT: Line: [[# @LINE + 7 ]], Column: 21 } +// CHECK-NEXT: Function: main +// CHECK-NEXT: Args: +// CHECK-NEXT: - String: 'heap allocated ref of type ''' +// CHECK-NEXT: - ValueType: Klass +// CHECK-NEXT: - String: '''' +// CHECK-NEXT: ... +public var global = Klass() // expected-remark {{heap allocated ref of type 'Klass'}} // CHECK: --- !Missed // CHECK-NEXT: Pass: sil-opt-remark-gen @@ -32,6 +42,17 @@ public func getGlobal() -> Klass { // expected-note @-19:12 {{of 'global'}} } +// CHECK: --- !Missed +// CHECK-NEXT: Pass: sil-opt-remark-gen +// CHECK-NEXT: Name: sil.memory +// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift', +// CHECK-NEXT: Line: [[# @LINE + 51]], Column: 11 } +// CHECK-NEXT: Function: 'useGlobal()' +// CHECK-NEXT: Args: +// CHECK-NEXT: - String: 'heap allocated ref of type ''' +// CHECK-NEXT: - ValueType: +// CHECK-NEXT: - String: '''' +// CHECK-NEXT: ... // CHECK-NEXT: --- !Missed // CHECK-NEXT: Pass: sil-opt-remark-gen // CHECK-NEXT: Name: sil.memory @@ -54,7 +75,7 @@ public func getGlobal() -> Klass { // CHECK-NEXT: Function: 'useGlobal()' // CHECK-NEXT: Args: // CHECK-NEXT: - String: 'release of type ''' -// CHECK-NEXT: - ValueType: {{'Array'|__ContiguousArrayStorageBase}} +// CHECK-NEXT: - ValueType: // CHECK-NEXT: - String: '''' // CHECK-NEXT: ... // CHECK-NEXT: --- !Missed @@ -76,10 +97,11 @@ public func useGlobal() { let x = getGlobal() // Make sure that the retain msg is at the beginning of the print and the // releases are the end of the print. - print(x) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-4:9 {{of 'x'}} + print(x) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-5:9 {{of 'x'}} // We test the type emission above since FileCheck can handle regex. - // expected-remark @-3:12 {{release of type}} - // expected-remark @-4:12 {{release of type 'Klass'}} - // expected-note @-8:9 {{of 'x'}} + // expected-remark @-4:12 {{release of type}} + // expected-remark @-5:12 {{release of type 'Klass'}} + // expected-note @-9:9 {{of 'x'}} } diff --git a/test/SILOptimizer/opt-remark-generator.sil b/test/SILOptimizer/opt-remark-generator.sil index b8ddadb6d1ac0..4e10c7fd151ac 100644 --- a/test/SILOptimizer/opt-remark-generator.sil +++ b/test/SILOptimizer/opt-remark-generator.sil @@ -1,15 +1,86 @@ -// RUN: %target-sil-opt -sil-opt-remark-generator -sil-remarks-missed=sil-opt-remark-gen -verify %s -o /dev/null +// RUN: %target-sil-opt -sil-opt-remark-ignore-always-infer -optremarkgen-declless-debugvalue-use-sildebugvar-info -sil-opt-remark-generator -sil-remarks-missed=sil-opt-remark-gen -verify %s -o /dev/null sil_stage canonical import Builtin -sil @foo : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { +////////////////// +// Declarations // +////////////////// + +class Klass {} + +enum TrivialState { +case first +case second +case third +} + +struct StructWithOwner { + var owner: Klass + var state: TrivialState +} + +struct KlassPair { + var lhs: Klass + var rhs: Klass +} + +struct StructWithOwnerAndState { + var structWithOwner: StructWithOwner + var state: TrivialState +} + +/////////// +// Tests // +/////////// + +sil @simple : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { bb0(%0 : $Builtin.NativeObject): - strong_retain %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} - retain_value %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} + debug_value %0 : $Builtin.NativeObject, let, name "arg" + strong_retain %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} + // expected-note @-2 {{of 'arg'}} + retain_value %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} + // expected-note @-4 {{of 'arg'}} strong_release %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}} - release_value %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}} + // expected-note @-6 {{of 'arg'}} + release_value %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}} + // expected-note @-8 {{of 'arg'}} %9999 = tuple() return %9999 : $() } + +sil @extract_out_singleobj_struct_subfield_1 : $@convention(thin) (@guaranteed StructWithOwner) -> Klass { +bb0(%0 : $StructWithOwner): + debug_value %0 : $StructWithOwner, let, name "x" + %1 = struct_extract %0 : $StructWithOwner, #StructWithOwner.owner + strong_retain %1 : $Klass // expected-remark {{retain of type 'Klass'}} + // expected-note @-3 {{of 'x.owner'}} + return %1 : $Klass +} + +// This case should never actually happen like this, but we should handle it in +// a sane way by printing both notes for y and x and also make sure that we do +// not infer .owner on y since y is on owner itself. +sil @extract_out_singleobj_struct_subfield_multiple_debugvalue : $@convention(thin) (@guaranteed StructWithOwner) -> Klass { +bb0(%0 : $StructWithOwner): + debug_value %0 : $StructWithOwner, let, name "x" + %1 = struct_extract %0 : $StructWithOwner, #StructWithOwner.owner + debug_value %1 : $Klass, let, name "y" + strong_retain %1 : $Klass // expected-remark {{retain of type 'Klass'}} + // expected-note @-4 {{of 'x.owner'}} + // expected-note @-3 {{of 'y'}} + return %1 : $Klass +} + +// In this case, we emit the remark for x since its operand %2 is rc-identical +// to %0 the value we found while traversing our access path. +sil @rcidentity_based_use : $@convention(thin) (@guaranteed StructWithOwner, TrivialState) -> @owned Klass { +bb0(%0 : $StructWithOwner, %1 : $TrivialState): + %2 = struct $StructWithOwnerAndState(%0 : $StructWithOwner, %1 : $TrivialState) + debug_value %2 : $StructWithOwnerAndState, let, name "x" + %3 = struct_extract %0 : $StructWithOwner, #StructWithOwner.owner + strong_retain %3 : $Klass // expected-remark {{retain of type 'Klass'}} + // expected-note @-3 {{of 'x'}} + return %3 : $Klass +} diff --git a/test/SILOptimizer/opt-remark-generator.swift b/test/SILOptimizer/opt-remark-generator.swift index ed32d18dae885..6aedcd8ca8dc8 100644 --- a/test/SILOptimizer/opt-remark-generator.swift +++ b/test/SILOptimizer/opt-remark-generator.swift @@ -1,9 +1,13 @@ // RUN: %target-swiftc_driver -O -Rpass-missed=sil-opt-remark-gen -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil %s -o /dev/null -Xfrontend -verify // REQUIRES: optimized_stdlib +// XFAIL: OS=linux-androideabi && CPU=armv7 + public class Klass {} -public var global = Klass() +// TODO: Change global related code to be implicit/autogenerated (as +// appropriate) so we don't emit this remark. +public var global = Klass() // expected-remark {{heap allocated ref of type 'Klass'}} @inline(never) public func getGlobal() -> Klass { @@ -11,15 +15,20 @@ public func getGlobal() -> Klass { // expected-note @-5:12 {{of 'global'}} } +// Make sure that the retain msg is at the beginning of the print and the +// releases are the end of the print. +// +// The heap allocated ref is for the temporary array and the release that is +// unannotated is for that array as well. We make sure that the heap allocated +// ref is on the argument that necessitated its creation. public func useGlobal() { let x = getGlobal() - // Make sure that the retain msg is at the beginning of the print and the - // releases are the end of the print. - print(x) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-4:9 {{of 'x'}} - // expected-remark @-2:12 {{release of type}} - // expected-remark @-3:12 {{release of type 'Klass'}} - // expected-note @-7:9 {{of 'x'}} + print(x) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-3:9 {{of 'x'}} + // expected-remark @-3:12 {{release of type}} + // expected-remark @-4:12 {{release of type 'Klass'}} + // expected-note @-6:9 {{of 'x'}} } public enum TrivialState { @@ -29,27 +38,21 @@ case third } struct StructWithOwner { - // This retain is from the initializers of owner. - // - // TODO: Should we emit this? - var owner = Klass() // expected-remark {{retain of type 'Klass'}} - // expected-note @-1 {{of 'self.owner'}} - // expected-remark @-2 {{release of type 'Klass'}} - // expected-note @-3 {{of 'self.owner'}} + var owner = Klass() var state = TrivialState.first } func printStructWithOwner(x : StructWithOwner) { - print(x) // expected-remark {{retain of type 'Klass'}} - // expected-note @-2:27 {{of 'x.owner'}} - // We should be able to infer the arg here. + print(x) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1 {{retain of type 'Klass'}} + // expected-note @-3:27 {{of 'x.owner'}} // expected-remark @-3:12 {{release of type}} } func printStructWithOwnerOwner(x : StructWithOwner) { - print(x.owner) // expected-remark {{retain of type 'Klass'}} - // expected-note @-2:32 {{of 'x.owner'}} - // We should be able to infer the arg here. + print(x.owner) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1 {{retain of type 'Klass'}} + // expected-note @-3:32 {{of 'x.owner'}} // expected-remark @-3:18 {{release of type}} } @@ -64,37 +67,33 @@ func callingAnInitializerStructWithOwner(x: Klass) -> StructWithOwner { } struct KlassPair { - var lhs: Klass // expected-remark {{retain of type 'Klass'}} - // expected-note @-1 {{of 'self.lhs'}} - // expected-remark @-2 {{release of type 'Klass'}} - // expected-note @-3 {{of 'self.lhs'}} - var rhs: Klass // expected-remark {{retain of type 'Klass'}} - // expected-note @-1 {{of 'self.rhs'}} - // expected-remark @-2 {{release of type 'Klass'}} - // expected-note @-3 {{of 'self.rhs'}} + var lhs: Klass + var rhs: Klass } func printKlassPair(x : KlassPair) { // We pattern match columns to ensure we get retain on the p and release on // the end ')' - print(x) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-4:21 {{of 'x.lhs'}} - // expected-remark @-2:5 {{retain of type 'Klass'}} - // expected-note @-6:21 {{of 'x.rhs'}} - // This is a release for Array for print. + print(x) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-5:21 {{of 'x.lhs'}} + // expected-remark @-3:5 {{retain of type 'Klass'}} + // expected-note @-7:21 {{of 'x.rhs'}} // expected-remark @-5:12 {{release of type}} } func printKlassPairLHS(x : KlassPair) { // We print the remarks at the 'p' and at the ending ')'. - print(x.lhs) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-3:24 {{of 'x.lhs'}} - // Release for Array needed for print. + print(x.lhs) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-4:24 {{of 'x.lhs'}} // expected-remark @-3:16 {{release of type}} } +// We put the retain on the return here since it is part of the result +// convention. func returnKlassPairLHS(x: KlassPair) -> Klass { - return x.lhs // expected-remark @:14 {{retain of type 'Klass'}} + return x.lhs // expected-remark @:5 {{retain of type 'Klass'}} // expected-note @-2:25 {{of 'x.lhs'}} } @@ -108,24 +107,25 @@ func callingAnInitializerKlassPair(x: Klass, y: Klass) -> KlassPair { func printKlassTuplePair(x : (Klass, Klass)) { // We pattern match columns to ensure we get retain on the p and release on // the end ')' - print(x) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-4:26 {{of 'x'}} - // expected-remark @-2:5 {{retain of type 'Klass'}} - // expected-note @-6:26 {{of 'x'}} - // Release on temp array for print(...). + print(x) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-5:26 {{of 'x'}} + // expected-remark @-3:5 {{retain of type 'Klass'}} + // expected-note @-7:26 {{of 'x'}} // expected-remark @-5:12 {{release of type}} } func printKlassTupleLHS(x : (Klass, Klass)) { // We print the remarks at the 'p' and at the ending ')'. - print(x.0) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-3:25 {{of 'x'}} + print(x.0) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-4:25 {{of 'x'}} // Release on Array for print. - // expected-remark @-3:14 {{release of type}} + // expected-remark @-4:14 {{release of type}} } func returnKlassTupleLHS(x: (Klass, Klass)) -> Klass { - return x.0 // expected-remark @:12 {{retain of type 'Klass'}} + return x.0 // expected-remark @:5 {{retain of type 'Klass'}} // expected-note @-2:26 {{of 'x'}} } @@ -189,19 +189,22 @@ func castAsQuestionDiamondGEP2(x: KlassPair) { // expected-remark @-2:39 {{retain of type 'Klass'}} // expected-note @-4 {{of 'x.rhs'}} case let (.some(x1), .some(x2)): - print(x1, x2) // expected-remark {{retain of type 'Optional'}} + print(x1, x2) // expected-remark @:15 {{heap allocated ref of type}} // expected-remark @-1 {{retain of type 'Optional'}} - // expected-remark @-2 {{release of type}} - // expected-remark @-3 {{release of type 'Optional'}} + // expected-remark @-2 {{retain of type 'Optional'}} + // expected-remark @-3 {{release of type}} // expected-remark @-4 {{release of type 'Optional'}} + // expected-remark @-5 {{release of type 'Optional'}} case let (.some(x1), nil): - print(x1) // expected-remark {{retain of type 'SubKlass'}} - // expected-remark @-1 {{release of type}} - // expected-remark @-2 {{release of type 'Optional'}} + print(x1) // expected-remark @:15 {{heap allocated ref of type}} + // expected-remark @-1 {{retain of type 'SubKlass'}} + // expected-remark @-2 {{release of type}} + // expected-remark @-3 {{release of type 'Optional'}} case let (nil, .some(x2)): - print(x2) // expected-remark {{retain of type 'SubKlass'}} - // expected-remark @-1 {{release of type}} - // expected-remark @-2 {{release of type 'Optional'}} + print(x2) // expected-remark @:15 {{heap allocated ref of type}} + // expected-remark @-1 {{retain of type 'SubKlass'}} + // expected-remark @-2 {{release of type}} + // expected-remark @-3 {{release of type 'Optional'}} case (nil, nil): break } @@ -241,3 +244,45 @@ func inoutKlassQuestionCastArgument2(x: inout Klass?) -> SubKlass? { return x as? SubKlass // expected-remark {{retain of type 'Klass'}} // expected-note @-2 {{of 'x.some'}} } + +// We should have 1x rr remark here on calleeX for storing it into the array to +// print. Release is from the array. We don't pattern match it due to the actual +// underlying Array type name changing under the hood in between platforms. +@inline(__always) +func alwaysInlineCallee(_ calleeX: Klass) { + print(calleeX) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-3:27 {{of 'calleeX'}} + // expected-remark @-3:18 {{release of type}} +} + +// We should have 3x rr remarks here on callerX and none on calleeX. All of the +// releases are for the temporary array that we pass into print. +// +// TODO: Should we print out as notes the whole inlined call stack? +func alwaysInlineCaller(_ callerX: Klass) { + alwaysInlineCallee(callerX) // expected-remark @:5 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-3:27 {{of 'callerX'}} + // expected-remark @-3:31 {{release of type}} + print(callerX) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-7:27 {{of 'callerX'}} + // expected-remark @-3:18 {{release of type}} + alwaysInlineCallee(callerX) // expected-remark @:5 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-11:27 {{of 'callerX'}} + // expected-remark @-3:31 {{release of type}} +} + +func allocateValue() { + // Remark should be on Klass and note should be on k. + let k = Klass() // expected-remark @:13 {{heap allocated ref of type 'Klass'}} + // expected-note @-1:9 {{of 'k'}} + print(k) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-4:9 {{of 'k'}} + // expected-remark @-3:12 {{release of type}} + // expected-remark @-4:12 {{release of type 'Klass'}} + // expected-note @-7:9 {{of 'k'}} +} diff --git a/test/SILOptimizer/prune-vtables.sil b/test/SILOptimizer/prune-vtables.sil index d72af0b338b10..633dc9e53bf5a 100644 --- a/test/SILOptimizer/prune-vtables.sil +++ b/test/SILOptimizer/prune-vtables.sil @@ -14,9 +14,9 @@ sil @PrivateA_yesOverrides : $@convention(method) (@guaranteed PrivateA) -> () sil @PrivateA_isFinal : $@convention(method) (@guaranteed PrivateA) -> () // NOWMO-LABEL: sil_vtable PrivateA { -// NOWMO: #PrivateA.noOverrides{{.*}} [nonoverridden] +// NOWMO: #PrivateA.noOverrides{{[^[]]*}} // NOWMO-NOT: #PrivateA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #PrivateA.isFinal{{.*}} [nonoverridden] +// NOWMO: #PrivateA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable PrivateA { // WMO: #PrivateA.noOverrides{{.*}} [nonoverridden] @@ -35,9 +35,9 @@ private class PrivateB: PrivateA { sil @PrivateB_yesOverrides : $@convention(method) (@guaranteed PrivateB) -> () // NOWMO-LABEL: sil_vtable PrivateB { -// NOWMO: #PrivateA.noOverrides{{.*}} [nonoverridden] +// NOWMO: #PrivateA.noOverrides{{[^[]]*}} // NOWMO-NOT: #PrivateA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #PrivateA.isFinal{{.*}} [nonoverridden] +// NOWMO: #PrivateA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable PrivateB { // WMO: #PrivateA.noOverrides{{.*}} [nonoverridden] @@ -62,7 +62,7 @@ sil @InternalA_isFinal : $@convention(method) (@guaranteed InternalA) -> () // NOWMO-LABEL: sil_vtable InternalA { // NOWMO-NOT: #InternalA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #InternalA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #InternalA.isFinal{{.*}} [nonoverridden] +// NOWMO: #InternalA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable InternalA { // WMO: #InternalA.noOverrides{{.*}} [nonoverridden] @@ -83,7 +83,7 @@ sil @InternalB_yesOverrides : $@convention(method) (@guaranteed InternalB) -> () // NOWMO-LABEL: sil_vtable InternalB { // NOWMO-NOT: #InternalA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #InternalA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #InternalA.isFinal{{.*}} [nonoverridden] +// NOWMO: #InternalA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable InternalB { // WMO: #InternalA.noOverrides{{.*}} [nonoverridden] @@ -108,7 +108,7 @@ sil @PublicA_isFinal : $@convention(method) (@guaranteed PublicA) -> () // NOWMO-LABEL: sil_vtable PublicA { // NOWMO-NOT: #PublicA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #PublicA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #PublicA.isFinal{{.*}} [nonoverridden] +// NOWMO: #PublicA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable PublicA { // WMO: #PublicA.noOverrides{{.*}} [nonoverridden] @@ -129,7 +129,7 @@ sil @PublicB_yesOverrides : $@convention(method) (@guaranteed PublicB) -> () // NOWMO-LABEL: sil_vtable PublicB { // NOWMO-NOT: #PublicA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #PublicA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #PublicA.isFinal{{.*}} [nonoverridden] +// NOWMO: #PublicA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable PublicB { // WMO: #PublicA.noOverrides{{.*}} [nonoverridden] @@ -154,7 +154,7 @@ sil @OpenA_isFinal : $@convention(method) (@guaranteed OpenA) -> () // NOWMO-LABEL: sil_vtable OpenA { // NOWMO-NOT: #OpenA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #OpenA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #OpenA.isFinal{{.*}} [nonoverridden] +// NOWMO: #OpenA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable OpenA { // WMO-NOT: #OpenA.noOverrides{{.*}} [nonoverridden] @@ -175,7 +175,7 @@ sil @OpenB_yesOverrides : $@convention(method) (@guaranteed OpenB) -> () // NOWMO-LABEL: sil_vtable OpenB { // NOWMO-NOT: #OpenA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #OpenA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #OpenA.isFinal{{.*}} [nonoverridden] +// NOWMO: #OpenA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable OpenB { // WMO-NOT: #OpenA.noOverrides{{.*}} [nonoverridden] diff --git a/test/SILOptimizer/semantic-arc-opts.sil b/test/SILOptimizer/semantic-arc-opts.sil index aac4e3eb35ddf..1b79ff3e34775 100644 --- a/test/SILOptimizer/semantic-arc-opts.sil +++ b/test/SILOptimizer/semantic-arc-opts.sil @@ -20,19 +20,29 @@ sil @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> sil @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> () sil @get_owned_obj : $@convention(thin) () -> @owned Builtin.NativeObject sil @unreachable_guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever +sil @inout_user : $@convention(thin) (@inout FakeOptional) -> () struct NativeObjectPair { var obj1 : Builtin.NativeObject var obj2 : Builtin.NativeObject } +struct FakeOptionalNativeObjectPairPair { + var pair1 : FakeOptional + var pair2 : FakeOptional +} +sil @inout_user2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () + sil @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair protocol MyFakeAnyObject : Klass { func myFakeMethod() } -final class Klass {} +final class Klass { + var base: Klass +} + extension Klass : MyFakeAnyObject { func myFakeMethod() } @@ -1512,6 +1522,31 @@ bb3: return %9999 : $() } +// CHECK-LABEL: sil [ossa] @switch_enum_test_loadcopy_with_leaked_enum_case : $@convention(thin) (@owned FakeOptional) -> () { +// CHECK-NOT: load [copy] +// CHECK: load_borrow +// CHECK-NOT: load [copy] +// CHECK: } // end sil function 'switch_enum_test_loadcopy_with_leaked_enum_case' +sil [ossa] @switch_enum_test_loadcopy_with_leaked_enum_case : $@convention(thin) (@owned FakeOptional) -> () { +bb0(%0 : @owned $FakeOptional): + %0a = alloc_stack $FakeOptional + store %0 to [init] %0a : $*FakeOptional + %1 = load [copy] %0a : $*FakeOptional + switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 + +bb1(%2 : @owned $Builtin.NativeObject): + unreachable + +bb2: + br bb3 + +bb3: + destroy_addr %0a : $*FakeOptional + dealloc_stack %0a : $*FakeOptional + %9999 = tuple() + return %9999 : $() +} + // CHECK-LABEL: sil [ossa] @switch_enum_test_copyvalue_no_default : $@convention(thin) (@guaranteed FakeOptional) -> () { // CHECK-NOT: copy_value // CHECK: } // end sil function 'switch_enum_test_copyvalue_no_default' @@ -2568,3 +2603,127 @@ bb0(%0 : @guaranteed $Builtin.NativeObject, %1 : @guaranteed $Builtin.NativeObje %9999 = tuple() return %9999 : $() } + +// Make sure that we properly handle this case with out parameters and don't +// crash due to the SILArgument in bb3. +// +// CHECK-LABEL: sil [ossa] @iterated_transforming_terminator : $@convention(method) (@guaranteed Builtin.NativeObject) -> @out FakeOptional { +// CHECK-NOT: copy_value +// CHECK-NOT: @owned +// CHECK: } // end sil function 'iterated_transforming_terminator' +sil [ossa] @iterated_transforming_terminator : $@convention(method) (@guaranteed Builtin.NativeObject) -> @out FakeOptional { +bb0(%0 : $*FakeOptional, %1 : @guaranteed $Builtin.NativeObject): + %3 = init_enum_data_addr %0 : $*FakeOptional, #FakeOptional.some!enumelt + %4 = copy_value %1 : $Builtin.NativeObject + checked_cast_br %4 : $Builtin.NativeObject to Klass, bb1, bb2 + +bb1(%7 : @owned $Klass): + %8 = enum $FakeOptional, #FakeOptional.some!enumelt, %7 : $Klass + br bb3(%8 : $FakeOptional) + +bb2(%10 : @owned $Builtin.NativeObject): + destroy_value %10 : $Builtin.NativeObject + %12 = enum $FakeOptional, #FakeOptional.none!enumelt + br bb3(%12 : $FakeOptional) + +bb3(%14 : @owned $FakeOptional): + switch_enum %14 : $FakeOptional, case #FakeOptional.some!enumelt: bb4, case #FakeOptional.none!enumelt: bb6 + +bb4(%16 : @owned $Klass): + %17 = begin_borrow %16 : $Klass + %18 = ref_element_addr %17 : $Klass, #Klass.base + copy_addr %18 to [initialization] %3 : $*Klass + end_borrow %17 : $Klass + destroy_value %16 : $Klass + inject_enum_addr %0 : $*FakeOptional, #FakeOptional.some!enumelt + br bb5 + +bb5: + %24 = tuple () + return %24 : $() + +bb6: + inject_enum_addr %0 : $*FakeOptional, #FakeOptional.none!enumelt + br bb5 +} + +// CHECK-LABEL: sil [ossa] @destructure_with_differing_lifetimes_inout_1 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'destructure_with_differing_lifetimes_inout_1' +sil [ossa] @destructure_with_differing_lifetimes_inout_1 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { +bb0(%0 : $*FakeOptionalNativeObjectPairPair): + %0a = struct_element_addr %0 : $*FakeOptionalNativeObjectPairPair, #FakeOptionalNativeObjectPairPair.pair1 + %1 = load [copy] %0a : $*FakeOptional + switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, default bb2 + +bb2(%2 : @owned $FakeOptional): + destroy_value %2 : $FakeOptional + br bbEnd + +bb1(%3 : @owned $NativeObjectPair): + (%3a, %3b) = destructure_struct %3 : $NativeObjectPair + cond_br undef, bb1a, bb1b + +bb1a: + destroy_value %3a : $Builtin.NativeObject + destroy_value %3b : $Builtin.NativeObject + br bbEnd + +bb1b: + destroy_value %3a : $Builtin.NativeObject + %f = function_ref @inout_user2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () + apply %f(%0) : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () + destroy_value %3b : $Builtin.NativeObject + br bbEnd + +bbEnd: + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @destructure_with_differing_lifetimes_inout_2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'destructure_with_differing_lifetimes_inout_2' +sil [ossa] @destructure_with_differing_lifetimes_inout_2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { +bb0(%0 : $*FakeOptionalNativeObjectPairPair): + %0a = struct_element_addr %0 : $*FakeOptionalNativeObjectPairPair, #FakeOptionalNativeObjectPairPair.pair1 + %1 = load [copy] %0a : $*FakeOptional + switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, default bb2 + +bb2(%2 : @owned $FakeOptional): + destroy_value %2 : $FakeOptional + br bbEnd + +bb1(%3 : @owned $NativeObjectPair): + (%3a, %3b) = destructure_struct %3 : $NativeObjectPair + cond_br undef, bb1a, bb1b + +bb1a: + destroy_value %3a : $Builtin.NativeObject + br bb1ab + +bb1ab: + destroy_value %3b : $Builtin.NativeObject + br bbEnd + +bb1b: + destroy_value %3a : $Builtin.NativeObject + %f = function_ref @inout_user2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () + apply %f(%0) : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () + cond_br undef, bb1ba, bb1bb + +bb1ba: + br bb1baEnd + +bb1bb: + br bb1baEnd + +bb1baEnd: + destroy_value %3b : $Builtin.NativeObject + br bbEnd + +bbEnd: + %9999 = tuple() + return %9999 : $() +} + diff --git a/test/SILOptimizer/sil_combine.sil b/test/SILOptimizer/sil_combine.sil index 145399c069f35..c3c8c95051839 100644 --- a/test/SILOptimizer/sil_combine.sil +++ b/test/SILOptimizer/sil_combine.sil @@ -3508,6 +3508,33 @@ bb0(%0 : $VV): return %26 : $() } +sil @any_to_object : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned AnyObject + +// CHECK-LABEL: sil @dont_crash_when_propagating_existentials +// CHECK: [[EM:%[0-9]+]] = init_existential_metatype %0 +// CHECK: [[S:%[0-9]+]] = alloc_stack $Any +// CHECK: [[M:%[0-9]+]] = open_existential_metatype [[EM]] +// CHECK: [[E:%[0-9]+]] = init_existential_addr [[S]] +// CHECK: store [[M]] to [[E]] +// CHECK: apply {{%[0-9]+}}<(@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134") AnyObject).Type>([[E]]) +// CHECK: } // end sil function 'dont_crash_when_propagating_existentials' +sil @dont_crash_when_propagating_existentials : $@convention(thin) () -> @owned AnyObject { +bb0: + %0 = metatype $@thick C.Type + %1 = init_existential_metatype %0 : $@thick C.Type, $@thick AnyObject.Type + %3 = alloc_stack $Any, let, name "object" + %4 = open_existential_metatype %1 : $@thick AnyObject.Type to $@thick (@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134") AnyObject).Type + %5 = init_existential_addr %3 : $*Any, $(@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134") AnyObject).Type + store %4 to %5 : $*@thick (@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134") AnyObject).Type + %7 = open_existential_addr immutable_access %3 : $*Any to $*@opened("5F9F1B04-EC40-11EA-9534-8C8590A6A134") Any + %8 = function_ref @any_to_object : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned AnyObject + %9 = apply %8<@opened("5F9F1B04-EC40-11EA-9534-8C8590A6A134") Any>(%7) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned AnyObject + destroy_addr %3 : $*Any + dealloc_stack %3 : $*Any + return %9 : $AnyObject +} + + // CHECK-LABEL: sil @remove_unused_alloc_ref // CHECK-NEXT: bb0 // CHECK-NEXT: %0 = tuple () diff --git a/test/SILOptimizer/simplify_cfg.sil b/test/SILOptimizer/simplify_cfg.sil index 6adb3f9859dbc..d19fb986fa0aa 100644 --- a/test/SILOptimizer/simplify_cfg.sil +++ b/test/SILOptimizer/simplify_cfg.sil @@ -2980,6 +2980,70 @@ bb3: br bb2(%z : $Builtin.Int1) } +// CHECK-LABEL: sil @trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed Int, @guaranteed Int) -> @owned Int +// CHECK: [[SRC:%.*]] = alloc_stack $Int +// CHECK: store %0 to [[SRC]] +// CHECK: [[DST:%.*]] = alloc_stack $Int +// CHECK: [[LD1:%.*]] = load [[SRC]] +// CHECK: store [[LD1]] to [[DST]] +// CHECK: [[LD2:%.*]] = load [[DST]] +// CHECK: return [[LD2]] +// CHECK: } // end sil function 'trivial_checked_cast_addr_br' +sil @trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed Int, @guaranteed Int) -> @owned Int { +bb0(%0 : $Int, %1 : $Int): + %6 = alloc_stack $Int + store %0 to %6 : $*Int + %8 = alloc_stack $Int + checked_cast_addr_br copy_on_success Int in %6 : $*Int to Int in %8 : $*Int, bb1, bb2 + +bb1: + %10 = load %8 : $*Int + dealloc_stack %8 : $*Int + br bb3(%10 : $Int) + +bb2: + retain_value %1: $Int + dealloc_stack %8 : $*Int + br bb3(%1 : $Int) + +bb3(%11 : $Int): + dealloc_stack %6 : $*Int + return %11 : $Int +} + +// CHECK-LABEL: sil @non_trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed String, @guaranteed String) -> @owned String +// CHECK: [[SRC:%.*]] = alloc_stack $String +// CHECK: store %0 to [[SRC]] +// CHECK: [[DST:%.*]] = alloc_stack $String +// CHECK: [[TEMP:%.*]] = alloc_stack $String +// CHECK: copy_addr [[SRC]] to [initialization] [[TEMP]] +// CHECK: [[LD1:%.*]] = load [[TEMP]] +// CHECK: store [[LD1]] to [[DST]] +// CHECK: [[LD2:%.*]] = load [[DST]] +// CHECK: return [[LD2]] +// CHECK: } // end sil function 'non_trivial_checked_cast_addr_br' +sil @non_trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed String, @guaranteed String) -> @owned String { +bb0(%0 : $String, %1 : $String): + %6 = alloc_stack $String + store %0 to %6 : $*String + %8 = alloc_stack $String + checked_cast_addr_br copy_on_success String in %6 : $*String to String in %8 : $*String, bb1, bb2 + +bb1: + %10 = load %8 : $*String + dealloc_stack %8 : $*String + br bb3(%10 : $String) + +bb2: + retain_value %1: $String + dealloc_stack %8 : $*String + br bb3(%1 : $String) + +bb3(%11 : $String): + dealloc_stack %6 : $*String + return %11 : $String +} + // CHECK-LABEL: sil @dont_hang // CHECK: bb6: // CHECK: integer_literal $Builtin.Int64, 1 diff --git a/test/SILOptimizer/static_initializer.sil b/test/SILOptimizer/static_initializer.sil index bcdb29794c702..dbc5e28526a4f 100644 --- a/test/SILOptimizer/static_initializer.sil +++ b/test/SILOptimizer/static_initializer.sil @@ -25,8 +25,8 @@ sil_global private @globalinit_token0 : $Builtin.Word // CHECK-NEXT: } sil_global @_Tv2ch1xSi : $Outer -// CHECK-LABEL: sil private @globalinit_func0 : $@convention(c) () -> () { -sil private @globalinit_func0 : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] @globalinit_func0 : $@convention(c) () -> () { +sil private [global_init_once_fn] @globalinit_func0 : $@convention(c) () -> () { bb0: %0 = global_addr @_Tv2ch1xSi : $*Outer %1 = integer_literal $Builtin.Int32, 2 diff --git a/test/SPI/Inputs/ioi_helper.swift b/test/SPI/Inputs/ioi_helper.swift new file mode 100644 index 0000000000000..f885a21d07f60 --- /dev/null +++ b/test/SPI/Inputs/ioi_helper.swift @@ -0,0 +1 @@ +public struct IOIPublicStruct {} diff --git a/test/SPI/experimental_spi_imports_swiftinterface.swift b/test/SPI/experimental_spi_imports_swiftinterface.swift index 76a50f21796da..35d715424d387 100644 --- a/test/SPI/experimental_spi_imports_swiftinterface.swift +++ b/test/SPI/experimental_spi_imports_swiftinterface.swift @@ -4,7 +4,7 @@ /// Generate 3 empty modules. // RUN: touch %t/empty.swift -// RUN: %target-swift-frontend -emit-module %t/empty.swift -module-name ExperimentalImported -emit-module-path %t/ExperimentalImported.swiftmodule -swift-version 5 -enable-library-evolution +// RUN: %target-swift-frontend -emit-module %S/Inputs/ioi_helper.swift -module-name ExperimentalImported -emit-module-path %t/ExperimentalImported.swiftmodule -swift-version 5 -enable-library-evolution // RUN: %target-swift-frontend -emit-module %t/empty.swift -module-name IOIImported -emit-module-path %t/IOIImported.swiftmodule -swift-version 5 -enable-library-evolution // RUN: %target-swift-frontend -emit-module %t/empty.swift -module-name SPIImported -emit-module-path %t/SPIImported.swiftmodule -swift-version 5 -enable-library-evolution @@ -24,3 +24,10 @@ @_spi(dummy) import SPIImported // CHECK-PUBLIC: {{^}}import SPIImported // CHECK-PRIVATE: @_spi{{.*}} import SPIImported + +@_spi(X) +extension IOIPublicStruct { + public func foo() {} +} +// CHECK-PUBLIC-NOT: IOIPublicStruct +// CHECK-PRIVATE: @_spi{{.*}} extension IOIPublicStruct diff --git a/test/SPI/private_swiftinterface.swift b/test/SPI/private_swiftinterface.swift index 6af2d40bc51f2..9473a265af173 100644 --- a/test/SPI/private_swiftinterface.swift +++ b/test/SPI/private_swiftinterface.swift @@ -3,6 +3,7 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module %S/Inputs/spi_helper.swift -module-name SPIHelper -emit-module-path %t/SPIHelper.swiftmodule -swift-version 5 -enable-library-evolution -emit-module-interface-path %t/SPIHelper.swiftinterface -emit-private-module-interface-path %t/SPIHelper.private.swiftinterface +// RUN: %target-swift-frontend -emit-module %S/Inputs/ioi_helper.swift -module-name IOIHelper -emit-module-path %t/IOIHelper.swiftmodule -swift-version 5 -enable-library-evolution -emit-module-interface-path %t/IOIHelper.swiftinterface -emit-private-module-interface-path %t/IOIHelper.private.swiftinterface /// Make sure that the public swiftinterface of spi_helper doesn't leak SPI. // RUN: %FileCheck -check-prefix=CHECK-HELPER %s < %t/SPIHelper.swiftinterface @@ -25,6 +26,7 @@ // CHECK-PUBLIC: import SPIHelper // CHECK-PRIVATE: @_spi(OtherSPI) @_spi(HelperSPI) import SPIHelper +@_implementationOnly import IOIHelper public func foo() {} // CHECK-PUBLIC: foo() // CHECK-PRIVATE: foo() @@ -155,6 +157,11 @@ extension PublicType: SPIProto2 where T: SPIProto2 {} // CHECK-PRIVATE: extension PublicType : {{.*}}.SPIProto2 where T : {{.*}}.SPIProto2 // CHECK-PUBLIC-NOT: _ConstraintThatIsNotPartOfTheAPIOfThisLibrary +public protocol LocalPublicProto {} +extension IOIPublicStruct : LocalPublicProto {} +// CHECK-PRIVATE-NOT: IOIPublicStruct +// CHECK-PUBLIC-NOT: IOIPublicStruct + // The dummy conformance should be only in the private swiftinterface for // SPI extensions. @_spi(LocalSPI) diff --git a/test/SPI/protocol_requirement.swift b/test/SPI/protocol_requirement.swift index 756915e1556ee..c3b952e1c8221 100644 --- a/test/SPI/protocol_requirement.swift +++ b/test/SPI/protocol_requirement.swift @@ -96,3 +96,20 @@ public protocol SPIProtocol { @_spi(Private) static var staticProperty: Int { get } } + +public protocol OtherProto {} +public protocol Proto { + associatedtype A : Sequence where A.Element : OtherProto +} + +public struct BadStruct {} +@_spi(Horse) extension BadStruct : OtherProto {} +public struct BadConforms : Proto { // expected-error {{cannot use conformance of 'BadStruct' to 'OtherProto' in associated type 'Self.A.Element' (inferred as 'BadStruct'); the conformance is declared as SPI}} + public typealias A = [BadStruct] +} + +public struct OKStruct {} +@_spi(Horse) extension OKStruct : OtherProto {} +@_spi(Horse) public struct OKConforms : Proto { + public typealias A = [OKStruct] +} diff --git a/test/Sanitizers/symbolication-linux.swift b/test/Sanitizers/symbolication-linux.swift new file mode 100644 index 0000000000000..a892bc88d2cd9 --- /dev/null +++ b/test/Sanitizers/symbolication-linux.swift @@ -0,0 +1,37 @@ +// RUN: %target-build-swift %s -sanitize=address -g -target %sanitizers-target-triple -o %t +// RUN: env %env-ASAN_OPTIONS=abort_on_error=0 not %target-run %t 2>&1 | %swift-demangle | %FileCheck %s -check-prefix=OOP +// In-process symbolication doesn't work on Linux (yet) +// XXX: env %env-ASAN_OPTIONS=abort_on_error=0,external_symbolizer_path= not %target-run %t 2>&1 | %swift-demangle | %FileCheck %s -check-prefix=IP +// REQUIRES: executable_test +// REQUIRES: asan_runtime +// REQUIRES: OS=linux-gnu + +// Check that Sanitizer reports are properly symbolicated on Linux, both +// out-of-process (via `llvm-symbolizer`) and when falling back to in-process +// symbolication. Note that `llvm-symbolizer` does not demangle Swift symbol +// names, so we use `swift demangle`. + +@inline(never) +func foo() { + let x = UnsafeMutablePointer.allocate(capacity: 1) + x.deallocate() + print(x.pointee) +} + +@inline(never) +func bar() { + foo() + print("Prevent tail call optimization") +} + +bar() + +// Out-of-process +// OOP: #0 0x{{[0-9a-f]+}} in main.foo() -> () {{.*}}symbolication-linux.swift:[[@LINE-12]] +// OOP-NEXT: #1 0x{{[0-9a-f]+}} in main.bar() -> () {{.*}}symbolication-linux.swift:[[@LINE-8]] +// OOP-NEXT: #2 0x{{[0-9a-f]+}} in main {{.*}}symbolication-linux.swift:[[@LINE-5]] + +// In-process +// IP: #0 0x{{[0-9a-f]+}} in main.foo() -> ()+0x +// IP-NEXT: #1 0x{{[0-9a-f]+}} in main.bar() -> ()+0x +// IP-NEXT: #2 0x{{[0-9a-f]+}} in main+0x diff --git a/test/Sanitizers/symbolication.swift b/test/Sanitizers/symbolication.swift new file mode 100644 index 0000000000000..2fc6ea7cb94ba --- /dev/null +++ b/test/Sanitizers/symbolication.swift @@ -0,0 +1,37 @@ +// RUN: %target-build-swift %s -sanitize=address -g -target %sanitizers-target-triple -o %t +// RUN: env %env-ASAN_OPTIONS=abort_on_error=0 not %target-run %t 2>&1 | %FileCheck %s -check-prefix=OOP +// RUN: env %env-ASAN_OPTIONS=abort_on_error=0,external_symbolizer_path= not %target-run %t 2>&1 | %FileCheck %s -check-prefix=IP +// REQUIRES: executable_test +// REQUIRES: asan_runtime +// REQUIRES: VENDOR=apple + +// REQUIRES: rdar68353068 + +// Check that Sanitizer reports are properly symbolicated on Apple platforms, +// both out-of-process (via `atos`) and when falling back to in-process +// symbolication. Note that `atos` also demangles Swift symbol names. + +@inline(never) +func foo() { + let x = UnsafeMutablePointer.allocate(capacity: 1) + x.deallocate() + print(x.pointee) +} + +@inline(never) +func bar() { + foo() + print("Prevent tail call optimization") +} + +bar() + +// Out-of-process +// OOP: #0 0x{{[0-9a-f]+}} in foo() symbolication.swift:[[@LINE-12]] +// OOP-NEXT: #1 0x{{[0-9a-f]+}} in bar() symbolication.swift:[[@LINE-8]] +// OOP-NEXT: #2 0x{{[0-9a-f]+}} in main symbolication.swift:[[@LINE-5]] + +// In-process +// IP: #0 0x{{[0-9a-f]+}} in main.foo() -> ()+0x +// IP-NEXT: #1 0x{{[0-9a-f]+}} in main.bar() -> ()+0x +// IP-NEXT: #2 0x{{[0-9a-f]+}} in main+0x diff --git a/test/ScanDependencies/Inputs/CHeaders/G.h b/test/ScanDependencies/Inputs/CHeaders/G.h index ef09c49a98e0f..4da23ffcbb4f6 100644 --- a/test/ScanDependencies/Inputs/CHeaders/G.h +++ b/test/ScanDependencies/Inputs/CHeaders/G.h @@ -1 +1,6 @@ +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 110000 +#include "X.h" +#endif + void funcG(void); + diff --git a/test/ScanDependencies/Inputs/CHeaders/H.h b/test/ScanDependencies/Inputs/CHeaders/H.h new file mode 100644 index 0000000000000..9c4b66d8f0e84 --- /dev/null +++ b/test/ScanDependencies/Inputs/CHeaders/H.h @@ -0,0 +1,5 @@ +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 110000 +#include "I.h" +#endif + +void funcH(void); diff --git a/test/ScanDependencies/Inputs/CHeaders/I.h b/test/ScanDependencies/Inputs/CHeaders/I.h new file mode 100644 index 0000000000000..d9ddc05cc65b4 --- /dev/null +++ b/test/ScanDependencies/Inputs/CHeaders/I.h @@ -0,0 +1 @@ +void funcI(void); diff --git a/test/ScanDependencies/Inputs/CHeaders/X.h b/test/ScanDependencies/Inputs/CHeaders/X.h new file mode 100644 index 0000000000000..11c123884ef12 --- /dev/null +++ b/test/ScanDependencies/Inputs/CHeaders/X.h @@ -0,0 +1 @@ +void funcX(void); diff --git a/test/ScanDependencies/Inputs/CHeaders/module.modulemap b/test/ScanDependencies/Inputs/CHeaders/module.modulemap index dbd29ce9d9739..95fc7fef133c2 100644 --- a/test/ScanDependencies/Inputs/CHeaders/module.modulemap +++ b/test/ScanDependencies/Inputs/CHeaders/module.modulemap @@ -27,3 +27,18 @@ module G { header "G.h" export * } + +module H { + header "H.h" + export * +} + +module I { + header "I.h" + export * +} + +module X { + header "X.h" + export * +} diff --git a/test/ScanDependencies/Inputs/ModuleDependencyGraph.swift b/test/ScanDependencies/Inputs/ModuleDependencyGraph.swift index 464afba79f014..4c84230cd4efb 100644 --- a/test/ScanDependencies/Inputs/ModuleDependencyGraph.swift +++ b/test/ScanDependencies/Inputs/ModuleDependencyGraph.swift @@ -90,6 +90,9 @@ struct SwiftModuleDetails: Codable { /// arguments to the generic PCM build arguments reported from the dependency /// graph. var extraPcmArgs: [String]? + + /// A flag to indicate whether or not this module is a framework. + var isFramework: Bool } /// Details specific to Swift external modules. diff --git a/test/ScanDependencies/batch_module_scan.swift b/test/ScanDependencies/batch_module_scan.swift new file mode 100644 index 0000000000000..59189771b340f --- /dev/null +++ b/test/ScanDependencies/batch_module_scan.swift @@ -0,0 +1,40 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/inputs) +// RUN: %empty-directory(%t/outputs) +// RUN: mkdir -p %t/clang-module-cache + +// RUN: echo "[{" > %/t/inputs/input.json +// RUN: echo "\"swiftModuleName\": \"F\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-target x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/F.swiftmodule.json\"" >> %/t/inputs/input.json +// RUN: echo "}," >> %/t/inputs/input.json +// RUN: echo "{" >> %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"F\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-target x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/F.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}]" >> %/t/inputs/input.json + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -batch-scan-input-file %/t/inputs/input.json + +// Check the contents of the JSON output +// RUN: %FileCheck %s -check-prefix=CHECK-PCM < %t/outputs/F.pcm.json +// RUN: %FileCheck %s -check-prefix=CHECK-SWIFT < %t/outputs/F.swiftmodule.json + +// CHECK-PCM: { +// CHECK-PCM-NEXT: "mainModuleName": "F", +// CHECK-PCM-NEXT: "modules": [ +// CHECK-PCM-NEXT: { +// CHECK-PCM-NEXT: "clang": "F" +// CHECK-PCM-NEXT: }, +// CHECK-PCM-NEXT: { +// CHECK-PCM-NEXT: "modulePath": "F.pcm", +// CHECK-PCM: "-I + +// CHECK-SWIFT: { +// CHECK-SWIFT-NEXT: "mainModuleName": "F", +// CHECK-SWIFT-NEXT: "modules": [ +// CHECK-SWIFT-NEXT: { +// CHECK-SWIFT-NEXT: "swift": "F" +// CHECK-SWIFT-NEXT: }, +// CHECK-SWIFT-NEXT: { +// CHECK-SWIFT-NEXT: "modulePath": "F.swiftmodule", diff --git a/test/ScanDependencies/batch_module_scan_arguments.swift b/test/ScanDependencies/batch_module_scan_arguments.swift new file mode 100644 index 0000000000000..65f2320766ec7 --- /dev/null +++ b/test/ScanDependencies/batch_module_scan_arguments.swift @@ -0,0 +1,24 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/inputs) +// RUN: %empty-directory(%t/outputs) +// RUN: mkdir -p %t/clang-module-cache + +// RUN: echo "[{" > %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"H\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-target x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/H.10.9.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}," >> %/t/inputs/input.json +// RUN: echo "{" >> %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"H\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-target x86_64-apple-macosx11.0\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/H.11.0.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}]" >> %/t/inputs/input.json + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -batch-scan-input-file %/t/inputs/input.json + +// Check the contents of the JSON output +// RUN: %FileCheck %s -check-prefix=CHECK-TEN < %t/outputs/H.10.9.pcm.json +// RUN: %FileCheck %s -check-prefix=CHECK-ELEVEN < %t/outputs/H.11.0.pcm.json + +// CHECK-TEN: "clang": "I" +// CHECK-ELEVEN-NOT: "clang": "I" diff --git a/test/ScanDependencies/batch_module_scan_versioned.swift b/test/ScanDependencies/batch_module_scan_versioned.swift new file mode 100644 index 0000000000000..02725a2ff0160 --- /dev/null +++ b/test/ScanDependencies/batch_module_scan_versioned.swift @@ -0,0 +1,49 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/inputs) +// RUN: %empty-directory(%t/outputs) +// RUN: mkdir -p %t/clang-module-cache + +// RUN: echo "[{" > %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"G\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-Xcc -target -Xcc x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/G_109.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}," >> %/t/inputs/input.json +// RUN: echo "{" >> %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"G\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-Xcc -target -Xcc x86_64-apple-macosx11.0\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/G_110.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}]" >> %/t/inputs/input.json + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -batch-scan-input-file %/t/inputs/input.json + +// Check the contents of the JSON output +// RUN: %FileCheck %s -check-prefix=CHECK-PCM109 < %t/outputs/G_109.pcm.json +// RUN: %FileCheck %s -check-prefix=CHECK-PCM110 < %t/outputs/G_110.pcm.json + +// CHECK-PCM109: { +// CHECK-PCM109-NEXT: "mainModuleName": "G", +// CHECK-PCM109-NEXT: "modules": [ +// CHECK-PCM109-NEXT: { +// CHECK-PCM109-NEXT: "clang": "G" +// CHECK-PCM109-NEXT: }, +// CHECK-PCM109-NEXT: { +// CHECK-PCM109-NEXT: "modulePath": "G.pcm", +// CHECK-PCM109: "directDependencies": [ +// CHECK-PCM109-NEXT: { +// CHECK-PCM109-NEXT: "clang": "X" +// CHECK-PCM109-NEXT: } +// CHECK-PCM109-NEXT: ], +// CHECK-PCM109: "-I + +// CHECK-PCM110: { +// CHECK-PCM110-NEXT: "mainModuleName": "G", +// CHECK-PCM110-NEXT: "modules": [ +// CHECK-PCM110-NEXT: { +// CHECK-PCM110-NEXT: "clang": "G" +// CHECK-PCM110-NEXT: }, +// CHECK-PCM110-NEXT: { +// CHECK-PCM110-NEXT: "modulePath": "G.pcm", +// CHECK-PCM110: "directDependencies": [ +// CHECK-PCM110-NEXT: ], +// CHECK-PCM110-NOT: "clang": "X" +// CHECK-PCM110: "-I diff --git a/test/ScanDependencies/can_import_placeholder.swift b/test/ScanDependencies/can_import_placeholder.swift new file mode 100644 index 0000000000000..777f283fdf0ac --- /dev/null +++ b/test/ScanDependencies/can_import_placeholder.swift @@ -0,0 +1,45 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: mkdir -p %t/inputs + +// RUN: echo "[{" > %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"SomeExternalModule\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/t/inputs/SomeExternalModule.swiftmodule\"," >> %/t/inputs/map.json +// RUN: echo "\"docPath\": \"%/t/inputs/SomeExternalModule.swiftdoc\"," >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/SomeExternalModule.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}]" >> %/t/inputs/map.json + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 + +// Check the contents of the JSON output +// RUN: %FileCheck %s < %t/deps.json + +// REQUIRES: executable_test +// REQUIRES: objc_interop +#if canImport(SomeExternalModule) +import SomeExternalModule +#endif + +// CHECK: "mainModuleName": "deps" + +/// --------Main module +// CHECK-LABEL: "modulePath": "deps.swiftmodule", +// CHECK-NEXT: sourceFiles +// CHECK-NEXT: can_import_placeholder.swift + +// CHECK: directDependencies +// CHECK-NEXT: { +// CHECK-NEXT: "swiftPlaceholder": "SomeExternalModule" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "Swift" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "SwiftOnoneSupport" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "F" +// CHECK-NEXT: } +// CHECK-NEXT: ], + diff --git a/test/ScanDependencies/can_import_with_map.swift b/test/ScanDependencies/can_import_with_map.swift index e21bf826fe038..3becb8115eb1f 100644 --- a/test/ScanDependencies/can_import_with_map.swift +++ b/test/ScanDependencies/can_import_with_map.swift @@ -8,15 +8,18 @@ // RUN: echo "\"moduleName\": \"Foo\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%/t/inputs/Foo.swiftmodule\"," >> %/t/inputs/map.json // RUN: echo "\"docPath\": \"%/t/inputs/Foo.swiftdoc\"," >> %/t/inputs/map.json -// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"" >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/stdlib_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/ononesupport_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json // RUN: %target-swift-frontend -typecheck %s -explicit-swift-module-map-file %t/inputs/map.json -disable-implicit-swift-modules diff --git a/test/ScanDependencies/diagnose_dependency_cycle.swift b/test/ScanDependencies/diagnose_dependency_cycle.swift index 1157d364a7954..609fd331646eb 100644 --- a/test/ScanDependencies/diagnose_dependency_cycle.swift +++ b/test/ScanDependencies/diagnose_dependency_cycle.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: not %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules &> %t/out.txt +// RUN: not %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 &> %t/out.txt // RUN: %FileCheck %s < %t/out.txt diff --git a/test/ScanDependencies/explicit-framework-irgen.swift b/test/ScanDependencies/explicit-framework-irgen.swift new file mode 100644 index 0000000000000..0ad514de35a2b --- /dev/null +++ b/test/ScanDependencies/explicit-framework-irgen.swift @@ -0,0 +1,37 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: mkdir -p %t/inputs +// RUN: echo "/// Some cool comments" > %t/foo.swift +// RUN: echo "public func foo() {}" >> %t/foo.swift +// RUN: %target-swift-frontend -emit-module -emit-module-path %t/inputs/Foo.swiftmodule -emit-module-doc-path %t/inputs/Foo.swiftdoc -emit-module-source-info -emit-module-source-info-path %t/inputs/Foo.swiftsourceinfo -module-cache-path %t.module-cache %t/foo.swift -module-name Foo + +// RUN: echo "[{" > %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"Foo\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/t/inputs/Foo.swiftmodule\"," >> %/t/inputs/map.json +// RUN: echo "\"docPath\": \"%/t/inputs/Foo.swiftdoc\"," >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": true" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}]" >> %/t/inputs/map.json + +// RUN: %target-swift-frontend -emit-object -emit-module -disable-implicit-swift-modules -explicit-swift-module-map-file %t/inputs/map.json -o %t/explicit-framework-irgen.o %s +import Foo + +// This test is to verify autolinking behavior so it is macOS-specific. +// REQUIRES: OS=macosx + +// RUN: otool -l %t/explicit-framework-irgen.o | %FileCheck %s +// CHECK: cmd LC_LINKER_OPTION +// CHECK-NEXT: cmdsize +// CHECK-NEXT: count +// CHECK-NEXT: string #1 -framework +// CHECK-NEXT: string #2 Foo diff --git a/test/ScanDependencies/explicit-module-map-forwarding-module.swift b/test/ScanDependencies/explicit-module-map-forwarding-module.swift index 5d3c3cfa82c60..c8b694cea201c 100644 --- a/test/ScanDependencies/explicit-module-map-forwarding-module.swift +++ b/test/ScanDependencies/explicit-module-map-forwarding-module.swift @@ -18,15 +18,18 @@ // RUN: echo "\"moduleName\": \"Foo\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%/t/inputs/Foo-from-interface.swiftmodule\"," >> %/t/inputs/map.json // RUN: echo "\"docPath\": \"%/t/inputs/Foo.swiftdoc\"," >> %/t/inputs/map.json -// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"" >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/stdlib_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/ononesupport_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json // RUN: %target-swift-ide-test -print-module-comments -module-to-print=Foo -enable-swiftsourceinfo -source-filename %s -explicit-swift-module-map-file %t/inputs/map.json | %FileCheck %s diff --git a/test/ScanDependencies/explicit-module-map.swift b/test/ScanDependencies/explicit-module-map.swift index 821a6cfdc847f..77bfe5dd248f6 100644 --- a/test/ScanDependencies/explicit-module-map.swift +++ b/test/ScanDependencies/explicit-module-map.swift @@ -9,15 +9,18 @@ // RUN: echo "\"moduleName\": \"Foo\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%/t/inputs/Foo.swiftmodule\"," >> %/t/inputs/map.json // RUN: echo "\"docPath\": \"%/t/inputs/Foo.swiftdoc\"," >> %/t/inputs/map.json -// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"" >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/stdlib_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/ononesupport_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json // RUN: %target-swift-ide-test -print-module-comments -module-to-print=Foo -enable-swiftsourceinfo -source-filename %s -explicit-swift-module-map-file %t/inputs/map.json | %FileCheck %s diff --git a/test/ScanDependencies/module_deps.swift b/test/ScanDependencies/module_deps.swift index 7e3a62507ed99..dc48ba5e0998d 100644 --- a/test/ScanDependencies/module_deps.swift +++ b/test/ScanDependencies/module_deps.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json @@ -105,7 +105,6 @@ import SubE // CHECK-NEXT: "-only-use-extra-clang-opts" // CHECK-NEXT: "-Xcc" // CHECK-NEXT: "clang" -// CHECK: "-fno-implicit-modules" /// --------Swift module E // CHECK: "swift": "E" @@ -195,9 +194,7 @@ import SubE /// --------Clang module SwiftShims // CHECK-LABEL: "modulePath": "SwiftShims.pcm", -// CHECK-NO-SEARCH-PATHS-NOT: "-I" // CHECK-NO-SEARCH-PATHS-NOT: "-sdk" -// CHECK-NO-SEARCH-PATHS-NOT: "-F" // CHECK-NO-SEARCH-PATHS-NOT: "-prebuilt-module-cache-path" // Check make-style dependencies diff --git a/test/ScanDependencies/module_deps_clang_only.swift b/test/ScanDependencies/module_deps_clang_only.swift new file mode 100644 index 0000000000000..34ac0c6eeefd1 --- /dev/null +++ b/test/ScanDependencies/module_deps_clang_only.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: %target-swift-frontend -scan-clang-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -module-name C + +// Check the contents of the JSON output +// RUN: %FileCheck %s < %t/deps.json + +// CHECK: "mainModuleName": "C", +// CHECK-NEXT: "modules": [ +// CHECK-NEXT: { +// CHECK-NEXT: "clang": "C" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "modulePath": "C.pcm", +// CHECK-NEXT: "sourceFiles": [ + + +// CHECK: "directDependencies": [ +// CHECK-NEXT: { +// CHECK-NEXT: "clang": "B" +// CHECK-NEXT: } diff --git a/test/ScanDependencies/module_deps_cross_import_overlay.swift b/test/ScanDependencies/module_deps_cross_import_overlay.swift index 7b1bfd9b63363..94031c4ce38bc 100644 --- a/test/ScanDependencies/module_deps_cross_import_overlay.swift +++ b/test/ScanDependencies/module_deps_cross_import_overlay.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ScanDependencies/module_deps_external.swift b/test/ScanDependencies/module_deps_external.swift index 601b60d62b4e7..4242028b6d114 100644 --- a/test/ScanDependencies/module_deps_external.swift +++ b/test/ScanDependencies/module_deps_external.swift @@ -6,26 +6,11 @@ // RUN: echo "\"moduleName\": \"SomeExternalModule\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%/t/inputs/SomeExternalModule.swiftmodule\"," >> %/t/inputs/map.json // RUN: echo "\"docPath\": \"%/t/inputs/SomeExternalModule.swiftdoc\"," >> %/t/inputs/map.json -// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/SomeExternalModule.swiftsourceinfo\"" >> %/t/inputs/map.json -// RUN: echo "}," >> %/t/inputs/map.json -// RUN: echo "{" >> %/t/inputs/map.json -// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/stdlib_module\"" >> %/t/inputs/map.json -// RUN: echo "}," >> %/t/inputs/map.json -// RUN: echo "{" >> %/t/inputs/map.json -// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/ononesupport_module\"" >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/SomeExternalModule.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json - -// RUN: echo "[{" > %/t/inputs/map.json -// RUN: echo "\"moduleName\": \"SomeExternalModule\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/t/inputs/SomeExternalModule.swiftmodule\"," >> %/t/inputs/map.json -// RUN: echo "\"docPath\": \"%/t/inputs/SomeExternalModule.swiftdoc\"," >> %/t/inputs/map.json -// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/SomeExternalModule.swiftsourceinfo\"" >> %/t/inputs/map.json -// RUN: echo "}]" >> %/t/inputs/map.json - -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ScanDependencies/module_deps_private_interface.swift b/test/ScanDependencies/module_deps_private_interface.swift new file mode 100644 index 0000000000000..2098775216ea8 --- /dev/null +++ b/test/ScanDependencies/module_deps_private_interface.swift @@ -0,0 +1,16 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: echo "// swift-interface-format-version: 1.0" > %t/Foo.swiftinterface +// RUN: echo "// swift-module-flags: -module-name Foo" >> %t/Foo.swiftinterface +// RUN: echo "public func foo() {}" >> %t/Foo.swiftinterface + +// RUN: cp %t/Foo.swiftinterface %t/Foo.private.swiftinterface + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %t + +// Check the contents of the JSON output +// RUN: %FileCheck %s < %t/deps.json + +import Foo + +// CHECK: "moduleInterfacePath": "{{.*}}Foo.private.swiftinterface", diff --git a/test/ScanDependencies/module_framework.swift b/test/ScanDependencies/module_framework.swift new file mode 100644 index 0000000000000..9756277074277 --- /dev/null +++ b/test/ScanDependencies/module_framework.swift @@ -0,0 +1,23 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -Xcc -Xclang + +// Check the contents of the JSON output +// RUN: %FileCheck %s < %t/deps.json +// REQUIRES: OS=macosx + +import CryptoKit + +// CHECK: "mainModuleName": "deps" +// CHECK: directDependencies +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "CryptoKit" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "Swift" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "SwiftOnoneSupport" +// CHECK-NEXT: } +// CHECK-NEXT: ], + +// CHECK: "isFramework": true diff --git a/test/ScanDependencies/module_not_found.swift b/test/ScanDependencies/module_not_found.swift index 1674f380b3732..8fd238eba6736 100644 --- a/test/ScanDependencies/module_not_found.swift +++ b/test/ScanDependencies/module_not_found.swift @@ -7,10 +7,12 @@ // RUN: echo "[{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%stdlib_dir/Swift.swiftmodule/%module-target-triple.swiftmodule\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%stdlib_dir/SwiftOnoneSupport.swiftmodule/%module-target-triple.swiftmodule\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json // Add the -I search path to ensure we do not accidentally implicitly load Foo.swiftmodule diff --git a/test/Sema/Inputs/fixits-derived-conformances-multifile.swift b/test/Sema/Inputs/fixits-derived-conformances-multifile.swift new file mode 100644 index 0000000000000..7512251332dbd --- /dev/null +++ b/test/Sema/Inputs/fixits-derived-conformances-multifile.swift @@ -0,0 +1,6 @@ +public enum Enum { case one } // expected-note {{type declared here}} +public enum GenericEnum { case one(Int) } // expected-note {{type declared here}} + +public struct Struct {} // expected-note {{type declared here}} +public struct GenericStruct {} // expected-note {{type declared here}} + diff --git a/test/Sema/editor_placeholders.swift b/test/Sema/editor_placeholders.swift index dedeb59a440db..cf14d23b74fd2 100644 --- a/test/Sema/editor_placeholders.swift +++ b/test/Sema/editor_placeholders.swift @@ -2,6 +2,7 @@ func foo(_ x: Int) -> Int {} func foo(_ x: Float) -> Float {} +func foo(_ t: T) -> T {} var v = foo(<#T##x: Float##Float#>) // expected-error {{editor placeholder}} v = "" // expected-error {{cannot assign value of type 'String' to type 'Float'}} @@ -36,3 +37,6 @@ func test_ambiguity_with_placeholders(pairs: [(rank: Int, count: Int)]) -> Bool // expected-error@-1 {{editor placeholder in source file}} // expected-error@-2 {{ambiguous use of 'subscript(_:)'}} } + +let unboundInPlaceholder1: Array = <#T##Array#> // expected-error{{editor placeholder in source file}} +let unboundInPlaceholder2: Array = foo(<#T##t: Array##Array#>) // expected-error{{editor placeholder in source file}} diff --git a/test/Sema/enum_conformance_synthesis.swift b/test/Sema/enum_conformance_synthesis.swift index 494d1b3480b32..c486385669cda 100644 --- a/test/Sema/enum_conformance_synthesis.swift +++ b/test/Sema/enum_conformance_synthesis.swift @@ -224,7 +224,7 @@ enum Complex2 { } extension Complex2 : Hashable {} extension Complex2 : CaseIterable {} // expected-error {{type 'Complex2' does not conform to protocol 'CaseIterable'}} -extension FromOtherFile: CaseIterable {} // expected-error {{cannot be automatically synthesized in an extension in a different file to the type}} +extension FromOtherFile: CaseIterable {} // expected-error {{extension outside of file declaring enum 'FromOtherFile' prevents automatic synthesis of 'allCases' for protocol 'CaseIterable'}} extension CaseIterableAcrossFiles: CaseIterable { public static var allCases: [CaseIterableAcrossFiles] { return [ .A ] @@ -248,7 +248,7 @@ extension OtherFileNonconforming: Hashable { func hash(into hasher: inout Hasher) {} } // ...but synthesis in a type defined in another file doesn't work yet. -extension YetOtherFileNonconforming: Equatable {} // expected-error {{cannot be automatically synthesized in an extension in a different file to the type}} +extension YetOtherFileNonconforming: Equatable {} // expected-error {{extension outside of file declaring enum 'YetOtherFileNonconforming' prevents automatic synthesis of '==' for protocol 'Equatable'}} extension YetOtherFileNonconforming: CaseIterable {} // expected-error {{does not conform}} // Verify that an indirect enum doesn't emit any errors as long as its "leaves" @@ -319,7 +319,7 @@ extension UnusedGenericDeriveExtension: Hashable {} // Cross-file synthesis is disallowed for conditional cases just as it is for // non-conditional ones. extension GenericOtherFileNonconforming: Equatable where T: Equatable {} -// expected-error@-1{{implementation of 'Equatable' cannot be automatically synthesized in an extension in a different file to the type}} +// expected-error@-1{{extension outside of file declaring generic enum 'GenericOtherFileNonconforming' prevents automatic synthesis of '==' for protocol 'Equatable'}} // rdar://problem/41852654 diff --git a/test/Sema/fixits-derived-conformances.swift b/test/Sema/fixits-derived-conformances.swift new file mode 100644 index 0000000000000..7d63103ed135c --- /dev/null +++ b/test/Sema/fixits-derived-conformances.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -emit-module -emit-library -module-name Types %S/Inputs/fixits-derived-conformances-multifile.swift -o %t/%target-library-name(Types) +// RUN: %swift -typecheck -target %target-triple -I %t -diagnostics-editor-mode -verify %s + +import Types + +extension GenericEnum: Equatable { } +// expected-error@-1 {{extension outside of file declaring generic enum 'GenericEnum' prevents automatic synthesis of '==' for protocol 'Equatable'}} +// expected-note@-2 {{do you want to add protocol stubs?}}{{35-35=\n public static func == (lhs: GenericEnum, rhs: GenericEnum) -> Bool {\n <#code#>\n \}\n}} + +extension Struct: Equatable { } +// expected-error@-1 {{extension outside of file declaring struct 'Struct' prevents automatic synthesis of '==' for protocol 'Equatable'}} +// expected-note@-2 {{do you want to add protocol stubs?}}{{30-30=\n public static func == (lhs: Struct, rhs: Struct) -> Bool {\n <#code#>\n \}\n}} +extension GenericStruct: Equatable { } +// expected-error@-1 {{extension outside of file declaring generic struct 'GenericStruct' prevents automatic synthesis of '==' for protocol 'Equatable'}} +// expected-note@-2 {{do you want to add protocol stubs?}}{{37-37=\n public static func == (lhs: GenericStruct, rhs: GenericStruct) -> Bool {\n <#code#>\n \}\n}} + +extension Enum: CaseIterable { } +// expected-error@-1 {{extension outside of file declaring enum 'Enum' prevents automatic synthesis of 'allCases' for protocol 'CaseIterable'}} +// expected-note@-2 {{do you want to add protocol stubs?}}{{31-31=\n public static var allCases: [Enum]\n}} + diff --git a/test/Sema/immutability.swift b/test/Sema/immutability.swift index beae8a87fa53e..d43c5c299b806 100644 --- a/test/Sema/immutability.swift +++ b/test/Sema/immutability.swift @@ -61,13 +61,13 @@ class FooClass { mutating init(a : Bool) {} // expected-error {{'mutating' may only be used on 'func' declarations}} {{3-12=}} - mutating // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} {{3-12=}} + mutating // expected-error {{'mutating' is not valid on instance methods in classes}} {{3-12=}} func baz() {} - nonmutating // expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} {{3-15=}} + nonmutating // expected-error {{'nonmutating' is not valid on instance methods in classes}} {{3-15=}} func bay() {} - mutating nonmutating // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} + mutating nonmutating // expected-error {{'mutating' is not valid on instance methods in classes}} expected-error {{'nonmutating' is not valid on instance methods in classes}} func bax() {} var x : Int { @@ -86,6 +86,15 @@ class FooClass { } } + var computed: Int { + mutating get { 0 } // expected-error {{'mutating' is not valid on getters in classes}} {{5-14=}} + nonmutating set {} // expected-error {{'nonmutating' is not valid on setters in classes}} {{5-17=}} + } + + var storedWithObservers: Int = 0 { + mutating willSet {} // expected-error {{'mutating' is not valid on willSet observers in classes}} {{5-14=}} + nonmutating didSet {} // expected-error {{'nonmutating' is not valid on didSet observers in classes}} {{5-17=}} + } } @@ -241,7 +250,7 @@ func test_arguments(_ a : Int, protocol ClassBoundProtocolMutating : class { - mutating // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} {{3-12=}} + mutating // expected-error {{'mutating' is not valid on instance methods in class-bound protocols}} {{3-12=}} func f() } diff --git a/test/Sema/spi-in-decls.swift b/test/Sema/spi-in-decls.swift new file mode 100644 index 0000000000000..e83c88a7cc660 --- /dev/null +++ b/test/Sema/spi-in-decls.swift @@ -0,0 +1,307 @@ +/// SPI variant of implementation-only-import-in-decls with the "Bad" +/// declarations defined as local SPI. + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/NormalLibrary.swiftmodule %S/Inputs/implementation-only-import-in-decls-public-helper.swift + +// RUN: %target-typecheck-verify-swift -I %t + +import NormalLibrary + +@_spi(X) +extension NormalStruct: NormalProto { + public typealias Assoc = Int +} +@_spi(X) +extension GenericStruct: NormalProto { + public typealias Assoc = Int +} +@_spi(X) +extension NormalClass: NormalProto { + public typealias Assoc = Int +} + +@_spi(X) +public struct BadStruct {} // expected-note 27 {{type declared here}} +@_spi(X) +public protocol BadProto {} // expected-note 20 {{type declared here}} +@_spi(X) +open class BadClass {} // expected-note 2 {{type declared here}} + +@_spi(X) +public struct IntLike: ExpressibleByIntegerLiteral, Equatable { // expected-note {{type declared here}} + public init(integerLiteral: Int) {} +} + +@_spi(X) +@propertyWrapper +public struct BadWrapper { // expected-note {{type declared here}} + public var wrappedValue: Int + public init(wrappedValue: Int) { + self.wrappedValue = wrappedValue + } +} + +// FIXME SPI precedencegroups are not yet accepted. +//@_spi(X) +//precedencegroup BadPrecedence {} + +public struct TestConformance: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +@usableFromInline struct TestConformanceUFI: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +struct TestConformanceOkay: BadProto {} // ok + +public class TestConformanceClass: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +public enum TestConformanceEnum: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + + +public struct TestGenericParams {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +public struct TestGenericParamsWhereClause where T: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +public enum TestCase { + case x(BadStruct) // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + case y(Int, BadStruct) // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +} + +public func testGenericParams(_: T) {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +public func testGenericParamsWhereClause(_: T) where T: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +public func testParams(_: BadStruct, _: BadProto) {} +// expected-error@-1 {{cannot use struct 'BadStruct' here; it is SPI}} +// expected-error@-2 {{cannot use protocol 'BadProto' here; it is SPI}} +public func testResult() -> BadStruct? { return nil } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + +public struct TestSubscript { + public subscript(_: T) -> Int { return 0 } // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + public subscript(where _: T) -> Int where T: BadProto { return 0 } // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + public subscript(_: BadStruct) -> Int { return 0 } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + public subscript(_: Int) -> BadStruct? { return nil } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +} + +public struct TestInit { + public init(_: BadStruct) {} // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + public init(_: T) {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + public init(where _: T) where T: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +} + +public struct TestPropertyWrapper { + @BadWrapper public var BadProperty: Int // expected-error {{cannot use struct 'BadWrapper' as property wrapper here; it is SPI}} +} + +public protocol TestInherited: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +public protocol TestConstraintBase { + associatedtype Assoc +} +public protocol TestConstraint: TestConstraintBase where Assoc: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +public protocol TestConstraintEq: TestConstraintBase where Assoc == BadStruct {} // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + +public protocol TestAssocType { + associatedtype Assoc: BadProto // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +} + +public protocol TestAssocTypeWhereClause { + associatedtype Assoc: Collection where Assoc.Element: BadProto // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +} + +public enum TestRawType: IntLike { // expected-error {{cannot use struct 'IntLike' here; it is SPI}} + case x = 1 + // FIXME: expected-error@-1 {{cannot use conformance of 'IntLike' to 'Equatable' here; the conformance is declared as SPI}} +} + +public class TestSubclass: BadClass { // expected-error {{cannot use class 'BadClass' here; it is SPI}} +} + +public typealias TestUnderlying = BadStruct // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public typealias TestGenericParamsAliasWhereClause = T where T: BadProto // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +public typealias TestGenericParamsAlias = T // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +public var testBadType: BadStruct? = nil // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var testBadTypeInferred = Optional.none // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var testBadTypePartiallyInferred: Optional = Optional.none // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var (testBadTypeTuple1, testBadTypeTuple2): (BadStruct?, BadClass?) = (nil, nil) +// expected-error@-1 {{cannot use struct 'BadStruct' here; it is SPI}} +// expected-error@-2 {{cannot use class 'BadClass' here; it is SPI}} +public var (testBadTypeTuplePartlyInferred1, testBadTypeTuplePartlyInferred2): (Optional, Optional) = (Optional.none, Optional.none) // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var (testBadTypeTuplePartlyInferred3, testBadTypeTuplePartlyInferred4): (Optional, Optional) = (Optional.none, Optional.none) // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var testMultipleBindings1: Int? = nil, testMultipleBindings2: BadStruct? = nil // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var testMultipleBindings3: BadStruct? = nil, testMultipleBindings4: Int? = nil // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + +extension BadStruct { + public func testExtensionOfBadType() {} + public var testExtensionVarBad: Int { 0 } + public subscript(bad _: Int) -> Int { 0 } + + func testExtensionOfOkayType() {} + var testExtensionVarOkay: Int { 0 } + subscript(okay _: Int) -> Int { 0 } +} + +extension Array where Element == BadStruct { // expected-error {{cannot use struct 'BadStruct' in an extension with public or '@usableFromInline' members; it is SPI}} + public func testExtensionWithBadRequirement() {} + public var testExtensionVarBad: Int { 0 } + public subscript(bad _: Int) -> Int { 0 } +} + +extension Array where Element == BadStruct { + func testExtensionWithOkayRequirement() {} // okay + var testExtensionVarOkay: Int { 0 } // okay + subscript(okay _: Int) -> Int { 0 } // okay +} + +extension Int: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +struct TestExtensionConformanceOkay {} +extension TestExtensionConformanceOkay: BadProto {} // okay + +public protocol TestConstrainedExtensionProto {} +extension Array: TestConstrainedExtensionProto where Element == BadStruct { // expected-error {{cannot use struct 'BadStruct' in an extension with conditional conformances; it is SPI}} +} + + +// FIXME Support SPI precedencegroup? +//infix operator !!!!!!: BadPrecedence +// +//precedencegroup TestLowerThan { +// lowerThan: BadPrecedence +//} +//precedencegroup TestHigherThan { +// higherThan: BadPrecedence +//} + +public struct PublicStructStoredProperties { + public var publiclyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + internal var internallyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private var privatelyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private let letIsLikeVar = [BadStruct]() // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + + private var computedIsOkay: BadStruct? { return nil } // okay + private static var staticIsOkay: BadStruct? // okay + @usableFromInline internal var computedUFIIsNot: BadStruct? { return nil } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +} + +@usableFromInline internal struct UFIStructStoredProperties { + @usableFromInline var publiclyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + internal var internallyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private var privatelyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private let letIsLikeVar = [BadStruct]() // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + + private var computedIsOkay: BadStruct? { return nil } // okay + private static var staticIsOkay: BadStruct? // okay + @usableFromInline internal var computedUFIIsNot: BadStruct? { return nil } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +} + +public class PublicClassStoredProperties { + public var publiclyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + internal var internallyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private var privatelyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private let letIsLikeVar = [BadStruct]() // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + + private var computedIsOkay: BadStruct? { return nil } // okay + private static var staticIsOkay: BadStruct? // okay + @usableFromInline internal var computedUFIIsNot: BadStruct? { return nil } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +} + +public typealias NormalProtoAssoc = T.Assoc +public func testConformanceInTypealias(_: NormalProtoAssoc) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +public struct NormalProtoAssocHolder { + public var value: T.Assoc +} +public func testConformanceInBoundGeneric(_: NormalProtoAssocHolder) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +public class SubclassOfNormalClass: NormalClass {} + +public func testInheritedConformance(_: NormalProtoAssocHolder) {} // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' here; the conformance is declared as SPI}} +public func testSpecializedConformance(_: NormalProtoAssocHolder>) {} // expected-error {{cannot use conformance of 'GenericStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +extension Array where Element == NormalProtoAssocHolder { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in an extension with public or '@usableFromInline' members; the conformance is declared as SPI}} + public func testConstrainedExtensionUsingBadConformance() {} +} + +public struct ConditionalGenericStruct {} +extension ConditionalGenericStruct: NormalProto where T: NormalProto { + public typealias Assoc = Int +} +public func testConditionalGeneric(_: NormalProtoAssocHolder>) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +public protocol PublicAssociatedTypeProto { + associatedtype Assoc: NormalProto + func takesAssoc(_: Assoc) +} +@usableFromInline protocol UFIAssociatedTypeProto { + associatedtype Assoc: NormalProto + func takesAssoc(_: Assoc) +} +protocol InternalAssociatedTypeProto { + associatedtype Assoc: NormalProto + func takesAssoc(_: Assoc) +} + +public struct PublicInferredAssociatedTypeImpl { + public func takesAssoc(_: NormalStruct) {} +} +extension PublicInferredAssociatedTypeImpl: PublicAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension PublicInferredAssociatedTypeImpl: UFIAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension PublicInferredAssociatedTypeImpl: InternalAssociatedTypeProto {} // okay + +@usableFromInline struct UFIInferredAssociatedTypeImpl { + public func takesAssoc(_: NormalStruct) {} +} +extension UFIInferredAssociatedTypeImpl: PublicAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension UFIInferredAssociatedTypeImpl: UFIAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension UFIInferredAssociatedTypeImpl: InternalAssociatedTypeProto {} // okay + +struct InternalInferredAssociatedTypeImpl { + public func takesAssoc(_: NormalStruct) {} +} +extension InternalInferredAssociatedTypeImpl: PublicAssociatedTypeProto {} // okay +extension InternalInferredAssociatedTypeImpl: UFIAssociatedTypeProto {} // okay +extension InternalInferredAssociatedTypeImpl: InternalAssociatedTypeProto {} // okay + +public struct PublicExplicitAssociatedTypeImpl { + public typealias Assoc = NormalStruct + public func takesAssoc(_: NormalStruct) {} +} +extension PublicExplicitAssociatedTypeImpl: PublicAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension PublicExplicitAssociatedTypeImpl: UFIAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension PublicExplicitAssociatedTypeImpl: InternalAssociatedTypeProto {} // okay + + +public protocol BaseProtoWithNoRequirement { + associatedtype Assoc + func takesAssoc(_: Assoc) +} +public protocol RefinedProto: BaseProtoWithNoRequirement where Assoc: NormalProto { +} + +public struct RefinedProtoImpl: RefinedProto { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} + public func takesAssoc(_: NormalStruct) {} +} + +public protocol RefinedSelfProto where Self: NormalProto {} +extension NormalStruct: RefinedSelfProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +public protocol RefinedSelfProtoInheritance: NormalProto {} +extension NormalStruct: RefinedSelfProtoInheritance {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + + +public protocol SlightlyMoreComplicatedRequirement { + associatedtype Assoc: Collection where Assoc.Element: NormalProto + func takesAssoc(_: Assoc) +} +public struct SlightlyMoreComplicatedRequirementImpl: SlightlyMoreComplicatedRequirement { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc.Element' (inferred as 'NormalStruct'); the conformance is declared as SPI}} + public func takesAssoc(_: [NormalStruct]) {} +} +public struct RequirementsHandleSubclassesToo: SlightlyMoreComplicatedRequirement { // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' in associated type 'Self.Assoc.Element' (inferred as 'SubclassOfNormalClass'); the conformance is declared as SPI}} + public func takesAssoc(_: [SubclassOfNormalClass]) {} +} + +public struct RequirementsHandleSpecializationsToo: SlightlyMoreComplicatedRequirement { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc.Element' (inferred as 'ConditionalGenericStruct'); the conformance is declared as SPI}} + public func takesAssoc(_: [ConditionalGenericStruct]) {} +} + +public struct ClassConstrainedGenericArg: PublicAssociatedTypeProto { // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'T'); the conformance is declared as SPI}} + public func takesAssoc(_: T) {} +} diff --git a/test/Sema/spi-inlinable-conformances.swift b/test/Sema/spi-inlinable-conformances.swift new file mode 100644 index 0000000000000..cd7a861272095 --- /dev/null +++ b/test/Sema/spi-inlinable-conformances.swift @@ -0,0 +1,294 @@ +/// SPI variant of implementation-only-inlinable-conformances with the "Bad" +/// declarations defined as local SPI. Also check that SPI conformances +/// can be used within inlinable SPI decls. + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/NormalLibrary.swiftmodule %S/Inputs/implementation-only-import-in-decls-public-helper.swift + +// RUN: %target-typecheck-verify-swift -I %t + +import NormalLibrary + +@_spi(X) +extension NormalStruct: NormalProto { + public typealias Assoc = Int +} +@_spi(X) +extension GenericStruct: NormalProto { + public typealias Assoc = Int +} +@_spi(X) +extension NormalClass: NormalProto { + public typealias Assoc = Int +} + +@_spi(X) +public struct BadStruct {} +@_spi(X) +public protocol BadProto {} +@_spi(X) +open class BadClass {} + +@_spi(X) +public struct IntLike: ExpressibleByIntegerLiteral, Equatable { + public init(integerLiteral: Int) {} +} + +@available(*, unavailable) +public typealias X = Int + +public typealias NormalProtoAssoc = T.Assoc +@inlinable func testConformanceInTypealias() { + let x: NormalProtoAssoc? = nil // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = x + _ = NormalProtoAssoc() // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestConformanceInTypealias() { + let x: NormalProtoAssoc? = nil + _ = x + _ = NormalProtoAssoc() +} + +func internalConformanceInTypealias() { + let x: NormalProtoAssoc? = nil // okay + _ = x + _ = NormalProtoAssoc() // okay +} + +public struct NormalProtoAssocHolder { + public var value: T.Assoc? + public init() {} + public init(_ value: T?) {} +} +@inlinable func testConformanceInBoundGeneric() { + let x: NormalProtoAssocHolder? = nil // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = x + // FIXME: We get this error twice: once for the TypeExpr and once for the implicit init. + _ = NormalProtoAssocHolder() // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = NormalProtoAssocHolder(nil as NormalStruct?) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestConformanceInBoundGeneric() { + let x: NormalProtoAssocHolder? = nil + _ = x + _ = NormalProtoAssocHolder() + _ = NormalProtoAssocHolder(nil as NormalStruct?) +} + +func internalConformanceInBoundGeneric() { + let x: NormalProtoAssocHolder? = nil // okay + _ = x + _ = NormalProtoAssocHolder() // okay + _ = NormalProtoAssocHolder(nil as NormalStruct?) // okay +} + +@inlinable func testDowncast(_ x: Any) -> Bool { + let normal = x is NormalProtoAssocHolder // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + let alias = x is NormalProtoAssoc // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + return normal || alias +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestDowncast(_ x: Any) -> Bool { + let normal = x is NormalProtoAssocHolder + let alias = x is NormalProtoAssoc + return normal || alias +} + +func internalDowncast(_ x: Any) -> Bool { + let normal = x is NormalProtoAssocHolder // okay + let alias = x is NormalProtoAssoc // okay + return normal || alias +} + +@inlinable func testSwitch(_ x: Any) { + switch x { + case let holder as NormalProtoAssocHolder: // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = holder + break + case is NormalProtoAssoc: // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + break + default: + break + } +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestSwitch(_ x: Any) { + switch x { + case let holder as NormalProtoAssocHolder: + _ = holder + break + case is NormalProtoAssoc: + break + default: + break + } +} + +func internalSwitch(_ x: Any) { + switch x { + case let holder as NormalProtoAssocHolder: // okay + _ = holder + break + case is NormalProtoAssoc: // okay + break + default: + break + } +} + +public enum NormalProtoEnumUser { + case a +} + +@inlinable func testEnum() { + // FIXME: We get this error twice: once for the pattern and once for the implicit TypeExpr. + let x: NormalProtoEnumUser = .a // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = x + // FIXME: We get this error twice: once for the TypeExpr and once for the case. + _ = NormalProtoEnumUser.a // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestEnum() { + let x: NormalProtoEnumUser = .a + _ = x + _ = NormalProtoEnumUser.a +} + +func internalEnum() { + let x: NormalProtoEnumUser = .a // okay + _ = x + _ = NormalProtoEnumUser.a // okay +} + +@usableFromInline func testFuncImpl(_: T.Type) {} + +@inlinable func testFunc() { + testFuncImpl(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestFunc() { + testFuncImpl(NormalStruct.self) +} + +func internalFunc() { + testFuncImpl(NormalStruct.self) // okay +} + +public struct ForTestingMembers { + public init() {} + public init(_: T.Type) {} + + public subscript(_: T.Type) -> Int { + get { return 0 } + set {} + } + + public func method(_: T.Type) {} +} + +@inlinable func testMembers() { + _ = ForTestingMembers(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = ForTestingMembers.init(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + + _ = ForTestingMembers()[NormalStruct.self] // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + var instance = ForTestingMembers() + instance[NormalStruct.self] = 1 // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + + ForTestingMembers().method(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestMembers() { + _ = ForTestingMembers(NormalStruct.self) + _ = ForTestingMembers.init(NormalStruct.self) + + _ = ForTestingMembers()[NormalStruct.self] + var instance = ForTestingMembers() + instance[NormalStruct.self] = 1 + + ForTestingMembers().method(NormalStruct.self) +} + +extension NormalProtoAssocHolder { + public static func testAnotherConformance(_: U.Type) {} +} + +@inlinable func testMultipleConformances() { + NormalProtoAssocHolder.testAnotherConformance(NormalClass.self) + // expected-error@-1 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + // expected-error@-2 {{cannot use conformance of 'NormalClass' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestMultipleConformances() { + NormalProtoAssocHolder.testAnotherConformance(NormalClass.self) +} + +@inlinable func localTypeAlias() { + typealias LocalUser = NormalProtoAssocHolder // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + typealias LocalGenericUser = (T, NormalProtoAssocHolder) // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + + typealias LocalProtoAssoc = T.Assoc + _ = LocalProtoAssoc() // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPIlocalTypeAlias() { + // FIXME these should be accepted. + typealias LocalUser = NormalProtoAssocHolder // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + typealias LocalGenericUser = (T, NormalProtoAssocHolder) // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + + typealias LocalProtoAssoc = T.Assoc + _ = LocalProtoAssoc() +} + +@inlinable func localFunctions() { + func local(_: NormalProtoAssocHolder) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + func localReturn() -> NormalProtoAssocHolder { fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + let _ = { (_: NormalProtoAssocHolder) in return } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + let _ = { () -> NormalProtoAssocHolder in fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPIlocalFunctions() { + // FIXME these should be accepted. + func local(_: NormalProtoAssocHolder) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + func localReturn() -> NormalProtoAssocHolder { fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + let _ = { (_: NormalProtoAssocHolder) in return } + let _ = { () -> NormalProtoAssocHolder in fatalError() } +} + +@inlinable public func signatureOfInlinable(_: NormalProtoAssocHolder) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +public func testDefaultArgument(_: Int = NormalProtoAssoc()) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +@_spi(AcceptInSPI) +@inlinable public func SPIsignatureOfInlinable(_: NormalProtoAssocHolder) {} + +@_spi(AcceptInSPI) +public func SPItestDefaultArgument(_: Int = NormalProtoAssoc()) {} + +public class SubclassOfNormalClass: NormalClass {} + +@inlinable public func testInheritedConformance() { + _ = NormalProtoAssocHolder.self // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' here; the conformance is declared as SPI}} +} +@inlinable public func testSpecializedConformance() { + _ = NormalProtoAssocHolder>.self // expected-error {{cannot use conformance of 'GenericStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestInheritedConformance() { + _ = NormalProtoAssocHolder.self +} +@_spi(AcceptInSPI) +@inlinable public func SPItestSpecializedConformance() { + _ = NormalProtoAssocHolder>.self +} diff --git a/test/Sema/struct_equatable_hashable.swift b/test/Sema/struct_equatable_hashable.swift index be162f1abd1a2..1f9e2a2d3d42a 100644 --- a/test/Sema/struct_equatable_hashable.swift +++ b/test/Sema/struct_equatable_hashable.swift @@ -114,8 +114,10 @@ struct StructWithoutExplicitConformance { } func structWithoutExplicitConformance() { + // FIXME(rdar://problem/64844584) - on iOS simulator this diagnostic is flaky // This diagnostic is about `Equatable` because it's considered the best possible solution among other ones for operator `==`. - if StructWithoutExplicitConformance(a: 1, b: "b") == StructWithoutExplicitConformance(a: 2, b: "a") { } // expected-error{{referencing operator function '==' on 'Equatable' requires that 'StructWithoutExplicitConformance' conform to 'Equatable'}} + if StructWithoutExplicitConformance(a: 1, b: "b") == StructWithoutExplicitConformance(a: 2, b: "a") { } + // expected-error@-1 {{requires that 'StructWithoutExplicitConformance' conform to 'Equatable'}} } // Structs with non-hashable/equatable stored properties don't derive conformance. @@ -196,7 +198,7 @@ extension OtherFileNonconforming: Hashable { func hash(into hasher: inout Hasher) {} } // ...but synthesis in a type defined in another file doesn't work yet. -extension YetOtherFileNonconforming: Equatable {} // expected-error {{cannot be automatically synthesized in an extension in a different file to the type}} +extension YetOtherFileNonconforming: Equatable {} // expected-error {{extension outside of file declaring struct 'YetOtherFileNonconforming' prevents automatic synthesis of '==' for protocol 'Equatable'}} // Verify that we can add Hashable conformance in an extension by only // implementing hash(into:) @@ -253,7 +255,7 @@ extension UnusedGenericDeriveExtension: Hashable {} // Cross-file synthesis is still disallowed for conditional cases extension GenericOtherFileNonconforming: Equatable where T: Equatable {} -// expected-error@-1{{implementation of 'Equatable' cannot be automatically synthesized in an extension in a different file to the type}} +// expected-error@-1{{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of '==' for protocol 'Equatable'}} // rdar://problem/41852654 diff --git a/test/Serialization/Inputs/objc-xref/module.modulemap b/test/Serialization/Inputs/objc-xref/module.modulemap new file mode 100644 index 0000000000000..7c036997bed3b --- /dev/null +++ b/test/Serialization/Inputs/objc-xref/module.modulemap @@ -0,0 +1,4 @@ +module ObjCXRef { + header "objc_xref.h" + export * +} diff --git a/test/Serialization/Inputs/objc-xref/objc_xref.h b/test/Serialization/Inputs/objc-xref/objc_xref.h new file mode 100644 index 0000000000000..d3b7a87ef6439 --- /dev/null +++ b/test/Serialization/Inputs/objc-xref/objc_xref.h @@ -0,0 +1,2 @@ +@interface MyObject +@end diff --git a/test/Serialization/access-level.swift b/test/Serialization/access-level.swift new file mode 100644 index 0000000000000..5b098fb83f00e --- /dev/null +++ b/test/Serialization/access-level.swift @@ -0,0 +1,19 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s --check-prefix DIRECT-CHECK +// RUN: %target-swift-frontend -emit-sib %s -o %t/access-level.sib +// RUN: %target-swift-frontend -emit-ir %t/access-level.sib | %FileCheck %s --check-prefix FROM-SIB-CHECK + +// Ensure that the method linkage is default external when lowered from .swift directly +// DIRECT-CHECK-NOT: define{{.*}}internal{{.*}}swiftcc{{.*}}void @"$s4main7VisitorC13visitExprImpl33_205B03B83823935B4865F4617387553BLLyyF" + +// Ensure that the method linkage is default external when lowered from .swift -> .sib -> .ll +// FROM-SIB-CHECK-NOT: define{{.*}}internal{{.*}}swiftcc{{.*}}void @"$s4main7VisitorC13visitExprImpl33_205B03B83823935B4865F4617387553BLLyyF" + +open class Visitor { + public func visit() { + visitExprImpl() + } + @_optimize(none) + private func visitExprImpl() { + } +} diff --git a/test/Serialization/cdecl_attr.swift b/test/Serialization/cdecl_attr.swift new file mode 100644 index 0000000000000..aa3975a738b97 --- /dev/null +++ b/test/Serialization/cdecl_attr.swift @@ -0,0 +1,12 @@ +// RUN: %empty-directory(%t) +// Ensure .swift -> .ll +// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s + +// Ensure .swift -> .sib -> .ll +// RUN: %target-swift-frontend -emit-sib %s -o %t/cdecl_attr.sib +// RUN: %target-swift-frontend -emit-ir %t/cdecl_attr.sib | %FileCheck %s + +// CHECK: define hidden {{.*}} @foo + +@_cdecl("foo") +func foo() {} diff --git a/test/Serialization/index-table-order.sil b/test/Serialization/index-table-order.sil new file mode 100644 index 0000000000000..b31e59bba578a --- /dev/null +++ b/test/Serialization/index-table-order.sil @@ -0,0 +1,51 @@ +// RUN: %empty-directory(%t) + +// Ensure that serialized sib can be deserialized correctly assuming +// contents of SIL_INDEX_BLOCK are sorted by their ids +// RUN: %target-swift-frontend -emit-sib %s -module-name test -o %t/test.sib +// RUN: %target-swift-frontend -emit-sil %t/test.sib -module-name test +// CHECK-DAG: sil_vtable +// CHECK-DAG: sil_global +// CHECK-DAG: sil_witness_table +// CHECK-DAG: sil_default_witness_table +// CHECK-DAG: sil_property + +sil_stage canonical + +import Builtin +import Swift + +// For SIL_FUNC_NAMES +sil @id : $@convention(thin) (Float) -> Float { +bb0(%0 : $Float): + return %0 : $Float +} + + +// For SIL_VTABLE_NAMES +class C {} +sil_vtable C {} + +// For SIL_GLOBALVAR_NAMES +sil_global @x : $Int + +// For SIL_WITNESS_TABLE_NAMES +protocol P1 {} +struct S : P1 {} + +sil_witness_table S: P1 module test {} + +// For SIL_DEFAULT_WITNESS_TABLE_NAMES +protocol P2 {} +sil_default_witness_table P2 {} + +// For SIL_PROPERTY_OFFSETS +struct A { + var a: Int +} + +sil_property #A.a () + +// For SIL_DIFFERENTIABILITY_WITNESS_NAMES +sil_differentiability_witness [parameters 0] [results 0] @id : $@convention(thin) (Float) -> Float {} + diff --git a/test/Serialization/load-target-normalization.swift b/test/Serialization/load-target-normalization.swift index 21040c0c2aab8..253698bd5d74e 100644 --- a/test/Serialization/load-target-normalization.swift +++ b/test/Serialization/load-target-normalization.swift @@ -1,6 +1,9 @@ // RUN: %empty-directory(%t/ForeignModule.swiftmodule) // RUN: touch %t/ForeignModule.swiftmodule/garbage-garbage-garbage.swiftmodule +// SR-12363: This test crashes on master-next. +// XFAIL: asserts + // Test format: We try to import ForeignModule with architectures besides // garbage-garbage-garbage and check the target triple listed in the error // message to make sure it was normalized correctly. This works in lieu of a diff --git a/test/Serialization/xref-deinit.swift b/test/Serialization/xref-deinit.swift new file mode 100644 index 0000000000000..98c43b6670a87 --- /dev/null +++ b/test/Serialization/xref-deinit.swift @@ -0,0 +1,9 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-sib %s -o %t/xref-deinit.sib -I%t -I %S/Inputs/objc-xref +// RUN: %target-swift-frontend -emit-sil %t/xref-deinit.sib -I%t -I %S/Inputs/objc-xref + +// REQUIRES: objc_interop + +import ObjCXRef + +public class Object: MyObject {} diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_avoid_check.swift b/test/SourceKit/CodeComplete/complete_checkdeps_avoid_check.swift index 6b86cc98a88e5..96fe52c196f58 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_avoid_check.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_avoid_check.swift @@ -40,7 +40,7 @@ func foo() { // RUN: -shell -- cp -R $INPUT_DIR/ClangFW.framework_mod/* %t/Frameworks/ClangFW.framework/ == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} == \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo '### Checking dependencies' == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_bridged.swift b/test/SourceKit/CodeComplete/complete_checkdeps_bridged.swift index 6b467da21c4a7..2ea30a5138254 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_bridged.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_bridged.swift @@ -29,7 +29,7 @@ func foo() { // RUN: %target-swift-frontend -emit-module -module-name SwiftFW -o %t/Frameworks/SwiftFW.framework/Modules/SwiftFW.swiftmodule/%target-swiftmodule-name $INPUT_DIR/SwiftFW_src/Funcs.swift // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} == \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_clangmodule.swift b/test/SourceKit/CodeComplete/complete_checkdeps_clangmodule.swift index 543d7f3875ff1..ce3900873e445 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_clangmodule.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_clangmodule.swift @@ -29,7 +29,7 @@ func foo() { // RUN: %target-swift-frontend -emit-module -module-name SwiftFW -o %t/Frameworks/SwiftFW.framework/Modules/SwiftFW.swiftmodule/%target-swiftmodule-name $INPUT_DIR/SwiftFW_src/Funcs.swift // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} == \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_otherfile.swift b/test/SourceKit/CodeComplete/complete_checkdeps_otherfile.swift index 61561efc3bdfe..83f2c76eb28af 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_otherfile.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_otherfile.swift @@ -29,7 +29,7 @@ func foo() { // RUN: %target-swift-frontend -emit-module -module-name SwiftFW -o %t/Frameworks/SwiftFW.framework/Modules/SwiftFW.swiftmodule/%target-swiftmodule-name $INPUT_DIR/SwiftFW_src/Funcs.swift // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} == \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_ownfile.swift b/test/SourceKit/CodeComplete/complete_checkdeps_ownfile.swift index 15233fed951b6..13d039936cc79 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_ownfile.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_ownfile.swift @@ -46,7 +46,7 @@ func foo(val: MyStruct) { // RUN: cp %t/State1.swift %t/test.swift // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=5:4 %t/test.swift -- ${COMPILER_ARGS[@]} == \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_swiftmodule.swift b/test/SourceKit/CodeComplete/complete_checkdeps_swiftmodule.swift index 2ed5cfbe3c6ec..6235a5b808a3a 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_swiftmodule.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_swiftmodule.swift @@ -29,7 +29,7 @@ func foo() { // RUN: %target-swift-frontend -emit-module -module-name SwiftFW -o %t/Frameworks/SwiftFW.framework/Modules/SwiftFW.swiftmodule/%target-swiftmodule-name $INPUT_DIR/SwiftFW_src/Funcs.swift // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} == \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift b/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift index 388c09e57af33..af0831df7cb87 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift @@ -4,15 +4,15 @@ func foo(value: MyStruct) { // REQUIRES: shell -// RUN: DEPCHECK_INTERVAL=1 -// RUN: SLEEP_TIME=2 +// RUN: DEPCHECK_INTERVAL=2 +// RUN: SLEEP_TIME=3 // RUN: %empty-directory(%t) // RUN: %empty-directory(%t/VFS) // RUN: cp %S/Inputs/checkdeps/MyProject/LibraryExt.swift %t/VFS/ // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift == \ @@ -23,7 +23,14 @@ func foo(value: MyStruct) { // RUN: -shell -- echo "### Keep" == \ // RUN: -shell -- sleep ${SLEEP_TIME} == \ -// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject_mod/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift \ +// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject_mod/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift == \ + +// RUN: -shell -- echo "### Rollback without sleep" == \ +// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift == \ + +// RUN: -shell -- echo "### After sleep" == \ +// RUN: -shell -- sleep ${SLEEP_TIME} == \ +// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift \ // RUN: | %FileCheck %s @@ -50,3 +57,19 @@ func foo(value: MyStruct) { // CHECK-DAG: key.description: "self" // CHECK: ] // CHECK: key.reusingastcontext: 1 + +// CHECK-LABEL: ### Rollback without sleep +// CHECK: key.results: [ +// CHECK-DAG: key.description: "myStructMethod_mod()" +// CHECK-DAG: key.description: "extensionMethod()" +// CHECK-DAG: key.description: "self" +// CHECK: ] +// CHECK: key.reusingastcontext: 1 + +// CHECK-LABEL: ### After sleep +// CHECK: key.results: [ +// CHECK-DAG: key.description: "myStructMethod()" +// CHECK-DAG: key.description: "extensionMethod()" +// CHECK-DAG: key.description: "self" +// CHECK: ] +// CHECK-NOT: key.reusingastcontext: 1 diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_vfs_open.swift b/test/SourceKit/CodeComplete/complete_checkdeps_vfs_open.swift index 1a8916dc0aceb..ec5bd8edbe5dd 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_vfs_open.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_vfs_open.swift @@ -12,7 +12,7 @@ func foo(value: MyStruct) { // RUN: cp %S/Inputs/checkdeps/MyProject/LibraryExt.swift %t/VFS/ // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete.open -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift == \ diff --git a/test/SourceKit/CodeComplete/complete_sequence.swift b/test/SourceKit/CodeComplete/complete_sequence.swift index d65a1c24b55f2..3ad76768e4253 100644 --- a/test/SourceKit/CodeComplete/complete_sequence.swift +++ b/test/SourceKit/CodeComplete/complete_sequence.swift @@ -19,8 +19,9 @@ func bar(arg: Bar) { // Disabled. // RUN: %sourcekitd-test \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -- %s > %t.response +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=0 ==\ +// RUN: -req=complete -pos=12:11 %s -- %s == \ +// RUN: -req=complete -pos=15:11 %s -- %s > %t.response // RUN: %FileCheck --check-prefix=RESULT_SLOW %s < %t.response // Enabled. diff --git a/test/SourceKit/CodeComplete/complete_sequence_in_ifconfig.swift b/test/SourceKit/CodeComplete/complete_sequence_in_ifconfig.swift new file mode 100644 index 0000000000000..50c4acd8163ec --- /dev/null +++ b/test/SourceKit/CodeComplete/complete_sequence_in_ifconfig.swift @@ -0,0 +1,54 @@ +struct MyStruct { + init() {} + var value: Int = 1 +} + +func foo(arg: MyStruct) { + #if true + _ = arg./*8:11*/ + #else + _ = arg./*10:11*/ + #endif +} + +struct TestStruct { + #if true + func testActive(arg: MyStruct) { + _ = arg./*17:13*/ + } + #else + func testInactive(arg: MyStruct) { + _ = arg./*21:13*/ + } + #endif +} + +// Test that (1) fast completion happens even in inactive #if blocks, and +// (2) #if in toplevel decls invalidate cached ASTContext + +// RUN: %sourcekitd-test \ +// RUN: -req=complete -pos=8:11 %s -- %s -parse-as-library == \ +// RUN: -req=complete -pos=10:11 %s -- %s -parse-as-library == \ +// RUN: -req=complete -pos=17:13 %s -- %s -parse-as-library == \ +// RUN: -req=complete -pos=21:13 %s -- %s -parse-as-library \ +// RUN: | %FileCheck %s --check-prefix=RESULT + +// RESULT-LABEL: key.results: [ +// RESULT-DAG: key.description: "value" +// RESULT: ] +// RESULT-NOT: key.reusingastcontext: 1 + +// RESULT-LABEL: key.results: [ +// RESULT-DAG: key.description: "value" +// RESULT: ] +// RESULT: key.reusingastcontext: 1 + +// RESULT-LABEL: key.results: [ +// RESULT-DAG: key.description: "value" +// RESULT: ] +// RESULT: key.reusingastcontext: 1 + +// RESULT-LABEL: key.results: [ +// RESULT-DAG: key.description: "value" +// RESULT: ] +// RESULT-NOT: key.reusingastcontext: 1 diff --git a/test/SourceKit/CodeComplete/complete_sequence_race.swift b/test/SourceKit/CodeComplete/complete_sequence_race.swift index 191ee53a15080..2876e239ca437 100644 --- a/test/SourceKit/CodeComplete/complete_sequence_race.swift +++ b/test/SourceKit/CodeComplete/complete_sequence_race.swift @@ -19,21 +19,23 @@ func bar(arg: Bar) { // ReuseASTContext disabled. // RUN: %sourcekitd-test \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=17:1 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=17:1 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -async -- %s +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=0 \ +// RUN: -req=complete -pos=12:11 %s -async -- %s == \ +// RUN: -req=complete -pos=15:11 %s -async -- %s == \ +// RUN: -req=complete -pos=12:11 %s -async -- %s == \ +// RUN: -req=complete -pos=15:11 %s -async -- %s == \ +// RUN: -req=complete -pos=17:1 %s -async -- %s == \ +// RUN: -req=complete -pos=12:11 %s -async -- %s == \ +// RUN: -req=complete -pos=15:11 %s -async -- %s == \ +// RUN: -req=complete -pos=12:11 %s -async -- %s == \ +// RUN: -req=complete -pos=15:11 %s -async -- %s == \ +// RUN: -req=complete -pos=17:1 %s -async -- %s == \ +// RUN: -req=complete -pos=12:11 %s -async -- %s == \ +// RUN: -req=complete -pos=15:11 %s -async -- %s // ReuseASTContext enabled. // RUN: %sourcekitd-test \ +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=5 \ // RUN: -req=complete -pos=12:11 %s -async -- %s == \ // RUN: -req=complete -pos=15:11 %s -async -- %s == \ // RUN: -req=complete -pos=12:11 %s -async -- %s == \ diff --git a/test/SourceKit/CodeComplete/complete_without_stdlib.swift b/test/SourceKit/CodeComplete/complete_without_stdlib.swift index 88d792388173a..7ece49f8f6aa4 100644 --- a/test/SourceKit/CodeComplete/complete_without_stdlib.swift +++ b/test/SourceKit/CodeComplete/complete_without_stdlib.swift @@ -10,10 +10,11 @@ class Str { // RUN: %empty-directory(%t/sdk) // RUN: %sourcekitd-test \ +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=0 \ // RUN: -req=complete -pos=4:1 %s -- %s -resource-dir %t/rsrc -sdk %t/sdk | %FileCheck %s // RUN: %sourcekitd-test \ -// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=4:1 %s -- %s -resource-dir %t/rsrc -sdk %t/sdk == \ -// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=4:1 %s -- %s -resource-dir %t/rsrc -sdk %t/sdk | %FileCheck %s +// RUN: -req=complete -pos=4:1 %s -- %s -resource-dir %t/rsrc -sdk %t/sdk == \ +// RUN: -req=complete -pos=4:1 %s -- %s -resource-dir %t/rsrc -sdk %t/sdk | %FileCheck %s // CHECK: key.results: [ // CHECK-NOT: key.description: diff --git a/test/SourceKit/CodeFormat/indent-multiline-string-interp.swift b/test/SourceKit/CodeFormat/indent-multiline-string-interp.swift new file mode 100644 index 0000000000000..e88853322c7cb --- /dev/null +++ b/test/SourceKit/CodeFormat/indent-multiline-string-interp.swift @@ -0,0 +1,57 @@ +let s1 = """ + \( + 45 +) + """ + +let s2 = """ + \( + 45 + ) +""" + +let s3 = """ +\( + 45 +) + """ + +let s4 = """ + foo \( 45 /* +comment content +*/) bar + """ + +// RUN: %sourcekitd-test -req=format -line=2 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=3 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=4 %s >>%t.response + +// RUN: %sourcekitd-test -req=format -line=8 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=9 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=10 %s >>%t.response + +// RUN: %sourcekitd-test -req=format -line=14 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=15 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=16 %s >>%t.response + +// RUN: %sourcekitd-test -req=format -line=20 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=21 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=22 %s >>%t.response + +// RUN: %FileCheck --strict-whitespace %s <%t.response + +// CHECK: key.sourcetext: " \\(" +// CHECK: key.sourcetext: " 45" +// CHECK: key.sourcetext: " )" + +// CHECK: key.sourcetext: " \\(" +// CHECK: key.sourcetext: " 45" +// CHECK: key.sourcetext: " )" + +// CHECK: key.sourcetext: " \\(" +// CHECK: key.sourcetext: " 45" +// CHECK: key.sourcetext: ")" + +// CHECK: key.sourcetext: " foo \\( 45 /*" +// CHECK: key.sourcetext: " comment content" +// CHECK: key.sourcetext: " */) bar" diff --git a/test/SourceKit/CodeFormat/indent-multiline-string-nested.swift b/test/SourceKit/CodeFormat/indent-multiline-string-nested.swift new file mode 100644 index 0000000000000..feeff5ef5c468 --- /dev/null +++ b/test/SourceKit/CodeFormat/indent-multiline-string-nested.swift @@ -0,0 +1,25 @@ +func foo() { + let s1 = """ + this is line1 in outer string \(""" + nested string in interpolation + """) + + this is line2 in outer string + """ +} + +// RUN: %sourcekitd-test -req=format -line=3 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=4 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=5 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=6 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=7 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=8 %s >>%t.response + +// RUN: %FileCheck --strict-whitespace %s <%t.response + +// CHECK: key.sourcetext: " this is line1 in outer string \\(\"\"\"" +// CHECK: key.sourcetext: " nested string in interpolation" +// CHECK: key.sourcetext: " \"\"\")" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line2 in outer string" +// CHECK: key.sourcetext: " \"\"\"" diff --git a/test/SourceKit/CodeFormat/indent-multiline-string-trailing-interp.swift b/test/SourceKit/CodeFormat/indent-multiline-string-trailing-interp.swift new file mode 100644 index 0000000000000..254f91c087f40 --- /dev/null +++ b/test/SourceKit/CodeFormat/indent-multiline-string-trailing-interp.swift @@ -0,0 +1,31 @@ +// RUN: %sourcekitd-test -req=format -line=24 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=25 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=26 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=27 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=28 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=29 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=30 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=31 %s >>%t.response + +// RUN: %FileCheck --strict-whitespace %s <%t.response + +// The end quotes are ignored as it would be impossible to know whether +// they are part of the interpolation or another string, etc. +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line1" +// CHECK: key.sourcetext: "" +// CHECK: key.sourcetext: "this is line2" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " and this is a line with trailing interpolation \\(1 +" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " \"\"\"" + +let s1 = """ + +this is line1 + + this is line2 + + and this is a line with trailing interpolation \(1 + + + """ diff --git a/test/SourceKit/CodeFormat/indent-multiline-string-trailing-ownline.swift b/test/SourceKit/CodeFormat/indent-multiline-string-trailing-ownline.swift new file mode 100644 index 0000000000000..a709366985b4d --- /dev/null +++ b/test/SourceKit/CodeFormat/indent-multiline-string-trailing-ownline.swift @@ -0,0 +1,24 @@ +// RUN: %sourcekitd-test -req=format -line=19 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=20 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=21 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=22 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=23 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=24 %s >>%t.response + +// RUN: %FileCheck --strict-whitespace %s <%t.response + +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line1" +// CHECK: key.sourcetext: "" +// CHECK: key.sourcetext: "this is line2" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " " + +let s1 = + """ + +this is line1 + + this is line2 + + diff --git a/test/SourceKit/CodeFormat/indent-multiline-string-trailing.swift b/test/SourceKit/CodeFormat/indent-multiline-string-trailing.swift new file mode 100644 index 0000000000000..aad9b33e03312 --- /dev/null +++ b/test/SourceKit/CodeFormat/indent-multiline-string-trailing.swift @@ -0,0 +1,23 @@ +// RUN: %sourcekitd-test -req=format -line=18 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=19 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=20 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=21 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=22 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=23 %s >>%t.response + +// RUN: %FileCheck --strict-whitespace %s <%t.response + +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line1" +// CHECK: key.sourcetext: "" +// CHECK: key.sourcetext: "this is line2" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " " + +let s1 = """ + +this is line1 + + this is line2 + + diff --git a/test/SourceKit/CodeFormat/indent-multiline-string.swift b/test/SourceKit/CodeFormat/indent-multiline-string.swift index bab0eb7c80f32..3348f32c5eeab 100644 --- a/test/SourceKit/CodeFormat/indent-multiline-string.swift +++ b/test/SourceKit/CodeFormat/indent-multiline-string.swift @@ -1,20 +1,44 @@ func foo() { let s1 = """ -this is line1, - this is line2, + +this is line1 + + this is line2 + + + this is line3 + this is a line with interpolation \(1 + + 2) + """ + + let s2 = """ """ - let s1 = - "content" } -// RUN: %sourcekitd-test -req=format -line=3 -length=1 %s >%t.response -// RUN: %sourcekitd-test -req=format -line=4 -length=1 %s >>%t.response -// RUN: %sourcekitd-test -req=format -line=5 -length=1 %s >>%t.response -// RUN: %sourcekitd-test -req=format -line=7 -length=1 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=2 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=3 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=4 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=5 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=6 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=7 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=8 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=9 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=10 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=11 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=12 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=15 %s >>%t.response // RUN: %FileCheck --strict-whitespace %s <%t.response -// CHECK: key.sourcetext: "this is line1," -// CHECK: key.sourcetext: " this is line2," +// CHECK: key.sourcetext: " let s1 = \"\"\"" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line1" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line2" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line3" +// CHECK: key.sourcetext: " this is a line with interpolation \\(1 +" +// CHECK: key.sourcetext: " 2)" +// CHECK: key.sourcetext: " \"\"\"" // CHECK: key.sourcetext: "\"\"\"" -// CHECK: key.sourcetext: " \"content\"" diff --git a/test/SourceKit/ConformingMethods/basic.swift b/test/SourceKit/ConformingMethods/basic.swift index 35701bdefb7dc..551c53336ab90 100644 --- a/test/SourceKit/ConformingMethods/basic.swift +++ b/test/SourceKit/ConformingMethods/basic.swift @@ -26,9 +26,12 @@ func testing(obj: C) { let _ = obj. } -// RUN: %sourcekitd-test -req=conformingmethods -pos=26:14 -repeat-request=2 %s -req-opts=expectedtypes='$s8MyModule7Target2PD;$s8MyModule7Target1PD' -- -module-name MyModule %s > %t.response +// RUN: %sourcekitd-test \ +// RUN: -req=conformingmethods -pos=26:14 -repeat-request=2 %s -req-opts=expectedtypes='$s8MyModule7Target2PD;$s8MyModule7Target1PD' -- -module-name MyModule %s > %t.response // RUN: %diff -u %s.response %t.response -// RUN: %sourcekitd-test -req=conformingmethods -pos=26:14 -repeat-request=2 %s -req-opts=expectedtypes='$s8MyModule7Target2PD;$s8MyModule7Target1PD',reuseastcontext=0 -- -module-name MyModule %s | %FileCheck %s --check-prefix=DISABLED +// RUN: %sourcekitd-test \ +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=0 == \ +// RUN: -req=conformingmethods -pos=26:14 -repeat-request=2 %s -req-opts=expectedtypes='$s8MyModule7Target2PD;$s8MyModule7Target1PD' -- -module-name MyModule %s | %FileCheck %s --check-prefix=DISABLED // DISABLED-NOT: key.reuseastcontext // DISABLED: key.members: [ diff --git a/test/SourceKit/CursorInfo/use-swift-source-info.swift b/test/SourceKit/CursorInfo/use-swift-source-info.swift index 7f905f4cf52ca..6130411f17a47 100644 --- a/test/SourceKit/CursorInfo/use-swift-source-info.swift +++ b/test/SourceKit/CursorInfo/use-swift-source-info.swift @@ -3,16 +3,19 @@ func bar() { foo() } +// FIXME: Rmove REQUIRES rdar://problem/60096971 +// REQUIRES: rdar60096971 + // RUN: %empty-directory(%t) // RUN: echo "/// Some doc" >> %t/Foo.swift // RUN: echo "public func foo() { }" >> %t/Foo.swift // RUN: %target-swift-frontend -enable-batch-mode -emit-module -emit-module-doc -emit-module-path %t/Foo.swiftmodule %t/Foo.swift -module-name Foo -emit-module-source-info-path %t/Foo.swiftsourceinfo -emit-module-doc-path %t/Foo.swiftdoc // // Test setting optimize for ide to false -// RUN: %sourcekitd-test -req=global-config -for-ide=0 == -req=cursor -pos=3:3 %s -- -I %t -target %target-triple %s | %FileCheck --check-prefixes=BOTH,WITH %s +// RUN: %sourcekitd-test -req=global-config -req-opts=optimize_for_ide=0 == -req=cursor -pos=3:3 %s -- -I %t -target %target-triple %s | %FileCheck --check-prefixes=BOTH,WITH %s // // Test setting optimize for ide to true -// RUN: %sourcekitd-test -req=global-config -for-ide=1 == -req=cursor -pos=3:3 %s -- -I %t -target %target-triple %s | %FileCheck --check-prefixes=BOTH,WITHOUT %s +// RUN: %sourcekitd-test -req=global-config -req-opts=optimize_for_ide=1 == -req=cursor -pos=3:3 %s -- -I %t -target %target-triple %s | %FileCheck --check-prefixes=BOTH,WITHOUT %s // // Test sourcekitd-test's default global configuration request (optimize for ide is true) // RUN: %sourcekitd-test -req=cursor -pos=3:3 %s -- -I %t -target %target-triple %s | %FileCheck --check-prefixes=BOTH,WITHOUT %s diff --git a/test/SourceKit/TypeContextInfo/typecontext_basic.swift b/test/SourceKit/TypeContextInfo/typecontext_basic.swift index def196cd861c4..0eda3237abd2a 100644 --- a/test/SourceKit/TypeContextInfo/typecontext_basic.swift +++ b/test/SourceKit/TypeContextInfo/typecontext_basic.swift @@ -25,9 +25,12 @@ func test(obj: C) { let _ = obj.foo(x: } -// RUN: %sourcekitd-test -req=typecontextinfo -repeat-request=2 -pos=25:22 %s -- %s > %t.response +// RUN: %sourcekitd-test \ +// RUN: -req=typecontextinfo -repeat-request=2 -pos=25:22 %s -- %s > %t.response // RUN: %diff -u %s.response %t.response -// RUN: %sourcekitd-test -req=typecontextinfo -repeat-request=2 -pos=25:22 %s -req-opts=reuseastcontext=0 -- %s | %FileCheck %s --check-prefix=DISABLED +// RUN: %sourcekitd-test \ +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=0 == \ +// RUN: -req=typecontextinfo -repeat-request=2 -pos=25:22 %s -- %s | %FileCheck %s --check-prefix=DISABLED // DISABLED-NOT: key.reuseastcontext // DISABLED: key.results: [ diff --git a/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/UnderscoreNotLinked.swift b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/UnderscoreNotLinked.swift new file mode 100644 index 0000000000000..9fe3d6e819519 --- /dev/null +++ b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/UnderscoreNotLinked.swift @@ -0,0 +1,11 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name UnderscoreNotLinked -emit-module -emit-module-path %t/ +// RUN: %target-swift-symbolgraph-extract -module-name UnderscoreNotLinked -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/UnderscoreNotLinked.symbols.json + +public protocol _ShouldntBeLinked {} +public protocol ShouldBeLinked : _ShouldntBeLinked {} +public struct MyStruct : ShouldBeLinked {} + +// CHECK: "spelling": "_ShouldntBeLinked" +// CHECK-NOT: "preciseIdentifier": "s:19UnderscoreNotLinked011_ShouldntBeC0P" diff --git a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds index 43bd7aa16e71e..61dfcac3126bb 100644 --- a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds +++ b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds @@ -102,13 +102,15 @@ class C { @objc private init(a: Int) init!(a: Int) {} init?(a: Int) {} - public init(a: Int) throws {} + public init(a: Int) throws {} + init(a: Int..., b: Double...) {} @objc deinit {} private deinit {} internal subscript(x: Int) -> Int { get {} set {} } - subscript() -> Int { return 1 } + subscript() -> Int { return 1 } + subscript(x: Int..., y y: String...) -> Int { return 1 } var x: Int { address { fatalError() } @@ -197,7 +199,8 @@ func foo(_ _: Int = true ? 2: 3, @objc e: X = true, f: inout Int, - g: Int...) throws -> [Int: String] {} + g: Int..., + h: Bool...) throws -> [Int: String] {} func foo(_ a: Int) throws -> Int {} func foo( a: Int) rethrows -> Int {} diff --git a/test/Syntax/Parser/async.swift b/test/Syntax/Parser/async.swift new file mode 100644 index 0000000000000..686491170eb4d --- /dev/null +++ b/test/Syntax/Parser/async.swift @@ -0,0 +1,28 @@ +// Verify that async parses correctly via the parser lib even without the +// experimental flag being set in LangOpts. +// +// REQUIRES: syntax_parser_lib +// RUN: %swift-syntax-parser-test %s -dump-diags 2>&1 | %FileCheck %s + +func asyncGlobal1() async { } +func asyncGlobal2() async throws { } + +typealias AsyncFunc1 = () async -> () +typealias AsyncFunc2 = () async throws -> () + +func testTypeExprs() { + let _ = [() async -> ()]() + let _ = [() async throws -> ()]() +} + +func testAwaitOperator() async { + let _ = await asyncGlobal1() +} + +func testAsyncClosure() { + let _ = { () async in 5 } + let _ = { () throws in 5 } + let _ = { () async throws in 5 } +} + +// CHECK: 0 error(s) 0 warnings(s) 0 note(s) diff --git a/test/Syntax/round_trip_parse_gen.swift b/test/Syntax/round_trip_parse_gen.swift index 8c4c998fb49cb..6c68ff5aadae2 100644 --- a/test/Syntax/round_trip_parse_gen.swift +++ b/test/Syntax/round_trip_parse_gen.swift @@ -103,12 +103,14 @@ class C { init!(a: Int) {} init?(a: Int) {} public init(a: Int) throws {} + init(a: Int..., b: Double...) {} @objc deinit {} private deinit {} internal subscript(x: Int) -> Int { get {} set {} } subscript() -> Int { return 1 } + subscript(x: Int..., y y: String...) -> Int { return 1 } var x: Int { address { fatalError() } @@ -197,7 +199,8 @@ func foo(_ _: Int, d _: Int = true ? 2: 3, @objc e: X = true, f: inout Int, - g: Int...) throws -> [Int: String] {} + g: Int..., + h: Bool...) throws -> [Int: String] {} func foo(_ a: Int) throws -> Int {} func foo( a: Int) rethrows -> Int {} diff --git a/test/TypeDecoder/opaque_return_type.swift b/test/TypeDecoder/opaque_return_type.swift index 94b139ad48d1e..327e4860570d8 100644 --- a/test/TypeDecoder/opaque_return_type.swift +++ b/test/TypeDecoder/opaque_return_type.swift @@ -12,6 +12,12 @@ var prop: some P { return 0 } func bar() -> some Sequence { return [] } +struct G {} + +extension G where T == Int { + var baz: some P { return 0 } +} + // DEMANGLE: $s18opaque_return_type3fooQryFQOyQo_ // CHECK: some P @@ -21,5 +27,8 @@ func bar() -> some Sequence { return [] } // DEMANGLE: $s18opaque_return_type3barQryFQOyQo_ // CHECK: some Sequence +// DEMANGLE: $s18opaque_return_type1GVAASiRszlE3bazQrvpQOySi_Qo_ +// CHECK: some P + // DEMANGLE: $s18opaque_return_type3barQryFQOyQo_7ElementSTQxD // CHECK: (some Sequence).Element diff --git a/test/api-digester/Inputs/cake.swift b/test/api-digester/Inputs/cake.swift index 3de399487412f..b1728b6f61d48 100644 --- a/test/api-digester/Inputs/cake.swift +++ b/test/api-digester/Inputs/cake.swift @@ -139,3 +139,6 @@ public class UnavailableOnMac {} extension SwiftObjcClass { public func functionUnavailableOnMac() {} } + +@_alwaysEmitIntoClient +public func emitIntoClientFunc() {} diff --git a/test/api-digester/Outputs/cake.json b/test/api-digester/Outputs/cake.json index 8a487febb665b..08a230436a852 100644 --- a/test/api-digester/Outputs/cake.json +++ b/test/api-digester/Outputs/cake.json @@ -1340,6 +1340,25 @@ ], "hasMissingDesignatedInitializers": true }, + { + "kind": "Function", + "name": "emitIntoClientFunc", + "printedName": "emitIntoClientFunc()", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + } + ], + "declKind": "Func", + "usr": "s:4cake18emitIntoClientFuncyyF", + "moduleName": "cake", + "declAttributes": [ + "AlwaysEmitIntoClient" + ], + "funcSelfKind": "NonMutating" + }, { "kind": "TypeDecl", "name": "Int", diff --git a/test/api-digester/Outputs/clang-module-dump.txt b/test/api-digester/Outputs/clang-module-dump.txt index 43ec745788e68..3f928e1abbc71 100644 --- a/test/api-digester/Outputs/clang-module-dump.txt +++ b/test/api-digester/Outputs/clang-module-dump.txt @@ -43,6 +43,7 @@ "declKind": "Protocol", "usr": "c:objc(pl)AnotherObjcProt", "moduleName": "Foo", + "genericSig": "", "objc_name": "AnotherObjcProt", "declAttributes": [ "ObjC", @@ -196,6 +197,7 @@ "declKind": "Protocol", "usr": "c:objc(pl)ObjcProt", "moduleName": "Foo", + "genericSig": "", "objc_name": "ObjcProt", "declAttributes": [ "ObjC", diff --git a/test/api-digester/breakage-allowlist.swift b/test/api-digester/breakage-allowlist.swift new file mode 100644 index 0000000000000..9bb5aa7af626c --- /dev/null +++ b/test/api-digester/breakage-allowlist.swift @@ -0,0 +1,38 @@ +// REQUIRES: VENDOR=apple + +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t.mod1) +// RUN: %empty-directory(%t.mod2) +// RUN: %empty-directory(%t.sdk) +// RUN: %empty-directory(%t.module-cache) +// RUN: %empty-directory(%t.baseline/ABI) + +// RUN: echo "public func foo() {}" > %t.mod1/Foo.swift +// RUN: echo "public func bar() {}" > %t.mod2/Foo.swift + +// RUN: echo "Foo: Func foo() has been removed" > %t/incomplete-allowlist.txt +// RUN: echo "Foo: Func foo() has been removed" > %t/complete-allowlist.txt +// RUN: echo "Foo: Func bar() is a new API without @available attribute" >> %t/complete-allowlist.txt + +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -emit-module -o %t.mod1/Foo.swiftmodule %t.mod1/Foo.swift -parse-as-library -enable-library-evolution -emit-module-source-info -emit-module-source-info-path %t.mod1/Foo.swiftsourceinfo -emit-module-interface-path %t.mod1/Foo.swiftinterface -module-name Foo -swift-version 5 + +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -emit-module -o %t.mod2/Foo.swiftmodule %t.mod2/Foo.swift -parse-as-library -enable-library-evolution -emit-module-source-info -emit-module-source-info-path %t.mod2/Foo.swiftsourceinfo -emit-module-interface-path %t.mod2/Foo.swiftinterface -module-name Foo -swift-version 5 + +// RUN: %api-digester -dump-sdk -module Foo -output-dir %t.baseline -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod1 -abi -use-interface-for-module Foo + +// RUN: %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -breakage-allowlist-path %t/complete-allowlist.txt -o %t/expected-diags.txt + +// RUN: not %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -compiler-style-diags + +// RUN: not %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -compiler-style-diags -breakage-allowlist-path %t/incomplete-allowlist.txt + +// RUN: %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -compiler-style-diags -breakage-allowlist-path %t/complete-allowlist.txt + +// RUN: not %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -serialize-diagnostics-path %t/serialized-diag.dia +// RUN: ls %t/serialized-diag.dia + +// RUN: not %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -serialize-diagnostics-path %t/serialized-diag.dia -breakage-allowlist-path %t/incomplete-allowlist.txt +// RUN: ls %t/serialized-diag.dia + +// RUN: %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -serialize-diagnostics-path %t/serialized-diag.dia -breakage-allowlist-path %t/complete-allowlist.txt +// RUN: ls %t/serialized-diag.dia diff --git a/test/api-digester/compare-clang-dump.swift b/test/api-digester/compare-clang-dump.swift index cdb59d1bf93a4..3cafec46d6288 100644 --- a/test/api-digester/compare-clang-dump.swift +++ b/test/api-digester/compare-clang-dump.swift @@ -3,7 +3,7 @@ // RUN: %empty-directory(%t.module-cache) // RUN: %api-digester -dump-sdk -module Foo -o %t.dump1.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %S/Inputs/Foo -avoid-location // RUN: %api-digester -dump-sdk -module Foo -o %t.dump2.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %S/Inputs/Foo-new-version -avoid-location -// RUN: %api-digester -diagnose-sdk -protocol-requirement-white-list %S/Inputs/Foo-prot-allowlist.txt -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -o %t.result +// RUN: %api-digester -diagnose-sdk -protocol-requirement-allow-list %S/Inputs/Foo-prot-allowlist.txt -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -o %t.result // RUN: %clang -E -P -x c %S/Outputs/Foo-diff.txt -o - | sed '/^\s*$/d' > %t.expected // RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp diff --git a/test/api-digester/use-interface-for.swift b/test/api-digester/use-interface-for.swift new file mode 100644 index 0000000000000..6399084893092 --- /dev/null +++ b/test/api-digester/use-interface-for.swift @@ -0,0 +1,20 @@ +// REQUIRES: VENDOR=apple + +// RUN: %empty-directory(%t.mod) +// RUN: %empty-directory(%t.sdk) +// RUN: %empty-directory(%t.module-cache) + +// RUN: echo "public func foo() {}" > %t.swift + +// RUN: %target-swift-frontend -emit-module -emit-module-interface-path %t.mod/cake.swiftinterface %t.swift %clang-importer-sdk-nosource -parse-as-library -enable-library-evolution -disable-objc-attr-requires-foundation-module -module-cache-path %t.module-cache -emit-module-path %t.mod/cake.swiftmodule -module-name cake -swift-version 5 + +// Step 1: we should be able to load if we prefer cake.swiftinterface +// RUN: %api-digester -dump-sdk -print-module -module cake -I %t.mod -sdk %clang-importer-sdk-path -module-cache-path %t.module-cache -o %t.json -abi -abort-on-module-fail -use-interface-for-module cake + +// RUN: echo "Swift Syntax Error" >> %t.mod/cake.swiftinterface + +// Step 2: we shouldn't be able to load if we prefer cake.swiftinterface and cake.swiftinterface is broken +// RUN: not %api-digester -dump-sdk -print-module -module cake -I %t.mod -sdk %clang-importer-sdk-path -module-cache-path %t.module-cache -o %t.json -abi -abort-on-module-fail -use-interface-for-module cake + +// Step 3: we should be able to load if we don't prefer cake.swiftinterface +// RUN: %api-digester -dump-sdk -print-module -module cake -I %t.mod -sdk %clang-importer-sdk-path -module-cache-path %t.module-cache -o %t.json -abi -abort-on-module-fail diff --git a/test/attr/asynchandler.swift b/test/attr/asynchandler.swift new file mode 100644 index 0000000000000..e3147f62edbdd --- /dev/null +++ b/test/attr/asynchandler.swift @@ -0,0 +1,52 @@ +// RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-concurrency + +func globalAsyncFunction() async -> Int { 0 } + +@asyncHandler func asyncHandler1() { + // okay, it's an async context + let _ = await globalAsyncFunction() +} + +@asyncHandler func asyncHandler2(fn: @autoclosure () async -> Int ) { + // okay, it's an async context +} + +@asyncHandler +func asyncHandlerBad1() -> Int { 0 } +// expected-error@-1{{'@asyncHandler' function can only return 'Void'}} + +@asyncHandler +func asyncHandlerBad2() async { } +// expected-error@-1{{'@asyncHandler' function cannot be 'async' itself}}{{25-31=}} + +@asyncHandler +func asyncHandlerBad3() throws { } +// expected-error@-1{{'@asyncHandler' function cannot throw}}{{25-32=}} + +@asyncHandler +func asyncHandlerBad4(result: inout Int) { } +// expected-error@-1{{'inout' parameter is not allowed in '@asyncHandler' function}} + +struct X { + @asyncHandler func asyncHandlerMethod() { } + + @asyncHandler + mutating func asyncHandlerMethodBad1() { } + // expected-error@-1{{'@asyncHandler' function cannot be 'mutating'}}{{3-12=}} + + @asyncHandler init() { } + // expected-error@-1{{@asyncHandler may only be used on 'func' declarations}} +} + + +// Inference of @asyncHandler +protocol P { + @asyncHandler func callback() +} + +extension X: P { + func callback() { + // okay, it's an async context + let _ = await globalAsyncFunction() + } +} diff --git a/test/attr/asynchandler_noconcurrency.swift b/test/attr/asynchandler_noconcurrency.swift new file mode 100644 index 0000000000000..97545fd0bc555 --- /dev/null +++ b/test/attr/asynchandler_noconcurrency.swift @@ -0,0 +1,4 @@ +// RUN: %target-swift-frontend -typecheck -verify %s + +@asyncHandler func asyncHandler1() { } +// expected-error@-1{{'@asyncHandler' is only valid when experimental concurrency is enabled}} diff --git a/test/attr/attr_cdecl_async.swift b/test/attr/attr_cdecl_async.swift new file mode 100644 index 0000000000000..2cf765e8da20f --- /dev/null +++ b/test/attr/attr_cdecl_async.swift @@ -0,0 +1,5 @@ +// RUN: %target-typecheck-verify-swift -enable-objc-interop -enable-experimental-concurrency + +@_cdecl("async") // expected-error{{@_cdecl functions cannot be asynchronous}} +func asynchronous() async { } + diff --git a/test/attr/attr_objc.swift b/test/attr/attr_objc.swift index 946e0c8c26e92..77848a0ab196a 100644 --- a/test/attr/attr_objc.swift +++ b/test/attr/attr_objc.swift @@ -1,6 +1,6 @@ -// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify -verify-ignore-unknown %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency -// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency | %FileCheck %s -// RUN: not %target-swift-frontend -typecheck -dump-ast -disable-objc-attr-requires-foundation-module %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency > %t.ast +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify -verify-ignore-unknown %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference +// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference | %FileCheck %s +// RUN: not %target-swift-frontend -typecheck -dump-ast -disable-objc-attr-requires-foundation-module %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference > %t.ast // RUN: %FileCheck -check-prefix CHECK-DUMP %s < %t.ast // REQUIRES: objc_interop @@ -2381,11 +2381,3 @@ class SR12801 { @objc subscript(foo : [T]) -> Int { return 0 } // expected-error@-1 {{subscript cannot be marked @objc because it has generic parameters}} } - -// async cannot be compiled with @objc. -class Concurrency { - @objc func doBigJob() async -> Int { return 0 } // expected-error{{'async' function cannot be represented in Objective-C}} - - @objc func takeAnAsync(_ fn: () async -> Int) { } // expected-error{{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}} - // expected-note@-1{{'async' function types cannot be represented in Objective-C}} -} diff --git a/test/attr/attr_objc_async.swift b/test/attr/attr_objc_async.swift new file mode 100644 index 0000000000000..a3a2aad0c459d --- /dev/null +++ b/test/attr/attr_objc_async.swift @@ -0,0 +1,23 @@ +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify -verify-ignore-unknown %s -swift-version 5 -enable-source-import -I %S/Inputs -enable-experimental-concurrency +// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 5 -enable-source-import -I %S/Inputs -enable-experimental-concurrency | %FileCheck %s +// RUN: not %target-swift-frontend -typecheck -dump-ast -disable-objc-attr-requires-foundation-module %s -swift-version 5 -enable-source-import -I %S/Inputs -enable-experimental-concurrency > %t.ast +// RUN: %FileCheck -check-prefix CHECK-DUMP %s < %t.ast +// REQUIRES: objc_interop +import Foundation + +// CHECK: class Concurrency +class Concurrency { + // CHECK: @objc func doBigJob() async -> Int + // CHECK-DUMP: func_decl{{.*}}doBigJob{{.*}}foreign_async=@convention(block) (Int) -> (),completion_handler_param=0 + @objc func doBigJob() async -> Int { return 0 } + + // CHECK: @objc func doBigJobOrFail(_: Int) async throws -> (AnyObject, Int) + // CHECK-DUMP: func_decl{{.*}}doBigJobOrFail{{.*}}foreign_async=@convention(block) (Optional, Int, Optional) -> (),completion_handler_param=1,error_param=2 + @objc func doBigJobOrFail(_: Int) async throws -> (AnyObject, Int) { return (self, 0) } + + @objc func takeAnAsync(_ fn: () async -> Int) { } // expected-error{{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}} + // expected-note@-1{{'async' function types cannot be represented in Objective-C}} + + @objc class func createAsynchronously() async -> Self? { nil } + // expected-error@-1{{asynchronous method returning 'Self' cannot be '@objc'}} +} diff --git a/test/attr/attr_override.swift b/test/attr/attr_override.swift index b059d707a578f..e234a294b9e02 100644 --- a/test/attr/attr_override.swift +++ b/test/attr/attr_override.swift @@ -590,7 +590,7 @@ class SR_4206_Base_7 { } class SR_4206_Derived_7: SR_4206_Base_7 { - override func foo1() where T: SR_4206_Protocol_2 {} // expected-error {{overridden method 'foo1' has generic signature which is incompatible with base method's generic signature ; expected generic signature to be }} + override func foo1() where T: SR_4206_Protocol_2 {} // expected-error {{overridden method 'foo1' has generic signature which is incompatible with base method's generic signature ; expected generic signature to be }} override func foo2() {} // OK } @@ -627,7 +627,7 @@ class SR_4206_Base_10 { func foo() where T: SR_4206_Protocol_1 {} // expected-note {{overridden declaration is here}} } class SR_4206_Derived_10: SR_4206_Base_10 { - override func foo() where U: SR_4206_Protocol_1 {} // expected-error {{overridden method 'foo' has generic signature which is incompatible with base method's generic signature ; expected generic signature to be }} + override func foo() where U: SR_4206_Protocol_1 {} // expected-error {{overridden method 'foo' has generic signature which is incompatible with base method's generic signature ; expected generic signature to be }} } // Override with return type specialization diff --git a/test/decl/async/objc.swift b/test/decl/async/objc.swift new file mode 100644 index 0000000000000..96fba77b9826b --- /dev/null +++ b/test/decl/async/objc.swift @@ -0,0 +1,44 @@ +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify %s -swift-version 5 -enable-experimental-concurrency +// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 5 -enable-experimental-concurrency | %FileCheck %s +// REQUIRES: objc_interop +import Foundation +import ObjectiveC + +@objc protocol P { + func doBigJob() async -> Int +} + +// Infer @objc from protocol conformance +// CHECK: class ConformsToP +class ConformsToP: P { + // CHECK: @objc func doBigJob() async -> Int + func doBigJob() async -> Int { 5 } +} + +// Infer @objc from superclass +class Super { + @objc func longRunningRequest() async throws -> [String] { [] } +} + +// CHECK: class Sub +class Sub : Super { + // CHECK-NEXT: @objc override func longRunningRequest() async throws -> [String] + override func longRunningRequest() async throws -> [String] { [] } +} + +// Check selector computation. +@objc protocol MakeSelectors { + func selectorAsync() async -> Int + func selector(value: Int) async -> Int +} + +func testSelectors() { + // expected-warning@+1{{use '#selector' instead of explicitly constructing a 'Selector'}} + _ = Selector("selectorAsyncWithCompletionHandler:") + + // expected-warning@+1{{use '#selector' instead of explicitly constructing a 'Selector'}} + _ = Selector("selectorWithValue:completionHandler:") + + _ = Selector("canary:") // expected-warning{{no method declared with Objective-C selector 'canary:'}} + // expected-note@-1{{wrap the selector name in parentheses to suppress this warning}} +} diff --git a/test/decl/enum/enumtest.swift b/test/decl/enum/enumtest.swift index 57b8117e65b0c..3f5a450adf228 100644 --- a/test/decl/enum/enumtest.swift +++ b/test/decl/enum/enumtest.swift @@ -100,8 +100,7 @@ func test3a(_ a: ZeroOneTwoThree) { var h = ZeroOneTwoThree(1) var i = 0 > 3 ? .none : .some(3) // expected-error {{cannot infer contextual base in reference to member 'none'}} - // expected-error@-1 {{cannot infer contextual base in reference to member 'some'}} - + test3a; // expected-error {{unused function}} .Zero // expected-error {{reference to member 'Zero' cannot be resolved without a contextual type}} test3a // expected-error {{unused function}} diff --git a/test/decl/ext/extensions.swift b/test/decl/ext/extensions.swift index 485ff4da476d7..b6f5133acfd8d 100644 --- a/test/decl/ext/extensions.swift +++ b/test/decl/ext/extensions.swift @@ -267,14 +267,14 @@ extension ImposeClassReq1 where Self: AnyObject { var wrappingProperty2: Int { get { return someProperty } - mutating set { someProperty = newValue } // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} + mutating set { someProperty = newValue } // expected-error {{'mutating' is not valid on setters in class-bound protocols}} } - mutating func foo() { // expected-error {{mutating' isn't valid on methods in classes or class-bound protocols}} + mutating func foo() { // expected-error {{mutating' is not valid on instance methods in class-bound protocols}} someProperty = 1 } - nonmutating func bar() { // expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} + nonmutating func bar() { // expected-error {{'nonmutating' is not valid on instance methods in class-bound protocols}} someProperty = 2 } @@ -309,14 +309,14 @@ extension ImposeClassReq2 { var wrappingProperty2: Int { get { return someProperty } - mutating set { someProperty = newValue } // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} + mutating set { someProperty = newValue } // expected-error {{'mutating' is not valid on setters in class-bound protocols}} } - mutating func foo() { // expected-error {{mutating' isn't valid on methods in classes or class-bound protocols}} + mutating func foo() { // expected-error {{mutating' is not valid on instance methods in class-bound protocols}} someProperty = 1 } - nonmutating func bar() { // expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} + nonmutating func bar() { // expected-error {{'nonmutating' is not valid on instance methods in class-bound protocols}} someProperty = 2 } @@ -349,3 +349,10 @@ struct SR_10466 { extension SR_10466 where T == Never { // expected-note {{requirement specified as 'T' == 'Never' [with T = T]}} typealias A = Int } + +#if true +protocol Rdar66943328 { + associatedtype Assoc +} +extension Rdar66943328 where Assoc == Int // expected-error {{expected '{' in extension}} +#endif diff --git a/test/decl/func/vararg.swift b/test/decl/func/vararg.swift index 36bda36730f59..71befae75ef90 100644 --- a/test/decl/func/vararg.swift +++ b/test/decl/func/vararg.swift @@ -27,7 +27,38 @@ func invalidVariadic(_ e: NonExistentType) { // expected-error {{cannot find typ { (e: ExtraCrispy...) in }() // expected-error {{cannot find type 'ExtraCrispy' in scope}} } -func twoVariadics(_ a: Int..., b: Int...) { } // expected-error{{only a single variadic parameter '...' is permitted}} {{38-41=}} +func twoVariadics(_ a: Int..., b: Int...) { } +func unlabeledFollowingVariadic(_ a: Int..., _ b: Int) { } // expected-error {{a parameter following a variadic parameter requires a label}} +func unlabeledVariadicFollowingVariadic(_ a: Int..., _ b: Int...) { } // expected-error {{a parameter following a variadic parameter requires a label}} +func unlabeledFollowingTwoVariadics(_ a: Int..., b: Int..., _ c: Int) { } // expected-error {{a parameter following a variadic parameter requires a label}} +func splitVariadics(_ a: Int..., b: Int, _ c: String...) { } +func splitByDefaultArgVariadics(_ a: Int..., b: Int = 0, _ c: String...) { } + +struct HasSubscripts { + subscript(a: Int...) -> Void { () } + subscript(a: Int..., b b: Int...) -> Void { () } + subscript(a: Int..., b: Int...) -> Void { () } // expected-error {{a parameter following a variadic parameter requires a label}} + subscript(a: Int..., b: Int) -> Void { () } // expected-error {{a parameter following a variadic parameter requires a label}} + subscript(a: Int..., b b: Int..., c c: Int) -> Void { () } + subscript(a: Int..., b b: Int..., c: Int) -> Void { () } // expected-error {{a parameter following a variadic parameter requires a label}} + subscript(a: Int..., c c: Int = 0, b: Int...) -> Void { () } + subscript(a: Int..., b: String = "hello, world!") -> Bool { false } // expected-error {{a parameter following a variadic parameter requires a label}} +} + +struct HasInitializers { + init(a: Int...) {} + init(a: Int..., b: Int...) {} + init(a: Int..., _ b: Int...) {} // expected-error {{a parameter following a variadic parameter requires a label}} + init(a: Int..., c: Int = 0, _ b: Int...) {} +} + +let closure = {(x: Int..., y: Int...) in } // expected-error {{no parameters may follow a variadic parameter in a closure}} +let closure2 = {(x: Int..., y: Int) in } // expected-error {{no parameters may follow a variadic parameter in a closure}} +let closure3 = {(x: Int..., y: Int, z: Int...) in } // expected-error {{no parameters may follow a variadic parameter in a closure}} +let closure4 = {(x: Int...) in } +let closure5 = {(x: Int, y: Int...) in } +let closure6 = {(x: Int..., y z: Int) in } // expected-error {{closure cannot have keyword arguments}} +// expected-error@-1 {{no parameters may follow a variadic parameter in a closure}} // rdar://22056861 func f5(_ list: Any..., end: String = "") {} diff --git a/test/decl/nested/protocol.swift b/test/decl/nested/protocol.swift index 2d820f9224832..2ccc15b74e9a3 100644 --- a/test/decl/nested/protocol.swift +++ b/test/decl/nested/protocol.swift @@ -51,10 +51,11 @@ protocol Racoon { } enum SillyRawEnum : SillyProtocol.InnerClass {} // expected-error {{an enum with no cases cannot declare a raw type}} -// expected-error@-1 {{raw type}} +// expected-error@-1 {{reference to generic type 'SillyProtocol.InnerClass' requires arguments in <...>}} protocol SillyProtocol { class InnerClass {} // expected-error {{type 'InnerClass' cannot be nested in protocol 'SillyProtocol'}} + // expected-note@-1 {{generic type 'InnerClass' declared here}} } // N.B. Redeclaration checks don't see this case because `protocol A` is invalid. diff --git a/test/decl/overload.swift b/test/decl/overload.swift index 07ba5b7e948eb..b769dd03c7c9e 100644 --- a/test/decl/overload.swift +++ b/test/decl/overload.swift @@ -79,7 +79,6 @@ enum mixed_redecl3 {} // expected-error {{invalid redeclaration}} // expected-note @-1 2{{found this candidate}} enum mixed_redecl3a : mixed_redecl3 {} // expected-error {{'mixed_redecl3' is ambiguous for type lookup in this context}} // expected-error@-1 {{an enum with no cases cannot declare a raw type}} -// expected-error@-2 {{raw type}} class mixed_redecl3b : mixed_redecl3 {} // expected-error {{'mixed_redecl3' is ambiguous for type lookup in this context}} class mixed_redecl4 {} // expected-note {{previously declared here}} diff --git a/test/decl/protocol/conforms/associated_type.swift b/test/decl/protocol/conforms/associated_type.swift index f299611655ef8..805624c6f36a6 100644 --- a/test/decl/protocol/conforms/associated_type.swift +++ b/test/decl/protocol/conforms/associated_type.swift @@ -94,27 +94,8 @@ struct SR_12707_Conform_P2: SR_12707_P2 { typealias A = Never } -// Default type witness -protocol SR_12707_P3 { - associatedtype A - associatedtype B: SR_12707_C<(A, Self)> = SR_12707_C<(A, Self)> -} -struct SR_12707_Conform_P3: SR_12707_P3 { - typealias A = Never -} - -// FIXME: Type witness resolution success is order-dependent. -protocol SR_12707_FIXME_P1 { - associatedtype A -} -protocol SR_12707_FIXME_P2: SR_12707_FIXME_P1 { - associatedtype B: SR_12707_C<(A, Self)> = SR_12707_C<(A, Self)> // expected-note {{default type 'associated_type.SR_12707_C<(associated_type.SR_12707_FIXME_Conform_P2.A, associated_type.SR_12707_FIXME_Conform_P2)>' (aka 'SR_12707_C<(Never, SR_12707_FIXME_Conform_P2)>') for associated type 'B' (from protocol 'SR_12707_FIXME_P2') does not inherit from 'associated_type.SR_12707_C<(associated_type.SR_12707_FIXME_Conform_P2.A, associated_type.SR_12707_FIXME_Conform_P2)>'}} -} -struct SR_12707_FIXME_Conform_P2: SR_12707_FIXME_P2 { // expected-error {{type 'SR_12707_FIXME_Conform_P2' does not conform to protocol 'SR_12707_FIXME_P2'}} - typealias A = Never -} - -// FIXME: Type witness resolution success is order-dependent. +// FIXME: resolveTypeWitnessViaLookup must not happen independently in the +// general case. protocol SR_12707_FIXME_P3 { associatedtype A: SR_12707_C // expected-note {{protocol requires nested type 'A'; do you want to add it?}} associatedtype B @@ -123,3 +104,27 @@ struct SR_12707_FIXME_Conform_P3: SR_12707_FIXME_P3 { // expected-error {{type ' typealias A = SR_12707_C // expected-note {{possibly intended match 'SR_12707_FIXME_Conform_P3.A' (aka 'SR_12707_C') does not inherit from 'SR_12707_C'}} typealias B = Never } + +// FIXME: Associated type inference via value witnesses should consider +// tentative witnesses when checking a candidate. +protocol SR_12707_FIXME_P4 { + associatedtype X = Never + + associatedtype A: SR_12707_C // expected-note {{unable to infer associated type 'A' for protocol 'SR_12707_FIXME_P4'}} + func foo(arg: A) +} +struct SR_12707_FIXME_Conform_P4: SR_12707_FIXME_P4 { // expected-error {{type 'SR_12707_FIXME_Conform_P4' does not conform to protocol 'SR_12707_FIXME_P4'}} + func foo(arg: SR_12707_C) {} // expected-note {{candidate would match and infer 'A' = 'SR_12707_C' if 'SR_12707_C' inherited from 'SR_12707_C'}} +} + +// Abstract type witnesses. +protocol SR_12707_P5a { + associatedtype X = Never + + associatedtype A: SR_12707_C + associatedtype B: SR_12707_C +} +protocol SR_12707_P5b: SR_12707_P5a where B == SR_12707_C { + associatedtype C: SR_12707_C = SR_12707_C +} +struct SR_12707_Conform_P5>: SR_12707_P5b {} diff --git a/test/decl/protocol/fixits_missing_protocols_in_context.swift b/test/decl/protocol/fixits_missing_protocols_in_context.swift new file mode 100644 index 0000000000000..0511266896062 --- /dev/null +++ b/test/decl/protocol/fixits_missing_protocols_in_context.swift @@ -0,0 +1,45 @@ +// RUN: %target-swift-frontend -typecheck -diagnostics-editor-mode -verify %s + +// Test that we emit fix-its to insert requirement stubs for the missing protocol conformance, in addition to adding the conformance. + +protocol P { + func method() + var property: Int { get } +} + +class C { + var p: P? + + func assign() { + p = self + // expected-error@-1 {{cannot assign value of type 'C' to type 'P?'}} + // expected-note@-2 {{add missing conformance to 'P' to class 'C'}} {{8-8=: P}} {{10-10=\n func method() {\n <#code#>\n \}\n\n var property: Int\n}} + } +} + +// Test that we don't emit fix-it to insert a requirement stub if there is already a satisfying witness. + +class C1 { + var p: P? + + func assign() { + p = self + // expected-error@-1 {{cannot assign value of type 'C1' to type 'P?'}} + // expected-note@-2 {{add missing conformance to 'P' to class 'C1'}} {{9-9=: P}} {{11-11=\n var property: Int\n}} + } + + func method() {} +} + +class C2 { + var p: P? + + func assign() { + p = self + // expected-error@-1 {{cannot assign value of type 'C2' to type 'P?'}} + // expected-note@-2 {{add missing conformance to 'P' to class 'C2'}} {{9-9=: P}} + } + + func method() {} + var property: Int = 0 +} diff --git a/test/decl/protocol/req/missing_conformance.swift b/test/decl/protocol/req/missing_conformance.swift index c838d20cd8557..871c4344c30ef 100644 --- a/test/decl/protocol/req/missing_conformance.swift +++ b/test/decl/protocol/req/missing_conformance.swift @@ -132,6 +132,7 @@ extension CountSteps1 // expected-error {{type 'CountSteps1' does not conform where T : Equatable { typealias Index = Int + // expected-error@-1 {{invalid redeclaration of synthesized implementation for protocol requirement 'Index'}} func index(_ i: Index, offsetBy d: Int) -> Index { return i + d } diff --git a/test/decl/protocol/req/unsatisfiable.swift b/test/decl/protocol/req/unsatisfiable.swift index 682300ddd43e4..390c856bb0950 100644 --- a/test/decl/protocol/req/unsatisfiable.swift +++ b/test/decl/protocol/req/unsatisfiable.swift @@ -58,3 +58,25 @@ protocol P4 { protocol P5 { associatedtype Y where Y : S // expected-error {{type 'Self.Y' constrained to non-protocol, non-class type 'S'}} } + +protocol P6 { + associatedtype T + associatedtype U + + func foo() where T == U + // expected-error@-1 {{instance method requirement 'foo()' cannot add constraint 'Self.T == Self.U' on 'Self'}} + // expected-note@-2 {{protocol requires function 'foo()' with type '() -> ()'; do you want to add a stub?}} +} + +struct S2 : P6 { + // expected-error@-1 {{type 'S2' does not conform to protocol 'P6'}} + typealias T = Int + typealias U = String + + func foo() {} + // expected-note@-1 {{candidate has non-matching type '() -> ()'}} + + // FIXME: This error is bogus and should be omitted on account of the protocol requirement itself + // being invalid. +} + diff --git a/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi1.swift b/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi1.swift index 7d72e19fe049d..2bd193260a0f2 100644 --- a/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi1.swift +++ b/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi1.swift @@ -21,3 +21,11 @@ struct SimpleStruct : Codable { let _ = SimpleStruct.CodingKeys.z // expected-error {{type 'SimpleStruct.CodingKeys' has no member 'z'}} } } + +// SR-13137 Ensure unqualified lookup installs CodingKeys regardless of the +// order of primaries. +struct A: Codable { + var property: String + static let propertyName = CodingKeys.property.stringValue +} + diff --git a/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi2.swift b/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi2.swift index e1c762b8d296a..96310709d71a4 100644 --- a/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi2.swift +++ b/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi2.swift @@ -8,3 +8,11 @@ func foo() { // struct. let _ = SimpleStruct.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}} } + +struct B { + static let propertyName = A.propertyName + + struct Nest { + static let propertyName = A.propertyName + } +} diff --git a/test/decl/var/function_builders.swift b/test/decl/var/function_builders.swift index fd93eaf42cc9b..b3b860535f1cc 100644 --- a/test/decl/var/function_builders.swift +++ b/test/decl/var/function_builders.swift @@ -7,10 +7,10 @@ var globalBuilder: Int func globalBuilderFunction() -> Int { return 0 } @_functionBuilder -struct Maker {} +struct Maker {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} @_functionBuilder -class Inventor {} +class Inventor {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} @Maker // expected-error {{function builder attribute 'Maker' can only be applied to a parameter, function, or computed property}} typealias typename = Inventor @@ -66,11 +66,11 @@ func makerParamAutoclosure(@Maker // expected-error {{function builder attribute fn: @autoclosure () -> ()) {} @_functionBuilder -struct GenericMaker {} // expected-note {{generic type 'GenericMaker' declared here}} +struct GenericMaker {} // expected-note {{generic type 'GenericMaker' declared here}} expected-error {{function builder must provide at least one static 'buildBlock' method}} struct GenericContainer { // expected-note {{generic type 'GenericContainer' declared here}} @_functionBuilder - struct Maker {} + struct Maker {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} } func makeParamUnbound(@GenericMaker // expected-error {{reference to generic type 'GenericMaker' requires arguments}} @@ -89,7 +89,7 @@ func makeParamNestedBound(@GenericContainer.Maker protocol P { } @_functionBuilder -struct ConstrainedGenericMaker {} +struct ConstrainedGenericMaker {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} struct WithinGeneric { @@ -99,3 +99,121 @@ struct WithinGeneric { func makeParamBoundInContextBad(@ConstrainedGenericMaker fn: () -> ()) {} } + +@_functionBuilder +struct ValidBuilder1 { + static func buildBlock(_ exprs: Any...) -> Int { return exprs.count } +} + +protocol BuilderFuncHelper {} + +extension BuilderFuncHelper { + static func buildBlock(_ exprs: Any...) -> Int { return exprs.count } +} + +@_functionBuilder +struct ValidBuilder2: BuilderFuncHelper {} + +class BuilderFuncBase { + static func buildBlock(_ exprs: Any...) -> Int { return exprs.count } +} + +@_functionBuilder +class ValidBuilder3: BuilderFuncBase {} + +@_functionBuilder +struct ValidBuilder4 {} +extension ValidBuilder4 { + static func buildBlock(_ exprs: Any...) -> Int { return exprs.count } +} + +@_functionBuilder +struct ValidBuilder5 { + static func buildBlock() -> Int { 0 } +} + +@_functionBuilder +struct InvalidBuilder1 {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} + +@_functionBuilder +struct InvalidBuilder2 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + func buildBlock(_ exprs: Any...) -> Int { return exprs.count } // expected-note {{did you mean to make instance method 'buildBlock' static?}} {{3-3=static }} +} + +@_functionBuilder +struct InvalidBuilder3 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + var buildBlock: (Any...) -> Int = { return $0.count } // expected-note {{potential match 'buildBlock' is not a static method}} +} + +@_functionBuilder +struct InvalidBuilder4 {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} +extension InvalidBuilder4 { + func buildBlock(_ exprs: Any...) -> Int { return exprs.count } // expected-note {{did you mean to make instance method 'buildBlock' static?}} {{3-3=static }} +} + +protocol InvalidBuilderHelper {} +extension InvalidBuilderHelper { + func buildBlock(_ exprs: Any...) -> Int { return exprs.count } // expected-note {{potential match 'buildBlock' is not a static method}} +} + +@_functionBuilder +struct InvalidBuilder5: InvalidBuilderHelper {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} + +@_functionBuilder +struct InvalidBuilder6 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + static var buildBlock: Int = 0 // expected-note {{potential match 'buildBlock' is not a static method}} +} + +struct Callable { + func callAsFunction(_ exprs: Any...) -> Int { return exprs.count } +} + +@_functionBuilder +struct InvalidBuilder7 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + static var buildBlock = Callable() // expected-note {{potential match 'buildBlock' is not a static method}} +} + +class BuilderVarBase { + static var buildBlock: (Any...) -> Int = { return $0.count } // expected-note {{potential match 'buildBlock' is not a static method}} +} + +@_functionBuilder +class InvalidBuilder8: BuilderVarBase {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} + +protocol BuilderVarHelper {} + +extension BuilderVarHelper { + static var buildBlock: (Any...) -> Int { { return $0.count } } // expected-note {{potential match 'buildBlock' is not a static method}} +} + +@_functionBuilder +struct InvalidBuilder9: BuilderVarHelper {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} + +@_functionBuilder +struct InvalidBuilder10 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + static var buildBlock: (Any...) -> Int = { return $0.count } // expected-note {{potential match 'buildBlock' is not a static method}} +} + +@_functionBuilder +enum InvalidBuilder11 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + case buildBlock(Any) // expected-note {{enum case 'buildBlock' cannot be used to satisfy the function builder requirement}} +} + +struct S { + @ValidBuilder1 var v1: Int { 1 } + @ValidBuilder2 var v2: Int { 1 } + @ValidBuilder3 var v3: Int { 1 } + @ValidBuilder4 var v4: Int { 1 } + @ValidBuilder5 func v5() -> Int {} + @InvalidBuilder1 var i1: Int { 1 } // expected-error {{type 'InvalidBuilder1' has no member 'buildBlock'}} + @InvalidBuilder2 var i2: Int { 1 } // expected-error {{instance member 'buildBlock' cannot be used on type 'InvalidBuilder2'; did you mean to use a value of this type instead?}} + @InvalidBuilder3 var i3: Int { 1 } // expected-error {{instance member 'buildBlock' cannot be used on type 'InvalidBuilder3'; did you mean to use a value of this type instead?}} + @InvalidBuilder4 var i4: Int { 1 } // expected-error {{instance member 'buildBlock' cannot be used on type 'InvalidBuilder4'; did you mean to use a value of this type instead?}} + @InvalidBuilder5 var i5: Int { 1 } // expected-error {{instance member 'buildBlock' cannot be used on type 'InvalidBuilder5'; did you mean to use a value of this type instead?}} + @InvalidBuilder6 var i6: Int { 1 } // expected-error {{cannot call value of non-function type 'Int'}} + @InvalidBuilder7 var i7: Int { 1 } + @InvalidBuilder8 var i8: Int { 1 } + @InvalidBuilder9 var i9: Int { 1 } + @InvalidBuilder10 var i10: Int { 1 } + @InvalidBuilder11 var i11: InvalidBuilder11 { 1 } +} diff --git a/test/decl/var/property_wrappers.swift b/test/decl/var/property_wrappers.swift index 736a32a261fa3..b816762cd2cc5 100644 --- a/test/decl/var/property_wrappers.swift +++ b/test/decl/var/property_wrappers.swift @@ -1732,7 +1732,7 @@ extension SR_11288_P4 where Self: AnyObject { // expected-note {{requirement spe } struct SR_11288_S4: SR_11288_P4 { - @SR_11288_Wrapper4 var answer = 42 // expected-error {{'SR_11288_S4.SR_11288_Wrapper4' (aka 'SR_11288_S0') requires that 'SR_11288_S4' be a class type}} + @SR_11288_Wrapper4 var answer = 42 // expected-error {{'Self.SR_11288_Wrapper4' (aka 'SR_11288_S0') requires that 'SR_11288_S4' be a class type}} } class SR_11288_C0: SR_11288_P4 { diff --git a/test/expr/cast/as_coerce.swift b/test/expr/cast/as_coerce.swift index 962c656322ca1..165d7b9eebafb 100644 --- a/test/expr/cast/as_coerce.swift +++ b/test/expr/cast/as_coerce.swift @@ -68,14 +68,16 @@ class C5 {} var c: AnyObject = C3() -if let castX = c as! C4? {} // expected-error {{cannot downcast from 'AnyObject' to a more optional type 'C4?'}} +// XXX TODO: Constant-folding should generate an error about 'C3' not being convertible to 'C4' +//if let castX = c as! C4? {} -// Only suggest replacing 'as' with 'as!' if it would fix the error. +// XXX TODO: Only suggest replacing 'as' with 'as!' if it would fix the error. C3() as C4 // expected-error {{'C3' is not convertible to 'C4'; did you mean to use 'as!' to force downcast?}} {{6-8=as!}} C3() as C5 // expected-error {{cannot convert value of type 'C3' to type 'C5' in coercion}} // Diagnostic shouldn't include @lvalue in type of c3. var c3 = C3() +// XXX TODO: This should not suggest `as!` c3 as C4 // expected-error {{'C3' is not convertible to 'C4'; did you mean to use 'as!' to force downcast?}} {{4-6=as!}} // Various incorrect diagnostics for explicit type conversions diff --git a/test/expr/closure/closures.swift b/test/expr/closure/closures.swift index 37c704b492714..f2b5eb5a0cf9f 100644 --- a/test/expr/closure/closures.swift +++ b/test/expr/closure/closures.swift @@ -141,6 +141,7 @@ func anonymousClosureArgsInClosureWithArgs() { var a5 = { (_: [Int], w: [Int]) in f($0.count) // expected-error {{anonymous closure arguments cannot be used inside a closure that has explicit arguments}} f($1.count) // expected-error {{anonymous closure arguments cannot be used inside a closure that has explicit arguments; did you mean 'w'?}} {{7-9=w}} + // expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'String'}} } } diff --git a/test/expr/closure/single_expr.swift b/test/expr/closure/single_expr.swift index ac3d7a7a94aad..62960ff837b6f 100644 --- a/test/expr/closure/single_expr.swift +++ b/test/expr/closure/single_expr.swift @@ -104,3 +104,20 @@ missionCritical(storage: { haltAndCatchFire() }) enum E { } func takesAnotherUninhabitedType(e: () -> E) {} takesAnotherUninhabitedType { haltAndCatchFire() } + +// Weak capture bug caught by rdar://problem/67351438 +class Y { + var toggle: Bool = false + + func doSomething(animated: Bool, completionHandler: (Int, Int) -> Void) { } +} + +class X { + private(set) var someY: Y! + + func doSomething() { + someY?.doSomething(animated: true, completionHandler: { [weak someY] _, _ in + someY?.toggle = true + }) + } +} diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift new file mode 100644 index 0000000000000..a2684adf0d310 --- /dev/null +++ b/test/expr/delayed-ident/member_chains.swift @@ -0,0 +1,373 @@ +// RUN: %target-typecheck-verify-swift -swift-version 5 + +struct ImplicitMembers: Equatable { + struct Other { + var implicit: ImplicitMembers { ImplicitMembers() } + } + + static var other = Other() + static func createOther() -> Other { + Other() + } + var anotherOther: Other { Other() } + func getAnotherOther() -> Other { + Other() + } + + static var implicit = ImplicitMembers() + static let implicitLet = ImplicitMembers() // expected-note2 {{change 'let' to 'var' to make it mutable}} + static var implicitImmutable: ImplicitMembers { ImplicitMembers() } + static func createImplicit() -> ImplicitMembers { + ImplicitMembers() + } + + static var optional: ImplicitMembers? = ImplicitMembers() + static func createOptional() -> ImplicitMembers? { + ImplicitMembers() + } + static var superOptional: ImplicitMembers??? = ImplicitMembers() + + static func createIUOArg(_: Int) -> ImplicitMembers { ImplicitMembers() } + var anotherIUO: ImplicitMembers! { ImplicitMembers() } + func getAnotherIUO() -> ImplicitMembers! { ImplicitMembers() } + + var another: ImplicitMembers { ImplicitMembers() } + var anotherMutable: ImplicitMembers { + get { ImplicitMembers() } + set {} + } + + func getAnother() -> ImplicitMembers { + ImplicitMembers() + } + + func getAnother(arg: Int) -> ImplicitMembers { + ImplicitMembers() + } + + var anotherOptional: ImplicitMembers? { ImplicitMembers() } + var anotherOptionalMutable: ImplicitMembers? { + get { ImplicitMembers() } + set {} + } + + func getAnotherOptional() -> ImplicitMembers? { + ImplicitMembers() + } + + func getAnotherOptional(arg: Int) -> ImplicitMembers? { + ImplicitMembers() + } + + static func takesClosure(_: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } + static func takesArgClosure(_: Int, _: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } + func methodTakesClosure(_: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } + func methodTakesArgClosure(_: Int, _: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } + + subscript(arg: Void) -> ImplicitMembers { + get { ImplicitMembers() } + set {} + } + subscript(optional arg: Void) -> ImplicitMembers? { + get { ImplicitMembers() } + set {} + } + subscript(immutable arg: Void) -> ImplicitMembers { ImplicitMembers() } + subscript(func arg: Void) -> (() -> ImplicitMembers) { { ImplicitMembers() } } + subscript(funcOptional arg: Void) -> (() -> ImplicitMembers?) { { ImplicitMembers() } } + subscript(optionalFunc arg: Void) -> (() -> ImplicitMembers)? { { ImplicitMembers() } } + subscript(other arg: Void) -> Other { Other() } +} + +let _: ImplicitMembers = .implicit +let _: ImplicitMembers? = .implicit +let _: ImplicitMembers? = .optional + +let _: ImplicitMembers = .implicit.another.another +let _: ImplicitMembers = .createImplicit().another.another +let _: ImplicitMembers = .init().another.another + +let _: ImplicitMembers = .implicit.getAnother().another +let _: ImplicitMembers = .createImplicit().getAnother().another +let _: ImplicitMembers = .init().getAnother().another + +let _: ImplicitMembers = .implicit.getAnother(arg: 0).another +let _: ImplicitMembers = .createImplicit().getAnother(arg: 0).another +let _: ImplicitMembers = .init().getAnother(arg: 0).another + +let _: ImplicitMembers = .implicit.another.getAnother() +let _: ImplicitMembers = .createImplicit().another.getAnother() +let _: ImplicitMembers = .init().another.getAnother() + +let _: ImplicitMembers = .implicit.another.getAnother(arg: 0) +let _: ImplicitMembers = .createImplicit().another.getAnother(arg: 0) +let _: ImplicitMembers = .init().another.getAnother(arg: 0) + +let _: ImplicitMembers = .implicit.getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .createImplicit().getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .init().getAnother().getAnother(arg: 0) + +let _: ImplicitMembers = .implicit.getAnother().getAnother(arg: 0).another +let _: ImplicitMembers = .createImplicit().getAnother().getAnother(arg: 0).another +let _: ImplicitMembers = .init().getAnother().getAnother(arg: 0).another + +let _: ImplicitMembers = .implicit.another.getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .createImplicit().another.getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .init().another.getAnother().getAnother(arg: 0) + +let _: ImplicitMembers = .implicit.another.another.another.another.another +let _: ImplicitMembers = .implicit.getAnother().getAnother().getAnother().getAnother().getAnother() +let _: ImplicitMembers = .implicit.getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0) + +let _: ImplicitMembers = .implicit.another.getAnother().getAnother(arg: 0).anotherIUO +let _: ImplicitMembers = .createImplicit().another.getAnother().getAnother(arg: 0).anotherIUO +let _: ImplicitMembers = .init().another.getAnother().getAnother(arg: 0).anotherIUO + +let _: ImplicitMembers = .implicit.another.getAnother().getAnother(arg: 0).getAnotherIUO() +let _: ImplicitMembers = .createImplicit().another.getAnother().getAnother(arg: 0).getAnotherIUO() +let _: ImplicitMembers = .init().another.getAnother().getAnother(arg: 0).getAnotherIUO() + +let _: ImplicitMembers = .createIUOArg(_:)(0) + +let _: ImplicitMembers = .optional! +let _: ImplicitMembers = .optional!.another +let _: ImplicitMembers = .createOptional()!.another +let _: ImplicitMembers = .optional!.anotherOptional! +let _: ImplicitMembers = .createOptional()!.anotherOptional! +let _: ImplicitMembers = .optional!.getAnotherOptional()! +let _: ImplicitMembers = .createOptional()!.getAnotherOptional()! +let _: ImplicitMembers = .implicit.getAnotherIUO() +let _: ImplicitMembers = .createImplicit().anotherIUO +let _: ImplicitMembers = .implicit.anotherIUO +let _: ImplicitMembers = .createImplicit().anotherIUO + +let _: ImplicitMembers = .optional // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{35-35= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{35-35=!}} +let _: ImplicitMembers = .implicit.anotherOptional // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{51-51= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{51-51=!}} +let _: ImplicitMembers = .createOptional() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{43-43= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{43-43=!}} +let _: ImplicitMembers = .implicit.getAnotherOptional() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{56-56= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{56-56=!}} +let _: ImplicitMembers = .implicit[optional: ()] // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{49-49= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{49-49=!}} +let _: ImplicitMembers = .implicit[funcOptional: ()]() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{55-55= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{55-55=!}} + +// FIXME: Improve these diagnostics (should probably offer unwrapping, as above) +let _: ImplicitMembers = .implicit.anotherOptional?.another // expected-error{{type of expression is ambiguous without more context}} +let _: ImplicitMembers = .implicit[optionalFunc: ()]?() // expected-error{{type of expression is ambiguous without more context}} + + +let _: ImplicitMembers = .other.implicit +let _: ImplicitMembers = .implicit.anotherOther.implicit +let _: ImplicitMembers = .createOther().implicit +let _: ImplicitMembers = .implicit.getAnotherOther().implicit +let _: ImplicitMembers = .implicit[other: ()].implicit + +let _: ImplicitMembers = .other // expected-error {{member 'other' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit.anotherOther // expected-error {{member 'anotherOther' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMember // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMember'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMethod() // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMethod'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMember.another // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMember'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMethod().another // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMethod'}} +let _: ImplicitMembers = .implicit.getAnotherOther() // expected-error {{member 'getAnotherOther()' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit[other: ()] // expected-error {{member 'subscript(other:)' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} + +let _: ImplicitMembers? = .implicit.another +let _: ImplicitMembers? = .implicit.anotherOptional + +let _: ImplicitMembers? = .optional +let _: ImplicitMembers? = .optional?.another +let _: ImplicitMembers? = .optional?.anotherOptional +let _: ImplicitMembers? = .optional?.getAnother() +let _: ImplicitMembers? = .optional?.getAnotherOptional() +let _: ImplicitMembers? = .optional?.anotherOptional?.another +let _: ImplicitMembers? = .optional?.getAnotherOptional()?.another +let _: ImplicitMembers? = .createOptional() +let _: ImplicitMembers? = .createOptional()?.another +let _: ImplicitMembers? = .createOptional()?.anotherOptional +let _: ImplicitMembers? = .createOptional()?.getAnother() +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional() +let _: ImplicitMembers? = .createOptional()?.anotherOptional?.another +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional()?.another +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional()?.anotherIUO +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional()?.getAnotherIUO() +// FIXME: This should be allowed +// let _: ImplicitMembers? = .superOptional???.another + +let _: ImplicitMembers = .takesClosure { _ in } +let _: ImplicitMembers = .takesArgClosure(0) { _ in } +let _: ImplicitMembers = .implicit.methodTakesClosure { _ in } +let _: ImplicitMembers = .implicit.methodTakesArgClosure(0) { _ in } +let _: ImplicitMembers? = .optional?.methodTakesClosure { _ in } +let _: ImplicitMembers? = .optional?.methodTakesArgClosure(0) { _ in } + +let _: ImplicitMembers = .implicit[()] +let _: ImplicitMembers = .implicit[optional: ()]! +let _: ImplicitMembers? = .implicit[optional: ()] +let _: ImplicitMembers = .implicit[func: ()]() +let _: ImplicitMembers = .implicit[funcOptional: ()]()! +let _: ImplicitMembers? = .implicit[funcOptional: ()]() +let _: ImplicitMembers = .implicit[optionalFunc: ()]!() +let _: ImplicitMembers? = .implicit[optionalFunc: ()]?() +let _: ImplicitMembers = .implicit.another[()] +let _: ImplicitMembers = .implicit.another[optional: ()]! +let _: ImplicitMembers? = .implicit.another[optional: ()] +let _: ImplicitMembers = .implicit.another[func: ()]() +let _: ImplicitMembers = .implicit.another[funcOptional: ()]()! +let _: ImplicitMembers? = .implicit.another[funcOptional: ()]() +let _: ImplicitMembers = .implicit.another[optionalFunc: ()]!() +let _: ImplicitMembers? = .implicit.another[optionalFunc: ()]?() +let _: ImplicitMembers = .implicit[()].another +let _: ImplicitMembers = .implicit[optional: ()]!.another +let _: ImplicitMembers? = .implicit[optional: ()]?.another +let _: ImplicitMembers = .implicit[func: ()]().another +let _: ImplicitMembers = .implicit[funcOptional: ()]()!.another +let _: ImplicitMembers? = .implicit[funcOptional: ()]()?.another +let _: ImplicitMembers = .implicit[optionalFunc: ()]!().another +let _: ImplicitMembers? = .implicit[optionalFunc: ()]?().another + +func implicit(_ i: inout ImplicitMembers) { + if i == .implicit {} + if i == .implicit.another {} + if i == .implicit.getAnother() {} + if i == .optional?.another {} + if i == .optional!.another {} + if i == .createOptional()?.another {} +} + +func testLValues() { + let local = ImplicitMembers(); + + .implicit = local; + .implicit.anotherMutable = local; + .implicit.anotherOptionalMutable? = local; + .implicit.anotherOptionalMutable! = local; + .implicit[()] = local; + .implicit[()].anotherMutable = local; + .optional?[optional: ()]?.anotherOptionalMutable! = local; + + .implicitLet = local; // expected-error {{cannot assign to property: 'implicitLet' is a 'let' constant}} + .implicitImmutable = local; // expected-error {{cannot assign to property: 'implicitImmutable' is a get-only property}} + .createImplicit() = local; // expected-error {{expression is not assignable: function call returns immutable value}} + .implicit.another = local; // expected-error {{cannot assign to property: 'another' is a get-only property}} + .implicit[immutable: ()] = local; // expected-error {{cannot assign through subscript: subscript is get-only}} + .implicit.getAnother() = local; // expected-error {{expression is not assignable: function call returns immutable value}} + + .implicitLet.anotherMutable = local; // expected-error {{cannot assign to property: 'implicitLet' is a 'let' constant}} + .implicitImmutable.anotherMutable = local; // expected-error {{cannot assign to property: 'implicitImmutable' is a get-only property}} + .createImplicit().anotherMutable = local; // expected-error {{cannot assign to property: function call returns immutable value}} + .implicit.another.anotherMutable = local; // expected-error {{cannot assign to property: 'another' is a get-only property}} + .implicit[immutable: ()].anotherMutable = local; // expected-error {{cannot assign to property: subscript is get-only}} + .implicit.getAnother().anotherMutable = local; // expected-error {{cannot assign to property: function call returns immutable value}} + + + // FIXME: These should probably be allowed + //.implicit.anotherOptionalMutable = local; + //.optional = local; +} + +struct ImplicitGeneric { // expected-note4 {{arguments to generic parameter 'T' ('Int' and 'String') are expected to be equal}} + static var implicit: ImplicitGeneric { ImplicitGeneric() } + var another: ImplicitGeneric { ImplicitGeneric() } + func getAnother() -> ImplicitGeneric { + ImplicitGeneric() + } +} + +extension ImplicitGeneric where T == Int { + static var implicitInt: ImplicitGeneric { ImplicitGeneric() } + static var implicitString: ImplicitGeneric { ImplicitGeneric() } + var anotherInt: ImplicitGeneric { ImplicitGeneric() } + var anotherIntString: ImplicitGeneric { ImplicitGeneric() } + func getAnotherInt() -> ImplicitGeneric { + ImplicitGeneric() + } +} + +extension ImplicitGeneric where T == String { + static var implicitString: ImplicitGeneric { ImplicitGeneric() } + var anotherString: ImplicitGeneric { ImplicitGeneric() } + var anotherStringInt: ImplicitGeneric { ImplicitGeneric() } + func getAnotherString() -> ImplicitGeneric { + ImplicitGeneric() + } + func getAnotherStringInt() -> ImplicitGeneric { + ImplicitGeneric() + } +} + +func implicit(_ arg: ImplicitGeneric) {} + +implicit(.implicitInt) +implicit(.implicit.anotherInt) +implicit(.implicit.anotherInt.another) +implicit(.implicit.another.anotherInt) +implicit(.implicit.getAnotherInt()) +implicit(.implicit.another.getAnotherInt()) +implicit(.implicit.getAnother().anotherInt) +implicit(.implicit.getAnotherInt()) +implicit(.implicit.getAnother().getAnotherInt()) +implicit(.implicitString.anotherStringInt) +// Member types along the chain can have different generic arguments +implicit(.implicit.anotherIntString.anotherStringInt) + +implicit(.implicit.anotherString.anotherStringInt) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} +implicit(.implicit.getAnotherString().anotherStringInt) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} +implicit(.implicit.anotherString.getAnotherStringInt()) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} +implicit(.implicit.getAnotherString().getAnotherStringInt()) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} + +// Implicit member syntax can be used to apply curried instance methods: +struct Curried { + func method() -> Curried { Curried() } + func method(with arg: Int) -> Curried { Curried() } + func method(with arg1: Int, and arg2: String) -> Curried { Curried() } + func takesClosure(_: (Int) -> Void) -> Curried { Curried() } + func takesArgClosure(_: Int, _: (Int) -> Void) -> Curried { Curried() } + static func curried(_ _self: Curried) -> () -> Curried{ return { _self } } + static func curriedWithArgs(_ _self: Curried) -> (Int, String) -> Curried { return { _, _ in _self } } +} + +let _: Curried = .method(Curried())() +let _: Curried = .method(Curried())(with: 0) +let _: Curried = .method(Curried())(with: 0, and: "") +let _: Curried = .takesClosure(Curried())() { _ in } +let _: Curried = .takesArgClosure(Curried())(0) { _ in } +let _: Curried = .curried(Curried())() +let _: Curried = .curriedWithArgs(Curried())(0, "") + + +struct CurriedGeneric { + func create(_: U.Type) -> CurriedGeneric { return CurriedGeneric() } +} + +extension CurriedGeneric where T == Int { + func createInt() -> Self { + return self + } +} + +let _: CurriedGeneric = .createInt(CurriedGeneric())() +let _: CurriedGeneric = .create(CurriedGeneric())(Int.self) + +// rdar://problem/68094328 - failed to compile unresolved member with implicit optional promotion +func rdar68094328() { + struct S { + init(string: String) {} + + var value: S { + get { S(string: "") } + } + + func baz(str: String) -> S { + S(string: str) + } + } + + class C { + func bar(_: S) {} + } + + func foo(_: (C) -> (T) -> Void, _: T?) {} + + func test(str: String) { + foo(C.bar, .init(string: str)) // Ok + foo(C.bar, .init(string: str).value) // Ok + foo(C.bar, .init(string: str).baz(str: "")) // Ok + } +} diff --git a/test/expr/delayed-ident/nested_type.swift b/test/expr/delayed-ident/nested_type.swift index da8a3fece6538..520d08c90dea9 100644 --- a/test/expr/delayed-ident/nested_type.swift +++ b/test/expr/delayed-ident/nested_type.swift @@ -4,12 +4,21 @@ class Base { class Derived : Base { init(x: Int) {} + class Sub: Derived { + init(y: Int) {} + } + typealias Ident = Derived + typealias Ident2 = Base } typealias Ident = Base } let _: Base = .Derived(x: 12) let _: Base = .Ident() +let _: Base = .Derived.Sub(y: 1) +let _: Base = .Derived.init(x: 3) +let _: Base = .Derived.Ident(x: 3) +let _: Base = .Derived.Ident2() // Typealias in protocol. protocol P { @@ -19,9 +28,19 @@ extension P { typealias Impl2 = ConcreteP } struct ConcreteP : P { + struct NestedP: P {} + typealias Same = ConcreteP } let _: P = .Impl1() let _: P = .Impl2() let _: ConcreteP = .Impl1() let _: ConcreteP = .Impl2() +let _: P = .Impl1.NestedP() +let _: P = .Impl2.NestedP() +let _: ConcreteP = .Impl1.Same() +let _: ConcreteP = .Impl2.Same() +let _: P = .Impl1.init() +let _: P = .Impl2.init() +let _: ConcreteP = .Impl1.init() +let _: ConcreteP = .Impl2.init() diff --git a/test/expr/delayed-ident/static_var.swift b/test/expr/delayed-ident/static_var.swift index cfe701754f791..3a01e7ff4137c 100644 --- a/test/expr/delayed-ident/static_var.swift +++ b/test/expr/delayed-ident/static_var.swift @@ -50,8 +50,7 @@ var _: HasClosure = .factoryOpt(3) // expected-error@-1 {{value of optional type '((Int) -> HasClosure)?' must be unwrapped to a value of type '(Int) -> HasClosure'}} // expected-note@-2 {{coalesce}} // expected-note@-3 {{force-unwrap}} -// FIXME: we should accept this -var _: HasClosure = .factoryOpt!(4) // expected-error {{cannot infer contextual base in reference to member 'factoryOpt'}} +var _: HasClosure = .factoryOpt!(4) infix operator =%: ComparisonPrecedence diff --git a/test/expr/postfix/call/forward_trailing_closure_unresolved_member.swift b/test/expr/postfix/call/forward_trailing_closure_unresolved_member.swift new file mode 100644 index 0000000000000..f65115051ddd6 --- /dev/null +++ b/test/expr/postfix/call/forward_trailing_closure_unresolved_member.swift @@ -0,0 +1,19 @@ +// RUN: %target-swift-emit-silgen %s | %FileCheck %s + +// rdar://problem/67781123 - crash in SILGen + +struct Foo { + var title: String + var handler1: ((Int, String) -> Void)? + var handler2: (() -> Void)? +} + +func take(foo: Foo) { } + +// CHECK-LABEL: sil hidden [ossa] @$s42forward_trailing_closure_unresolved_member4testyy +func test() { + // CHECK: function_ref @$s42forward_trailing_closure_unresolved_member4testyyFyycfU_ : $@convention(thin) () -> () + take(foo: .init(title: "") { + print("handler2 is called") + }) +} diff --git a/test/expr/postfix/dot/optional_context_member.swift b/test/expr/postfix/dot/optional_context_member.swift index b761c21657ab6..c3279781e40b0 100644 --- a/test/expr/postfix/dot/optional_context_member.swift +++ b/test/expr/postfix/dot/optional_context_member.swift @@ -27,9 +27,8 @@ func nonOptContext() -> Foo { // expected-error@-1 {{value of optional type 'Foo?' must be unwrapped to a value of type 'Foo'}} // expected-note@-2 {{coalesce}} // expected-note@-3 {{force-unwrap}} - // TODO - //case (): - // return .someOptFunc()! + case (): // expected-warning {{case is already handled by previous patterns; consider removing it}} + return .someOptFunc()! } } diff --git a/test/expr/unary/async_await.swift b/test/expr/unary/async_await.swift index 2ab75eae60eb4..3dc31a35ab1c9 100644 --- a/test/expr/unary/async_await.swift +++ b/test/expr/unary/async_await.swift @@ -1,10 +1,135 @@ -// RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-concurrency +// RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-concurrency -verify-syntax-tree func test1(asyncfp : () async -> Int, fp : () -> Int) async { - _ = __await asyncfp() - _ = __await asyncfp() + asyncfp() - _ = __await asyncfp() + fp() - _ = __await fp() + 42 // expected-warning {{no calls to 'async' functions occur within 'await' expression}} + _ = await asyncfp() + _ = await asyncfp() + asyncfp() + _ = await asyncfp() + fp() + _ = await fp() + 42 // expected-warning {{no calls to 'async' functions occur within 'await' expression}} _ = asyncfp() // expected-error {{call is 'async' but is not marked with 'await'}} } +func getInt() async -> Int { return 5 } + +// Locations where "await" is prohibited. +func test2( + defaulted: Int = await getInt() // expected-error{{'async' call cannot occur in a default argument}} +) async { + defer { + _ = await getInt() // expected-error{{'async' call cannot occur in a defer body}} + } + print("foo") +} + +func test3() { // expected-note{{add 'async' to function 'test3()' to make it asynchronous}} + // expected-note@-1{{add '@asyncHandler' to function 'test3()' to create an implicit asynchronous context}}{{1-1=@asyncHandler }} + _ = await getInt() // expected-error{{'async' in a function that does not support concurrency}} +} + +enum SomeEnum: Int { +case foo = await 5 // expected-error{{raw value for enum case must be a literal}} +} + +struct SomeStruct { + var x = await getInt() // expected-error{{'async' call cannot occur in a property initializer}} + static var y = await getInt() // expected-error{{'async' call cannot occur in a global variable initializer}} +} + +func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) async { } +func acceptAutoclosureAsync(_: @autoclosure () async -> Int) async { } + +func acceptAutoclosureNonAsyncBad(_: @autoclosure () async -> Int) -> Int { 0 } +// expected-error@-1{{'async' autoclosure parameter in a non-'async' function}} +// expected-note@-2{{add 'async' to function 'acceptAutoclosureNonAsyncBad' to make it asynchronous}} + +struct HasAsyncBad { + init(_: @autoclosure () async -> Int) { } + // expected-error@-1{{'async' autoclosure parameter in a non-'async' function}} +} + +func testAutoclosure() async { + await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument that is not marked with 'await'}} + await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} + + await acceptAutoclosureAsync(await getInt()) + await acceptAutoclosureNonAsync(await getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} + + await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument that is not marked with 'await'}} + await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} +} + +// Test inference of 'async' from the body of a closure. +func testClosure() { + let closure = { + await getInt() + } + + let _: () -> Int = closure // expected-error{{cannot convert value of type '() async -> Int' to specified type '() -> Int'}} + + let closure2 = { () async -> Int in + print("here") + return await getInt() + } + + let _: () -> Int = closure2 // expected-error{{cannot convert value of type '() async -> Int' to specified type '() -> Int'}} +} + +// Nesting async and await together +func throwingAndAsync() async throws -> Int { return 0 } + +enum HomeworkError : Error { + case dogAteIt +} + +func testThrowingAndAsync() async throws { + _ = await try throwingAndAsync() + _ = try await throwingAndAsync() + _ = await (try throwingAndAsync()) + _ = try (await throwingAndAsync()) + + // Errors + _ = await throwingAndAsync() // expected-error{{call can throw but is not marked with 'try'}} + // expected-note@-1{{did you mean to use 'try'?}} + // expected-note@-2{{did you mean to handle error as optional value?}} + // expected-note@-3{{did you mean to disable error propagation?}} + _ = try throwingAndAsync() // expected-error{{call is 'async' but is not marked with 'await'}} +} + +func testExhaustiveDoCatch() async { + do { + _ = await try throwingAndAsync() + } catch { + } + + do { + _ = await try throwingAndAsync() + // expected-error@-1{{errors thrown from here are not handled because the enclosing catch is not exhaustive}} + } catch let e as HomeworkError { + } + + // Ensure that we infer 'async' through an exhaustive do-catch. + let fn = { + do { + _ = await try throwingAndAsync() + } catch { + } + } + + let _: Int = fn // expected-error{{cannot convert value of type '() async -> ()'}} + + // Ensure that we infer 'async' through a non-exhaustive do-catch. + let fn2 = { + do { + _ = await try throwingAndAsync() + } catch let e as HomeworkError { + } + } + + let _: Int = fn2 // expected-error{{cannot convert value of type '() async throws -> ()'}} +} + +// String interpolation +func testStringInterpolation() async throws { + _ = "Eventually produces \(getInt())" // expected-error{{call is 'async' but is not marked with 'await'}} + _ = "Eventually produces \(await getInt())" + _ = await "Eventually produces \(getInt())" +} diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index d6fd26dade0f4..08282b4cd1bf2 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -36,7 +36,7 @@ struct A: Hashable { func hash(into hasher: inout Hasher) { fatalError() } } struct B {} -struct C { // expected-note 3 {{'T' declared as parameter to type 'C'}} +struct C { // expected-note 4 {{'T' declared as parameter to type 'C'}} var value: T subscript() -> T { get { return value } } subscript(sub: Sub) -> T { get { return value } set { } } @@ -224,15 +224,17 @@ func testKeyPathInGenericContext(hashable: H, anything: X) { } func testDisembodiedStringInterpolation(x: Int) { - \(x) // expected-error{{string interpolation}} expected-error{{}} - \(x, radix: 16) // expected-error{{string interpolation}} expected-error{{}} + \(x) // expected-error{{string interpolation can only appear inside a string literal}} + \(x, radix: 16) // expected-error{{string interpolation can only appear inside a string literal}} } func testNoComponents() { let _: KeyPath = \A // expected-error{{must have at least one component}} - let _: KeyPath = \C // expected-error{{must have at least one component}} expected-error{{}} + let _: KeyPath = \C // expected-error{{must have at least one component}} // expected-error@-1 {{generic parameter 'T' could not be inferred}} - // expected-error@-2 {{cannot convert value of type 'KeyPath' to specified type 'KeyPath, A>'}} + let _: KeyPath = \A // expected-error{{must have at least one component}} + // expected-error@-1 {{generic parameter 'T' could not be inferred}} + _ = \A // expected-error {{key path must have at least one component}} } struct TupleStruct { @@ -322,8 +324,8 @@ func testKeyPathSubscript(readonly: Z, writable: inout Z, var anySink2 = writable[keyPath: pkp] expect(&anySink2, toHaveType: Exactly.self) - readonly[keyPath: pkp] = anySink1 // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}} - writable[keyPath: pkp] = anySink2 // expected-error{{cannot assign through subscript: 'writable' is immutable}} + readonly[keyPath: pkp] = anySink1 // expected-error{{cannot assign through subscript: 'pkp' is a read-only key path}} + writable[keyPath: pkp] = anySink2 // expected-error{{cannot assign through subscript: 'pkp' is a read-only key path}} let akp: AnyKeyPath = pkp @@ -441,12 +443,12 @@ func testKeyPathSubscriptLValue(base: Z, kp: inout KeyPath) { } func testKeyPathSubscriptExistentialBase(concreteBase: inout B, - existentialBase: inout P, - kp: KeyPath, - wkp: WritableKeyPath, - rkp: ReferenceWritableKeyPath, - pkp: PartialKeyPath

, - s: String) { + existentialBase: inout P, + kp: KeyPath, + wkp: WritableKeyPath, + rkp: ReferenceWritableKeyPath, + pkp: PartialKeyPath

, + s: String) { _ = concreteBase[keyPath: kp] _ = concreteBase[keyPath: wkp] _ = concreteBase[keyPath: rkp] @@ -455,9 +457,7 @@ func testKeyPathSubscriptExistentialBase(concreteBase: inout B, concreteBase[keyPath: kp] = s // expected-error {{cannot assign through subscript: 'kp' is a read-only key path}} concreteBase[keyPath: wkp] = s // expected-error {{key path with root type 'P' cannot be applied to a base of type 'B'}} concreteBase[keyPath: rkp] = s - // TODO(diagnostics): Improve this diagnostic message because concreteBase is mutable, the problem is related to assign - // through PartialKeyPath. - concreteBase[keyPath: pkp] = s // expected-error {{cannot assign through subscript: 'concreteBase' is immutable}} + concreteBase[keyPath: pkp] = s // expected-error {{cannot assign through subscript: 'pkp' is a read-only key path}} _ = existentialBase[keyPath: kp] _ = existentialBase[keyPath: wkp] @@ -467,9 +467,7 @@ func testKeyPathSubscriptExistentialBase(concreteBase: inout B, existentialBase[keyPath: kp] = s // expected-error {{cannot assign through subscript: 'kp' is a read-only key path}} existentialBase[keyPath: wkp] = s existentialBase[keyPath: rkp] = s - // TODO(diagnostics): Improve this diagnostic message because existentialBase is mutable, the problem is related to assign - // through PartialKeyPath. - existentialBase[keyPath: pkp] = s // expected-error {{cannot assign through subscript: 'existentialBase' is immutable}} + existentialBase[keyPath: pkp] = s // expected-error {{cannot assign through subscript: 'pkp' is a read-only key path}} } struct AA { @@ -1008,9 +1006,17 @@ func testMemberAccessOnOptionalKeyPathComponent() { // expected-error@-1 {{value of optional type '(Int, Int)?' must be unwrapped to refer to member '0' of wrapped base type '(Int, Int)'}} // expected-note@-2 {{use unwrapped type '(Int, Int)' as key path root}}{{4-15=(Int, Int)}} - // TODO(diagnostics) Improve diagnostics refering to key path root not able to be infered as an optional type. - SR5688_KP(\.count) - // expected-error@-1 {{value of optional type 'String?' must be unwrapped to refer to member 'count' of wrapped base type 'String'}} + SR5688_KP(\.count) // expected-error {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'count' of unwrapped type 'String'}} + // expected-note@-1 {{chain the optional using '?.' to access unwrapped type member 'count'}} {{15-15=?.}} + // expected-note@-2 {{unwrap the optional using '!.' to access unwrapped type member 'count'}} {{15-15=!.}} + let _ : KeyPath = \.count // expected-error {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'count' of unwrapped type 'String'}} + // expected-note@-1 {{chain the optional using '?.' to access unwrapped type member 'count'}} {{37-37=?.}} + // expected-note@-2 {{unwrap the optional using '!.' to access unwrapped type member 'count'}} {{37-37=!.}} + + let _ : KeyPath = \.utf8.count + // expected-error@-1 {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'utf8' of unwrapped type 'String'}} + // expected-note@-2 {{chain the optional using '?.' to access unwrapped type member 'utf8'}} {{37-37=?.}} + // expected-note@-3 {{unwrap the optional using '!.' to access unwrapped type member 'utf8'}} {{37-37=!.}} } func testSyntaxErrors() { diff --git a/test/lit.cfg b/test/lit.cfg index f7f82f9c21c33..39b7b7cca9dfa 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -283,6 +283,7 @@ config.complete_test = inferSwiftBinary('complete-test') config.swift_api_digester = inferSwiftBinary('swift-api-digester') config.swift_refactor = inferSwiftBinary('swift-refactor') config.swift_demangle_yamldump = inferSwiftBinary('swift-demangle-yamldump') +config.swift_demangle = inferSwiftBinary('swift-demangle') config.benchmark_o = inferSwiftBinary('Benchmark_O') config.benchmark_driver = inferSwiftBinary('Benchmark_Driver') config.wasmer = inferSwiftBinary('wasmer') @@ -426,10 +427,6 @@ config.substitutions.append( ('%swift-syntax-test', config.swift_syntax_test) ) if 'syntax_parser_lib' in config.available_features: config.substitutions.append( ('%swift-syntax-parser-test', config.swift_syntax_parser_test) ) # For testing on CI -if '-enable-astscope-lookup' in config.swift_test_options: - config.available_features.add("enable-astscope-lookup") -if '-disable-astscope-lookup' in config.swift_test_options: - config.available_features.add("disable-astscope-lookup") if '-disable-parser-lookup' in config.swift_test_options: config.available_features.add("disable-parser-lookup") config.substitutions.append( ('%swift-indent', config.swift_indent) ) @@ -440,6 +437,7 @@ config.substitutions.append( ('%llvm-readelf', config.llvm_readelf) ) config.substitutions.append( ('%llvm-dis', config.llvm_dis) ) config.substitutions.append( ('%llvm-nm', config.llvm_nm) ) config.substitutions.append( ('%swift-demangle-yamldump', config.swift_demangle_yamldump) ) +config.substitutions.append( ('%swift-demangle', config.swift_demangle) ) config.substitutions.append( ('%Benchmark_O', config.benchmark_o) ) config.substitutions.append( ('%Benchmark_Driver', config.benchmark_driver) ) config.substitutions.append( ('%llvm-strings', config.llvm_strings) ) @@ -1374,8 +1372,6 @@ elif run_os == 'linux-androideabi' or run_os == 'linux-android': # The Swift interpreter is not available when targeting Android. config.available_features.discard('swift_interpreter') elif run_os == 'wasi': - tools_directory = pipes.quote(make_path(config.wasi_sdk_path, "bin")) - lit_config.note("Testing WebAssembly/WASI " + config.variant_triple) config.target_object_format = "wasm" @@ -1411,7 +1407,6 @@ elif run_os == 'wasi': '-target', config.variant_triple, '-Xcc', '--sysroot=%s' % config.variant_sdk, '-Xclang-linker', '--sysroot=%s' % config.variant_sdk, - '-tools-directory', tools_directory, '-toolchain-stdlib-rpath', resource_dir_opt, mcp_opt, config.swift_test_options, config.swift_driver_test_options, swift_execution_tests_extra_flags]) @@ -1424,7 +1419,6 @@ elif run_os == 'wasi': config.swift_frontend, '-target', config.variant_triple, '-Xcc', '--sysroot=%s' % config.variant_sdk, - '-tools-directory', tools_directory, resource_dir_opt, mcp_opt, config.swift_test_options, config.swift_frontend_test_options]) subst_target_swift_frontend_mock_sdk = config.target_swift_frontend @@ -2062,4 +2056,3 @@ else: num_extra_inhabitants_64bit = 4096 add_num_extra_inhabitants = "-D#num_extra_inhabitants_64bit={} ".format(num_extra_inhabitants_64bit) config.substitutions.append(('%add_num_extra_inhabitants', add_num_extra_inhabitants)) - diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index 7166762c20712..f1a01a1dff791 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -90,8 +90,8 @@ if "@SWIFT_AST_VERIFIER@" == "TRUE": if "@SWIFT_OPTIMIZED@" == "TRUE": config.available_features.add("optimized_stdlib") -if "@SWIFT_STDLIB_USE_NONATOMIC_RC@" == "TRUE": - config.available_features.add("nonatomic_rc") +if "@SWIFT_STDLIB_SINGLE_THREADED_RUNTIME@" == "TRUE": + config.available_features.add("single_threaded_runtime") if "@SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS@" == "TRUE": config.available_features.add('runtime_function_counters') diff --git a/test/multifile/Inputs/rdar67842221-other.swift b/test/multifile/Inputs/rdar67842221-other.swift new file mode 100644 index 0000000000000..bda0e894cfc54 --- /dev/null +++ b/test/multifile/Inputs/rdar67842221-other.swift @@ -0,0 +1,4 @@ +let closureValue = { () -> () in + class DummyClass {} + return () +}() diff --git a/test/multifile/rdar67842221.swift b/test/multifile/rdar67842221.swift new file mode 100644 index 0000000000000..64bacf0e58901 --- /dev/null +++ b/test/multifile/rdar67842221.swift @@ -0,0 +1,17 @@ +// Test both orderings, and single-file vs WMO + +// RUN: %target-swift-frontend -emit-ir -primary-file %s %S/Inputs/rdar67842221-other.swift -module-name main +// RUN: %target-swift-frontend -emit-ir %s -primary-file %S/Inputs/rdar67842221-other.swift -module-name main + +// RUN: %target-swift-frontend -emit-ir -primary-file %S/Inputs/rdar67842221-other.swift %s -module-name main +// RUN: %target-swift-frontend -emit-ir %S/Inputs/rdar67842221-other.swift -primary-file %s -module-name main + +// RUN: %target-swift-frontend -emit-ir %S/Inputs/rdar67842221-other.swift %s -module-name main +// RUN: %target-swift-frontend -emit-ir %S/Inputs/rdar67842221-other.swift %s -module-name main + +// The closure defines a local class; we want to make sure there is no cycle +// between computing the semantic members of the local class (which requires +// sorting) and computing the type of the closure value +public func force() { + _ = closureValue +} diff --git a/test/stdlib/Casts.swift b/test/stdlib/Casts.swift deleted file mode 100644 index 5e81f6643b154..0000000000000 --- a/test/stdlib/Casts.swift +++ /dev/null @@ -1,236 +0,0 @@ -// Casts.swift - Tests for conversion between types. -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -// ----------------------------------------------------------------------------- -/// -/// Contains tests for conversions between types which shouldn't trap. -/// -// ----------------------------------------------------------------------------- -// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-concurrency) -// REQUIRES: executable_test -// UNSUPPORTED: use_os_stdlib - -import StdlibUnittest -#if _runtime(_ObjC) -import Foundation -#endif - -private func blackhole(_ t: T) {} - -let CastsTests = TestSuite("Casts") - -// Test for SR-426: missing release for some types after failed conversion -CastsTests.test("No leak for failed tuple casts") { - let t: Any = (1, LifetimeTracked(0)) - expectFalse(t is Any.Type) -} - -protocol P {} -class ErrClass : Error { } - -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 _ in 0..<10 { - if case let a as P = t { - _ = a - } - } - } - - let err: Error = ErrClass() - bar(err) -} - -extension Int : P {} - -// Test for SR-7664: Inconsistent optional casting behaviour with generics -// Runtime failed to unwrap multiple levels of Optional when casting. -CastsTests.test("Multi-level optionals can be casted") { - func testSuccess(_ x: From, from: From.Type, to: To.Type) { - expectNotNil(x as? To) - } - func testFailure(_ x: From, from: From.Type, to: To.Type) { - expectNil(x as? To) - } - testSuccess(42, from: Int?.self, to: Int.self) - testSuccess(42, from: Int??.self, to: Int.self) - testSuccess(42, from: Int???.self, to: Int.self) - testSuccess(42, from: Int???.self, to: Int?.self) - testSuccess(42, from: Int???.self, to: Int??.self) - testSuccess(42, from: Int???.self, to: Int???.self) - testFailure(42, from: Int?.self, to: String.self) - testFailure(42, from: Int??.self, to: String.self) - testFailure(42, from: Int???.self, to: String.self) -} - -// Test for SR-9837: Optional.none not casting to Optional.none in generic context -CastsTests.test("Optional.none can be casted to Optional.none in generic context") { - func test(_ type: T.Type) -> T? { - return Any?.none as? T - } - - expectEqual(type(of: test(Bool.self)), Bool?.self) - expectEqual(type(of: test(Bool?.self)), Bool??.self) -} - -// Test for SR-3871: Cannot cast from ObjC existential without going through AnyObject -#if _runtime(_ObjC) -protocol P2 {} -CastsTests.test("Cast from ObjC existential to Protocol (SR-3871)") { - if #available(macOS 10.16, iOS 14.0, watchOS 7.0, tvOS 14.0, *) { - struct S: P2 {} - - class ObjCWrapper { - @objc dynamic let any: Any = S() - init() {} - } - let a = ObjCWrapper().any - expectTrue(a is P2) - // In SR-3871, the following cast failed (everything else here succeeded) - expectNotNil(a as? P2) - expectNotNil(a as? S) - let b = a as AnyObject - expectTrue(a is P2) - expectNotNil(b as? P2) - expectNotNil(b as? S) - } -} -#endif - -protocol P3 {} -CastsTests.test("Cast from Swift existential to Protocol") { - struct S: P3 {} - class SwiftWrapper { - let any: Any = S() - init() {} - } - let a = SwiftWrapper().any - expectTrue(a is P3) - expectNotNil(a as? P3) - expectNotNil(a as? S) - let b = a as AnyObject - expectTrue(b is P3) - expectNotNil(b as? P3) - expectNotNil(b as? S) -} - - -#if _runtime(_ObjC) -extension CFBitVector : P { - static func makeImmutable(from values: Array) -> CFBitVector { - return CFBitVectorCreate(/*allocator:*/ nil, values, values.count * 8) - } -} - -extension CFMutableBitVector { - static func makeMutable(from values: Array) -> CFMutableBitVector { - return CFBitVectorCreateMutableCopy( - /*allocator:*/ nil, - /*capacity:*/ 0, - CFBitVector.makeImmutable(from: values)) - } -} - -func isP(_ t: T) -> Bool { - return t is P -} - -CastsTests.test("Dynamic casts of CF types to protocol existentials") - .skip(.custom( - { !_isDebugAssertConfiguration() }, - reason: "This test behaves unpredictably in optimized mode.")) - .code { - expectTrue(isP(10 as Int)) - - // FIXME: SR-2289: dynamic casting of CF types to protocol existentials - // should work, but there is a bug in the runtime that prevents them from - // working. - expectFailure { - expectTrue(isP(CFBitVector.makeImmutable(from: [10, 20]))) - } - expectFailure { - expectTrue(isP(CFMutableBitVector.makeMutable(from: [10, 20]))) - } -} -#endif - -CastsTests.test("Any.Protocol") { - class C {} - struct S {} - func isAnyProtocol(_ type: T.Type) -> Bool { - let result = T.self is Any.Protocol - if result { - // `as!` should succeed if `is` does - blackhole(T.self as! Any.Protocol) - } - return result - } - func isAnyType(_ type: T.Type) -> Bool { - return T.self is Any.Type - } - func isType(_ type: T.Type, to: U.Type) -> Bool { - return T.self is U.Type - } - - expectTrue(Int.self is Any.Type) - expectNotNil(Int.self as? Any.Type) - expectTrue(isAnyType(Int.self)) - expectFalse(Int.self is Any.Protocol) - expectNil(Int.self as? Any.Protocol) - expectFalse(isAnyProtocol(Int.self)) - expectFalse(isType(Int.self, to: Any.self)) - - expectTrue(C.self is Any.Type) - expectNotNil(C.self as? Any.Type) - expectTrue(isAnyType(C.self)) - expectFalse(C.self is Any.Protocol) - expectNil(C.self as? Any.Protocol) - expectFalse(isAnyProtocol(C.self)) - expectFalse(isType(C.self, to: Any.self)) - - expectTrue(S.self is Any.Type) - expectNotNil(S.self as? Any.Type) - expectTrue(isAnyType(S.self)) - expectFalse(S.self is Any.Protocol) - expectNil(S.self as? Any.Protocol) - expectFalse(isAnyProtocol(S.self)) - expectFalse(isType(S.self, to: Any.self)) - - expectTrue(Any.self is Any.Type) - expectNotNil(Any.self as? Any.Type) - expectTrue(isAnyType(Any.self)) - expectTrue(Any.self is Any.Protocol) - expectNotNil(Any.self as? Any.Protocol) - expectTrue(isAnyProtocol(Any.self)) - expectTrue(isType(Any.self, to: Any.self)) - - expectTrue(Any?.self is Any.Type) - expectNotNil(Any?.self as? Any.Type) - expectTrue(isAnyType(Any?.self)) - expectFalse(Any?.self is Any.Protocol) - expectNil(Any?.self as? Any.Protocol) - expectFalse(isAnyProtocol(Any?.self)) - expectFalse(isType(Any?.self, to: Any.self)) -} - -CastsTests.test("Async function types") { - let asyncFnType: Any.Type = (() async -> Void).self - let fnType: Any.Type = (() -> Void).self - - expectTrue(fnType is (() -> Void).Type) - expectTrue(asyncFnType is (() async -> Void).Type) - expectFalse(fnType is (() async -> Void).Type) - expectFalse(asyncFnType is (() -> Void).Type) -} - -runAllTests() diff --git a/test/stdlib/Error.swift b/test/stdlib/Error.swift index e21e525ad02b0..7c95c04c72481 100644 --- a/test/stdlib/Error.swift +++ b/test/stdlib/Error.swift @@ -1,11 +1,11 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -o %t/Error -DPTR_SIZE_%target-ptrsize -module-name main %/s +// RUN: %target-codesign %t/Error // RUN: %target-run %t/Error // REQUIRES: executable_test import StdlibUnittest - var ErrorTests = TestSuite("Error") var NoisyErrorLifeCount = 0 diff --git a/test/stdlib/PrintStruct.swift b/test/stdlib/PrintStruct.swift index c637d5bebf01c..b616e61f5172a 100644 --- a/test/stdlib/PrintStruct.swift +++ b/test/stdlib/PrintStruct.swift @@ -4,6 +4,10 @@ // RUN: %target-codesign %t/main // RUN: %target-run %t/main // REQUIRES: executable_test +// +// FIXME Disable this case because this failed on only CI. +// Failed with 'Caught exception of type "CallIndirectOOB"' +// UNSUPPORTED: CPU=wasm32 import StdlibUnittest import PrintTestTypes diff --git a/test/stdlib/Reflection_jit.swift b/test/stdlib/Reflection_jit.swift index c36b6b6e8cc9f..8704ba6069ceb 100644 --- a/test/stdlib/Reflection_jit.swift +++ b/test/stdlib/Reflection_jit.swift @@ -2,3 +2,8 @@ // RUN: %target-jit-run -parse-stdlib %S/Reflection.swift -- %S/Inputs/shuffle.jpg | %FileCheck %S/Reflection.swift // REQUIRES: swift_interpreter + +// Only run this test when we build host tools (e.g. bin/swift-frontend), avoid running it for standalone stdlib builds. +// Standalone stdlib builds use downloadable toolchains from swift.org, which are codesigned in a way that doesn't let +// the interpreter process (swift-frontend) dynamically load locally-built modules (libswiftCore). +// REQUIRES: swift_tools_extra diff --git a/test/stdlib/symbol-visibility-linux.test-sh b/test/stdlib/symbol-visibility-linux.test-sh index 62be057f4d919..2472610c3e51b 100644 --- a/test/stdlib/symbol-visibility-linux.test-sh +++ b/test/stdlib/symbol-visibility-linux.test-sh @@ -19,6 +19,7 @@ // RUN: -e _ZNSt6vectorIjSaIjEE13_M_insert_auxIJjEEEvN9__gnu_cxx17__normal_iteratorIPjS1_EEDpOT_ \ // RUN: -e _ZNSt6vectorISt10unique_ptrIKvSt8functionIFvPS1_EEESaIS6_EE19_M_emplace_back_auxIJS6_EEEvDpOT_ \ // RUN: -e _ZNSt6vectorISt10unique_ptrIKvSt8functionIFvPS1_EEESaIS6_EE17_M_realloc_insertIJS6_EEEvN9__gnu_cxx17__normal_iteratorIPS6_S8_EEDpOT_ \ +// RUN: -e _ZNSt3_V28__rotateIPcEET_S2_S2_S2_St26random_access_iterator_tag \ // RUN: -e _ZN9__gnu_cxx12__to_xstringINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEcEET_PFiPT0_mPKS8_P13__va_list_tagEmSB_z \ // RUN: -e _ZZNSt19_Sp_make_shared_tag5_S_tiEvE5__tag \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEDnEEEvv \ @@ -30,6 +31,8 @@ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \ +// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA168_cEEEvv \ +// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA216_cEEEvv \ // RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \ // RUN: > %t/swiftCore-all.txt // RUN: %llvm-nm --defined-only --extern-only --no-weak %platform-dylib-dir/%target-library-name(swiftCore) > %t/swiftCore-no-weak.txt @@ -41,6 +44,7 @@ // RUN: -e _ZNSt6vectorIjSaIjEE13_M_insert_auxIJjEEEvN9__gnu_cxx17__normal_iteratorIPjS1_EEDpOT_ \ // RUN: -e _ZNSt6vectorISt10unique_ptrIKvSt8functionIFvPS1_EEESaIS6_EE19_M_emplace_back_auxIJS6_EEEvDpOT_ \ // RUN: -e _ZNSt6vectorISt10unique_ptrIKvSt8functionIFvPS1_EEESaIS6_EE17_M_realloc_insertIJS6_EEEvN9__gnu_cxx17__normal_iteratorIPS6_S8_EEDpOT_ \ +// RUN: -e _ZNSt3_V28__rotateIPcEET_S2_S2_S2_St26random_access_iterator_tag \ // RUN: -e _ZN9__gnu_cxx12__to_xstringINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEcEET_PFiPT0_mPKS8_P13__va_list_tagEmSB_z \ // RUN: -e _ZZNSt19_Sp_make_shared_tag5_S_tiEvE5__tag \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEDnEEEvv \ @@ -52,6 +56,8 @@ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \ +// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA168_cEEEvv \ +// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA216_cEEEvv \ // RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \ // RUN: > %t/swiftRemoteMirror-all.txt // RUN: %llvm-nm --defined-only --extern-only --no-weak %platform-dylib-dir/%target-library-name(swiftRemoteMirror) > %t/swiftRemoteMirror-no-weak.txt diff --git a/test/stmt/statements.swift b/test/stmt/statements.swift index b2594eb8f3398..93de7f6efabc8 100644 --- a/test/stmt/statements.swift +++ b/test/stmt/statements.swift @@ -280,7 +280,7 @@ func RepeatWhileStmt4() { func brokenSwitch(_ x: Int) -> Int { switch x { - case .Blah(var rep): // expected-error{{pattern cannot match values of type 'Int'}} + case .Blah(var rep): // expected-error{{type 'Int' has no member 'Blah'}} return rep } } diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 08a4083abdf15..b50cbc73b1f2b 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -22,6 +22,7 @@ add_swift_tool_subdirectory(swift-ide-test) add_swift_tool_subdirectory(swift-remoteast-test) add_swift_tool_subdirectory(swift-demangle) add_swift_tool_subdirectory(swift-demangle-yamldump) +add_swift_tool_subdirectory(swift-def-to-yaml-converter) add_swift_tool_subdirectory(swift-serialize-diagnostics) add_swift_tool_subdirectory(lldb-moduleimport-test) add_swift_tool_subdirectory(sil-func-extractor) diff --git a/tools/SourceKit/include/SourceKit/Core/Context.h b/tools/SourceKit/include/SourceKit/Core/Context.h index 922c1ab5c3c21..da9f19027b5a2 100644 --- a/tools/SourceKit/include/SourceKit/Core/Context.h +++ b/tools/SourceKit/include/SourceKit/Core/Context.h @@ -31,14 +31,20 @@ namespace SourceKit { class GlobalConfig { public: struct Settings { - /// When true, the default compiler options and other configuration flags will be chosen to optimize for - /// usage from an IDE. + /// When true, the default compiler options and other configuration flags + /// will be chosen to optimize for usage from an IDE. /// /// At the time of writing this just means ignoring .swiftsourceinfo files. bool OptimizeForIDE = false; - /// Interval second for checking dependencies in fast code completion. - unsigned CompletionCheckDependencyInterval = 5; + struct CompletionOptions { + + /// Max count of reusing ASTContext for cached code completion. + unsigned MaxASTContextReuseCount = 100; + + /// Interval second for checking dependencies in cached code completion. + unsigned CheckDependencyInterval = 5; + } CompletionOpts; }; private: @@ -47,9 +53,10 @@ class GlobalConfig { public: Settings update(Optional OptimizeForIDE, + Optional CompletionMaxASTContextReuseCount, Optional CompletionCheckDependencyInterval); bool shouldOptimizeForIDE() const; - unsigned getCompletionCheckDependencyInterval() const; + Settings::CompletionOptions getCompletionOpts() const; }; class Context { diff --git a/tools/SourceKit/lib/Core/Context.cpp b/tools/SourceKit/lib/Core/Context.cpp index b7899db03ba6c..f73c3fed54b55 100644 --- a/tools/SourceKit/lib/Core/Context.cpp +++ b/tools/SourceKit/lib/Core/Context.cpp @@ -18,12 +18,17 @@ using namespace SourceKit; GlobalConfig::Settings GlobalConfig::update(Optional OptimizeForIDE, + Optional CompletionMaxASTContextReuseCount, Optional CompletionCheckDependencyInterval) { llvm::sys::ScopedLock L(Mtx); if (OptimizeForIDE.hasValue()) State.OptimizeForIDE = *OptimizeForIDE; + if (CompletionMaxASTContextReuseCount.hasValue()) + State.CompletionOpts.MaxASTContextReuseCount = + *CompletionMaxASTContextReuseCount; if (CompletionCheckDependencyInterval.hasValue()) - State.CompletionCheckDependencyInterval = *CompletionCheckDependencyInterval; + State.CompletionOpts.CheckDependencyInterval = + *CompletionCheckDependencyInterval; return State; }; @@ -31,9 +36,10 @@ bool GlobalConfig::shouldOptimizeForIDE() const { llvm::sys::ScopedLock L(Mtx); return State.OptimizeForIDE; } -unsigned GlobalConfig::getCompletionCheckDependencyInterval() const { +GlobalConfig::Settings::CompletionOptions +GlobalConfig::getCompletionOpts() const { llvm::sys::ScopedLock L(Mtx); - return State.CompletionCheckDependencyInterval; + return State.CompletionOpts; } SourceKit::Context::Context( diff --git a/tools/SourceKit/lib/Support/CMakeLists.txt b/tools/SourceKit/lib/Support/CMakeLists.txt index 901720a521069..3b18cc18e98c9 100644 --- a/tools/SourceKit/lib/Support/CMakeLists.txt +++ b/tools/SourceKit/lib/Support/CMakeLists.txt @@ -1,6 +1,5 @@ add_sourcekit_library(SourceKitSupport Concurrency-libdispatch.cpp - FuzzyStringMatcher.cpp Logging.cpp ImmutableTextBuffer.cpp ThreadSafeRefCntPtr.cpp diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletion.h b/tools/SourceKit/lib/SwiftLang/CodeCompletion.h index 266282ab3f15b..f8098fbaf8390 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletion.h +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletion.h @@ -132,12 +132,6 @@ class CompletionBuilder { Optional moduleImportDepth; PopularityFactor popularityFactor; -public: - static void getFilterName(CodeCompletionString *str, raw_ostream &OS); - static void getDescription(SwiftResult *result, raw_ostream &OS, - bool leadingPunctuation, - bool annotatedDecription = false); - public: CompletionBuilder(CompletionSink &sink, SwiftResult &base); diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp index 8ac901da4de3c..c24e17a0e1afd 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp @@ -11,10 +11,10 @@ //===----------------------------------------------------------------------===// #include "CodeCompletionOrganizer.h" -#include "SourceKit/Support/FuzzyStringMatcher.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Module.h" #include "swift/IDE/CodeCompletionResultPrinter.h" +#include "swift/IDE/FuzzyStringMatcher.h" #include "swift/Frontend/Frontend.h" #include "swift/Markup/XMLUtils.h" #include "clang/Basic/CharInfo.h" @@ -1209,72 +1209,6 @@ bool LimitedResultView::walk(CodeCompletionView::Walker &walker) const { // CompletionBuilder //===----------------------------------------------------------------------===// -void CompletionBuilder::getFilterName(CodeCompletionString *str, - raw_ostream &OS) { - using ChunkKind = CodeCompletionString::Chunk::ChunkKind; - - // FIXME: we need a more uniform way to handle operator completions. - if (str->getChunks().size() == 1 && str->getChunks()[0].is(ChunkKind::Dot)) { - OS << "."; - return; - } else if (str->getChunks().size() == 2 && - str->getChunks()[0].is(ChunkKind::QuestionMark) && - str->getChunks()[1].is(ChunkKind::Dot)) { - OS << "?."; - return; - } - - auto FirstTextChunk = str->getFirstTextChunkIndex(); - if (FirstTextChunk.hasValue()) { - auto chunks = str->getChunks().slice(*FirstTextChunk); - for (auto i = chunks.begin(), e = chunks.end(); i != e; ++i) { - auto &C = *i; - - if (C.is(ChunkKind::BraceStmtWithCursor)) - break; // Don't include brace-stmt in filter name. - - if (C.is(ChunkKind::Equal)) { - OS << C.getText(); - break; - } - - bool shouldPrint = !C.isAnnotation(); - switch (C.getKind()) { - case ChunkKind::TypeAnnotation: - case ChunkKind::CallParameterInternalName: - case ChunkKind::CallParameterClosureType: - case ChunkKind::CallParameterClosureExpr: - case ChunkKind::CallParameterType: - case ChunkKind::DeclAttrParamColon: - case ChunkKind::Comma: - case ChunkKind::Whitespace: - case ChunkKind::Ellipsis: - case ChunkKind::Ampersand: - case ChunkKind::OptionalMethodCallTail: - continue; - case ChunkKind::CallParameterTypeBegin: - case ChunkKind::TypeAnnotationBegin: { - // Skip call parameter type or type annotation structure. - auto nestingLevel = C.getNestingLevel(); - do { ++i; } while (i != e && !i->endsPreviousNestedGroup(nestingLevel)); - --i; - continue; - } - case ChunkKind::CallParameterColon: - // Since we don't add the type, also don't add the space after ':'. - if (shouldPrint) - OS << ":"; - continue; - default: - break; - } - - if (C.hasText() && shouldPrint) - OS << C.getText(); - } - } -} - CompletionBuilder::CompletionBuilder(CompletionSink &sink, SwiftResult &base) : sink(sink), current(base) { typeRelation = current.getExpectedTypeRelation(); @@ -1286,7 +1220,7 @@ CompletionBuilder::CompletionBuilder(CompletionSink &sink, SwiftResult &base) // strings for our inner "." result. if (current.getCompletionString()->getFirstTextChunkIndex().hasValue()) { llvm::raw_svector_ostream OSS(originalName); - getFilterName(current.getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(current, OSS); } } @@ -1336,7 +1270,7 @@ Completion *CompletionBuilder::finish() { } llvm::raw_svector_ostream OSS(nameStorage); - getFilterName(base.getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(base, OSS); name = OSS.str(); } diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.h b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.h index f8f1d03225a2b..5ed52659a083e 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.h +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.h @@ -42,7 +42,6 @@ struct Options { bool hideLowPriority = true; bool hideByNameStyle = true; bool fuzzyMatching = true; - bool reuseASTContextIfPossible = true; bool annotatedDescription = false; unsigned minFuzzyLength = 2; unsigned showTopNonLiteralResults = 3; diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp index 7b30a003845b7..dfc5ea55b7daf 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp @@ -40,36 +40,6 @@ using namespace SourceKit; using namespace swift; using namespace swift::sys; -namespace { -class StreamDiagConsumer : public DiagnosticConsumer { - llvm::raw_ostream &OS; - -public: - StreamDiagConsumer(llvm::raw_ostream &OS) : OS(OS) {} - - void handleDiagnostic(SourceManager &SM, - const DiagnosticInfo &Info) override { - // FIXME: Print location info if available. - switch (Info.Kind) { - case DiagnosticKind::Error: - OS << "error: "; - break; - case DiagnosticKind::Warning: - OS << "warning: "; - break; - case DiagnosticKind::Note: - OS << "note: "; - break; - case DiagnosticKind::Remark: - OS << "remark: "; - break; - } - DiagnosticEngine::formatDiagnosticText(OS, Info.FormatString, - Info.FormatArgs); - } -}; -} // end anonymous namespace - void SwiftASTConsumer::failed(StringRef Error) { } //===----------------------------------------------------------------------===// @@ -433,46 +403,6 @@ convertFileContentsToInputs(const SmallVectorImpl &contents) { return inputsAndOutputs; } -static FrontendInputsAndOutputs resolveSymbolicLinksInInputs( - FrontendInputsAndOutputs &inputsAndOutputs, StringRef UnresolvedPrimaryFile, - llvm::IntrusiveRefCntPtr FileSystem, - std::string &Error) { - assert(FileSystem); - - llvm::SmallString<128> PrimaryFile; - if (auto err = FileSystem->getRealPath(UnresolvedPrimaryFile, PrimaryFile)) - PrimaryFile = UnresolvedPrimaryFile; - - unsigned primaryCount = 0; - // FIXME: The frontend should be dealing with symlinks, maybe similar to - // clang's FileManager ? - FrontendInputsAndOutputs replacementInputsAndOutputs; - for (const InputFile &input : inputsAndOutputs.getAllInputs()) { - llvm::SmallString<128> newFilename; - if (auto err = FileSystem->getRealPath(input.file(), newFilename)) - newFilename = input.file(); - llvm::sys::path::native(newFilename); - bool newIsPrimary = input.isPrimary() || - (!PrimaryFile.empty() && PrimaryFile == newFilename); - if (newIsPrimary) { - ++primaryCount; - } - assert(primaryCount < 2 && "cannot handle multiple primaries"); - replacementInputsAndOutputs.addInput( - InputFile(newFilename.str(), newIsPrimary, input.buffer())); - } - - if (PrimaryFile.empty() || primaryCount == 1) { - return replacementInputsAndOutputs; - } - - llvm::SmallString<64> Err; - llvm::raw_svector_ostream OS(Err); - OS << "'" << PrimaryFile << "' is not part of the input files"; - Error = std::string(OS.str()); - return replacementInputsAndOutputs; -} - bool SwiftASTManager::initCompilerInvocation( CompilerInvocation &Invocation, ArrayRef OrigArgs, DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, @@ -488,101 +418,10 @@ bool SwiftASTManager::initCompilerInvocation( DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, llvm::IntrusiveRefCntPtr FileSystem, std::string &Error) { - SmallVector Args; - // Make sure to put '-resource-dir' and '-diagnostic-documentation-path' at - // the top to allow overriding them with the passed in arguments. - Args.push_back("-resource-dir"); - Args.push_back(Impl.RuntimeResourcePath.c_str()); - Args.push_back("-Xfrontend"); - Args.push_back("-diagnostic-documentation-path"); - Args.push_back("-Xfrontend"); - Args.push_back(Impl.DiagnosticDocumentationPath.c_str()); - Args.append(OrigArgs.begin(), OrigArgs.end()); - - SmallString<32> ErrStr; - llvm::raw_svector_ostream ErrOS(ErrStr); - StreamDiagConsumer DiagConsumer(ErrOS); - Diags.addConsumer(DiagConsumer); - - bool HadError = driver::getSingleFrontendInvocationFromDriverArguments( - Args, Diags, [&](ArrayRef FrontendArgs) { - return Invocation.parseArgs(FrontendArgs, Diags); - }, /*ForceNoOutputs=*/true); - - // Remove the StreamDiagConsumer as it's no longer needed. - Diags.removeConsumer(DiagConsumer); - - if (HadError) { - Error = std::string(ErrOS.str()); - return true; - } - - Invocation.getFrontendOptions().InputsAndOutputs = - resolveSymbolicLinksInInputs( - Invocation.getFrontendOptions().InputsAndOutputs, - UnresolvedPrimaryFile, FileSystem, Error); - if (!Error.empty()) - return true; - - ClangImporterOptions &ImporterOpts = Invocation.getClangImporterOptions(); - ImporterOpts.DetailedPreprocessingRecord = true; - - assert(!Invocation.getModuleName().empty()); - - auto &LangOpts = Invocation.getLangOptions(); - LangOpts.AttachCommentsToDecls = true; - LangOpts.DiagnosticsEditorMode = true; - LangOpts.CollectParsedToken = true; - if (LangOpts.PlaygroundTransform) { - // The playground instrumenter changes the AST in ways that disrupt the - // SourceKit functionality. Since we don't need the instrumenter, and all we - // actually need is the playground semantics visible to the user, like - // silencing the "expression resolves to an unused l-value" error, disable it. - LangOpts.PlaygroundTransform = false; - } - - // Disable the index-store functionality for the sourcekitd requests. - auto &FrontendOpts = Invocation.getFrontendOptions(); - FrontendOpts.IndexStorePath.clear(); - ImporterOpts.IndexStorePath.clear(); - - // Force the action type to be -typecheck. This affects importing the - // SwiftONoneSupport module. - FrontendOpts.RequestedAction = FrontendOptions::ActionType::Typecheck; - - // We don't care about LLVMArgs - FrontendOpts.LLVMArgs.clear(); - - // SwiftSourceInfo files provide source location information for decls coming - // from loaded modules. For most IDE use cases it either has an undesirable - // impact on performance with no benefit (code completion), results in stale - // locations being used instead of more up-to-date indexer locations (cursor - // info), or has no observable effect (diagnostics, which are filtered to just - // those with a location in the primary file, and everything else). - if (Impl.Config->shouldOptimizeForIDE()) - FrontendOpts.IgnoreSwiftSourceInfo = true; - - // To save the time for module validation, consider the lifetime of ASTManager - // as a single build session. - // NOTE: Do this only if '-disable-modules-validate-system-headers' is *not* - // explicitly enabled. - auto &SearchPathOpts = Invocation.getSearchPathOptions(); - if (!SearchPathOpts.DisableModulesValidateSystemDependencies) { - // NOTE: 'SessionTimestamp - 1' because clang compares it with '<=' that may - // cause unnecessary validations if they happens within one second - // from the SourceKit startup. - ImporterOpts.ExtraArgs.push_back("-fbuild-session-timestamp=" + - std::to_string(Impl.SessionTimestamp - 1)); - ImporterOpts.ExtraArgs.push_back( - "-fmodules-validate-once-per-build-session"); - - SearchPathOpts.DisableModulesValidateSystemDependencies = true; - } - - // Disable expensive SIL options to reduce time spent in SILGen. - disableExpensiveSILOptions(Invocation.getSILOptions()); - - return false; + return ide::initCompilerInvocation( + Invocation, OrigArgs, Diags, UnresolvedPrimaryFile, FileSystem, + Impl.RuntimeResourcePath, Impl.DiagnosticDocumentationPath, + Impl.Config->shouldOptimizeForIDE(), Impl.SessionTimestamp, Error); } bool SwiftASTManager::initCompilerInvocation(CompilerInvocation &CompInvok, diff --git a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp index 0870461fede85..8e8e9bf8bbb95 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp @@ -49,8 +49,7 @@ struct SwiftToSourceKitCompletionAdapter { llvm::SmallString<64> name; { llvm::raw_svector_ostream OSS(name); - CodeCompletion::CompletionBuilder::getFilterName( - result->getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(*result, OSS); } llvm::SmallString<64> description; @@ -75,9 +74,6 @@ struct SwiftToSourceKitCompletionAdapter { bool legacyLiteralToKeyword, bool annotatedDescription); - static void getResultSourceText(const CodeCompletionString *CCStr, - raw_ostream &OS); - static void getResultAssociatedUSRs(ArrayRef AssocUSRs, raw_ostream &OS); }; @@ -125,9 +121,9 @@ static bool swiftCodeCompleteImpl( unsigned Offset, SwiftCodeCompletionConsumer &SwiftConsumer, ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, - bool EnableASTCaching, bool annotateDescription, std::string &Error) { + bool annotateDescription, std::string &Error) { return Lang.performCompletionLikeOperation( - UnresolvedInputFile, Offset, Args, FileSystem, EnableASTCaching, Error, + UnresolvedInputFile, Offset, Args, FileSystem, Error, [&](CompilerInstance &CI, bool reusingASTContext) { // Create a factory for code completion callbacks that will feed the // Consumer. @@ -219,7 +215,6 @@ void SwiftLangSupport::codeComplete( std::string Error; if (!swiftCodeCompleteImpl(*this, UnresolvedInputFile, Offset, SwiftConsumer, Args, fileSystem, - CCOpts.reuseASTContextIfPossible, CCOpts.annotatedDescription, Error)) { SKConsumer.failed(Error); } @@ -466,7 +461,7 @@ bool SwiftToSourceKitCompletionAdapter::handleResult( unsigned TextBegin = SS.size(); { llvm::raw_svector_ostream ccOS(SS); - getResultSourceText(Result->getCompletionString(), ccOS); + ide::printCodeCompletionResultSourceText(*Result, ccOS); } unsigned TextEnd = SS.size(); @@ -603,121 +598,6 @@ getCodeCompletionKeywordKindForUID(UIdent uid) { return CodeCompletionKeywordKind::None; } -using ChunkKind = CodeCompletionString::Chunk::ChunkKind; - -/// Provide the text for the call parameter, including constructing a typed -/// editor placeholder for it. -static void constructTextForCallParam( - ArrayRef ParamGroup, raw_ostream &OS) { - assert(ParamGroup.front().is(ChunkKind::CallParameterBegin)); - - for (; !ParamGroup.empty(); ParamGroup = ParamGroup.slice(1)) { - auto &C = ParamGroup.front(); - if (C.isAnnotation()) - continue; - if (C.is(ChunkKind::CallParameterInternalName) || - C.is(ChunkKind::CallParameterType) || - C.is(ChunkKind::CallParameterTypeBegin) || - C.is(ChunkKind::CallParameterClosureExpr)) { - break; - } - if (!C.hasText()) - continue; - OS << C.getText(); - } - - SmallString<32> DisplayString; - SmallString<32> TypeString; - SmallString<32> ExpansionTypeString; - - for (auto i = ParamGroup.begin(), e = ParamGroup.end(); i != e; ++i) { - auto &C = *i; - if (C.is(ChunkKind::CallParameterTypeBegin)) { - assert(TypeString.empty()); - auto nestingLevel = C.getNestingLevel(); - ++i; - for (; i != e; ++i) { - if (i->endsPreviousNestedGroup(nestingLevel)) - break; - if (!i->isAnnotation() && i->hasText()) { - TypeString += i->getText(); - DisplayString += i->getText(); - } - } - --i; - continue; - } - if (C.is(ChunkKind::CallParameterClosureType)) { - assert(ExpansionTypeString.empty()); - ExpansionTypeString = C.getText(); - continue; - } - if (C.is(ChunkKind::CallParameterType)) { - assert(TypeString.empty()); - TypeString = C.getText(); - } - if (C.is(ChunkKind::CallParameterClosureExpr)) { - // We have a closure expression, so provide it directly instead of in - // a placeholder. - OS << "{"; - if (!C.getText().empty()) - OS << " " << C.getText(); - OS << "\n" << getCodePlaceholder() << "\n}"; - return; - } - if (C.isAnnotation() || !C.hasText()) - continue; - DisplayString += C.getText(); - } - - StringRef Display = DisplayString.str(); - StringRef Type = TypeString.str(); - StringRef ExpansionType = ExpansionTypeString.str(); - if (ExpansionType.empty()) - ExpansionType = Type; - - OS << "<#T##" << Display; - if (Display == Type && Display == ExpansionType) { - // Short version, display and type are the same. - } else { - OS << "##" << Type; - if (ExpansionType != Type) - OS << "##" << ExpansionType; - } - OS << "#>"; -} - -void SwiftToSourceKitCompletionAdapter::getResultSourceText( - const CodeCompletionString *CCStr, raw_ostream &OS) { - auto Chunks = CCStr->getChunks(); - for (size_t i = 0; i < Chunks.size(); ++i) { - auto &C = Chunks[i]; - if (C.is(ChunkKind::BraceStmtWithCursor)) { - OS << " {\n" << getCodePlaceholder() << "\n}"; - continue; - } - if (C.is(ChunkKind::CallParameterBegin)) { - size_t Start = i++; - for (; i < Chunks.size(); ++i) { - if (Chunks[i].endsPreviousNestedGroup(C.getNestingLevel())) - break; - } - constructTextForCallParam(Chunks.slice(Start, i-Start), OS); - --i; - continue; - } - if (C.is(ChunkKind::TypeAnnotationBegin)) { - // Skip type annotation structure. - auto level = C.getNestingLevel(); - do { ++i; } while (i != Chunks.size() && !Chunks[i].endsPreviousNestedGroup(level)); - --i; - } - if (!C.isAnnotation() && C.hasText()) { - OS << C.getText(); - } - } -} - void SwiftToSourceKitCompletionAdapter::getResultAssociatedUSRs( ArrayRef AssocUSRs, raw_ostream &OS) { bool First = true; @@ -853,7 +733,6 @@ static void translateCodeCompletionOptions(OptionsDictionary &from, static UIdent KeyContextWeight("key.codecomplete.sort.contextweight"); static UIdent KeyFuzzyWeight("key.codecomplete.sort.fuzzyweight"); static UIdent KeyPopularityBonus("key.codecomplete.sort.popularitybonus"); - static UIdent KeyReuseASTContext("key.codecomplete.reuseastcontext"); static UIdent KeyAnnotatedDescription("key.codecomplete.annotateddescription"); from.valueForOption(KeySortByName, to.sortByName); @@ -879,7 +758,6 @@ static void translateCodeCompletionOptions(OptionsDictionary &from, from.valueForOption(KeyPopularityBonus, to.popularityBonus); from.valueForOption(KeyHideByName, to.hideByNameStyle); from.valueForOption(KeyTopNonLiteral, to.showTopNonLiteralResults); - from.valueForOption(KeyReuseASTContext, to.reuseASTContextIfPossible); from.valueForOption(KeyAnnotatedDescription, to.annotatedDescription); } @@ -1005,8 +883,7 @@ filterInnerResults(ArrayRef results, bool includeInner, llvm::SmallString<64> filterName; { llvm::raw_svector_ostream OSS(filterName); - CodeCompletion::CompletionBuilder::getFilterName( - result->getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(*result, OSS); } llvm::SmallString<64> description; { @@ -1140,8 +1017,7 @@ static void transformAndForwardResults( std::string str = inputBuf->getBuffer().slice(0, offset).str(); { llvm::raw_string_ostream OSS(str); - SwiftToSourceKitCompletionAdapter::getResultSourceText( - exactMatch->getCompletionString(), OSS); + ide::printCodeCompletionResultSourceText(*exactMatch, OSS); } auto buffer = @@ -1153,7 +1029,6 @@ static void transformAndForwardResults( std::string error; if (!swiftCodeCompleteImpl(lang, buffer.get(), str.size(), swiftConsumer, cargs, session->getFileSystem(), - options.reuseASTContextIfPossible, options.annotatedDescription, error)) { consumer.failed(error); return; @@ -1255,7 +1130,6 @@ void SwiftLangSupport::codeCompleteOpen( // Invoke completion. if (!swiftCodeCompleteImpl(*this, inputBuf, offset, swiftConsumer, extendedArgs, fileSystem, - CCOpts.reuseASTContextIfPossible, CCOpts.annotatedDescription, error)) { consumer.failed(error); return; diff --git a/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp b/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp index f2814e606baf0..176f307dd14bd 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp @@ -26,11 +26,10 @@ using namespace SourceKit; using namespace swift; using namespace ide; -static void translateConformingMethodListOptions(OptionsDictionary &from, - ConformingMethodList::Options &to) { - static UIdent KeyReuseASTContext("key.conformingmethods.reuseastcontext"); - - from.valueForOption(KeyReuseASTContext, to.reuseASTContextIfPossible); +static void +translateConformingMethodListOptions(OptionsDictionary &from, + ConformingMethodList::Options &to) { + // ConformingMethodList doesn't receive any options at this point. } static bool swiftConformingMethodListImpl( @@ -39,9 +38,9 @@ static bool swiftConformingMethodListImpl( ArrayRef ExpectedTypeNames, ide::ConformingMethodListConsumer &Consumer, llvm::IntrusiveRefCntPtr FileSystem, - bool EnableASTCaching, std::string &Error) { + std::string &Error) { return Lang.performCompletionLikeOperation( - UnresolvedInputFile, Offset, Args, FileSystem, EnableASTCaching, Error, + UnresolvedInputFile, Offset, Args, FileSystem, Error, [&](CompilerInstance &CI, bool reusingASTContext) { // Create a factory for code completion callbacks that will feed the // Consumer. @@ -194,7 +193,7 @@ void SwiftLangSupport::getConformingMethodList( if (!swiftConformingMethodListImpl(*this, UnresolvedInputFile, Offset, Args, ExpectedTypeNames, Consumer, fileSystem, - options.reuseASTContextIfPossible, error)) { + error)) { SKConsumer.failed(error); } } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp index 6b0fe110a774c..d77474f197d5c 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp @@ -1601,9 +1601,6 @@ class PlaceholderExpansionScanner { if (auto *CE = dyn_cast(E)) { // Call expression can have argument. Arg = CE->getArg(); - } else if (auto UME = dyn_cast(E)) { - // Unresolved member can have argument too. - Arg = UME->getArgument(); } if (!Arg) return false; diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp index 45684f0d87ced..02b066e70ee6e 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp @@ -264,8 +264,11 @@ class InMemoryFileSystemProvider: public SourceKit::FileSystemProvider { static void configureCompletionInstance(std::shared_ptr CompletionInst, std::shared_ptr GlobalConfig) { - CompletionInst->setDependencyCheckIntervalSecond( - GlobalConfig->getCompletionCheckDependencyInterval()); + auto Opts = GlobalConfig->getCompletionOpts(); + CompletionInst->setOptions({ + Opts.MaxASTContextReuseCount, + Opts.CheckDependencyInterval + }); } SwiftLangSupport::SwiftLangSupport(SourceKit::Context &SKCtx) @@ -274,7 +277,7 @@ SwiftLangSupport::SwiftLangSupport(SourceKit::Context &SKCtx) llvm::SmallString<128> LibPath(SKCtx.getRuntimeLibPath()); llvm::sys::path::append(LibPath, "swift"); RuntimeResourcePath = std::string(LibPath.str()); - DiagnosticDocumentationPath = SKCtx.getDiagnosticDocumentationPath(); + DiagnosticDocumentationPath = SKCtx.getDiagnosticDocumentationPath().str(); Stats = std::make_shared(); EditorDocuments = std::make_shared(); @@ -986,7 +989,7 @@ bool SwiftLangSupport::performCompletionLikeOperation( llvm::MemoryBuffer *UnresolvedInputFile, unsigned Offset, ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, - bool EnableASTCaching, std::string &Error, + std::string &Error, llvm::function_ref Callback) { assert(FileSystem); @@ -1042,8 +1045,7 @@ bool SwiftLangSupport::performCompletionLikeOperation( return CompletionInst->performOperation(Invocation, Args, FileSystem, newBuffer.get(), Offset, - EnableASTCaching, Error, - &CIDiags, Callback); + Error, &CIDiags, Callback); } CloseClangModuleFiles::~CloseClangModuleFiles() { diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h index f64adc35c85d6..81f61f49c7759 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h +++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h @@ -222,13 +222,13 @@ class SessionCacheMap { namespace TypeContextInfo { struct Options { - bool reuseASTContextIfPossible = true; + // TypeContextInfo doesn't receive any options at this point. }; } // namespace TypeContextInfo namespace ConformingMethodList { struct Options { - bool reuseASTContextIfPossible = true; + // ConformingMethodList doesn't receive any options at this point. }; } // namespace ConformingMethodList @@ -465,7 +465,7 @@ class SwiftLangSupport : public LangSupport { llvm::MemoryBuffer *UnresolvedInputFile, unsigned Offset, ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, - bool EnableASTCaching, std::string &Error, + std::string &Error, llvm::function_ref Callback); //==========================================================================// diff --git a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp index bd366f9de63de..746c13ea30f9f 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp @@ -20,8 +20,9 @@ #include "swift/AST/ASTDemangler.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" +#include "swift/AST/LookupKinds.h" +#include "swift/AST/ModuleNameLookup.h" #include "swift/AST/NameLookup.h" -#include "swift/AST/NameLookupRequests.h" #include "swift/AST/SwiftNameTranslation.h" #include "swift/AST/GenericSignature.h" #include "swift/Basic/SourceManager.h" @@ -484,40 +485,48 @@ void SwiftLangSupport::printFullyAnnotatedSynthesizedDeclaration( template void walkRelatedDecls(const ValueDecl *VD, const FnTy &Fn) { - llvm::SmallDenseMap NamesSeen; - ++NamesSeen[VD->getName()]; - SmallVector RelatedDecls; - if (isa(VD)) return; // Parameters don't have interesting related declarations. - // FIXME: Extract useful related declarations, overloaded functions, - // if VD is an initializer, we should extract other initializers etc. - // For now we use unqualified lookup to fetch other declarations with the same - // base name. auto &ctx = VD->getASTContext(); - auto descriptor = UnqualifiedLookupDescriptor(DeclNameRef(VD->getBaseName()), - VD->getDeclContext()); - auto lookup = evaluateOrDefault(ctx.evaluator, - UnqualifiedLookupRequest{descriptor}, {}); - for (auto result : lookup) { - ValueDecl *RelatedVD = result.getValueDecl(); - if (RelatedVD->getAttrs().isUnavailable(VD->getASTContext())) + + llvm::SmallDenseMap NamesSeen; + ++NamesSeen[VD->getName()]; + + + auto *DC = VD->getDeclContext(); + bool typeLookup = DC->isTypeContext(); + + SmallVector results; + + if (typeLookup) { + auto type = DC->getDeclaredInterfaceType(); + if (!type->is()) { + DC->lookupQualified(type, DeclNameRef(VD->getBaseName()), + NL_QualifiedDefault, results); + } + } else { + namelookup::lookupInModule(DC->getModuleScopeContext(), + VD->getBaseName(), results, + NLKind::UnqualifiedLookup, + namelookup::ResolutionKind::Overloadable, + DC->getModuleScopeContext()); + } + + SmallVector RelatedDecls; + for (auto result : results) { + if (result->getAttrs().isUnavailable(ctx)) continue; - if (RelatedVD != VD) { - ++NamesSeen[RelatedVD->getName()]; + if (result != VD) { + ++NamesSeen[result->getName()]; RelatedDecls.push_back(result); } } // Now provide the results along with whether the name is duplicate or not. - ValueDecl *OriginalBase = VD->getDeclContext()->getSelfNominalTypeDecl(); - for (auto Related : RelatedDecls) { - ValueDecl *RelatedVD = Related.getValueDecl(); - bool SameBase = Related.getBaseDecl() && Related.getBaseDecl() == OriginalBase; - Fn(RelatedVD, SameBase, NamesSeen[RelatedVD->getName()] > 1); - } + for (auto result : RelatedDecls) + Fn(result, typeLookup, NamesSeen[result->getName()] > 1); } //===----------------------------------------------------------------------===// diff --git a/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp b/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp index 5a7b8bdd3dcad..9e857ba8ac506 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp @@ -27,9 +27,7 @@ using namespace ide; static void translateTypeContextInfoOptions(OptionsDictionary &from, TypeContextInfo::Options &to) { - static UIdent KeyReuseASTContext("key.typecontextinfo.reuseastcontext"); - - from.valueForOption(KeyReuseASTContext, to.reuseASTContextIfPossible); + // TypeContextInfo doesn't receive any options at this point. } static bool swiftTypeContextInfoImpl( @@ -37,9 +35,9 @@ static bool swiftTypeContextInfoImpl( unsigned Offset, ide::TypeContextInfoConsumer &Consumer, ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, - bool EnableASTCaching, std::string &Error) { + std::string &Error) { return Lang.performCompletionLikeOperation( - UnresolvedInputFile, Offset, Args, FileSystem, EnableASTCaching, Error, + UnresolvedInputFile, Offset, Args, FileSystem, Error, [&](CompilerInstance &CI, bool reusingASTContext) { // Create a factory for code completion callbacks that will feed the // Consumer. @@ -168,8 +166,7 @@ void SwiftLangSupport::getExpressionContextInfo( } Consumer(SKConsumer); if (!swiftTypeContextInfoImpl(*this, UnresolvedInputFile, Offset, Consumer, - Args, fileSystem, - options.reuseASTContextIfPossible, error)) { + Args, fileSystem, error)) { SKConsumer.failed(error); } } diff --git a/tools/SourceKit/tools/sourcekitd-test/Options.td b/tools/SourceKit/tools/sourcekitd-test/Options.td index 5119a2e169470..522cc38fbecee 100644 --- a/tools/SourceKit/tools/sourcekitd-test/Options.td +++ b/tools/SourceKit/tools/sourcekitd-test/Options.td @@ -140,14 +140,6 @@ def vfs_files : CommaJoined<["-"], "vfs-files=">, def vfs_name : Separate<["-"], "vfs-name">, HelpText<"Specify a virtual filesystem name">; -def optimize_for_ide : Joined<["-"], "for-ide=">, - HelpText<"Value for the OptimizeForIde global configuration setting">; - -def completion_check_dependency_interval : Separate<["-"], "completion-check-dependency-interval">, - HelpText<"Inteval seconds for checking dependencies in fast completion">; -def completion_check_dependency_interval_EQ : Joined<["-"], "completion-check-dependency-interval=">, - Alias; - def suppress_config_request : Flag<["-"], "suppress-config-request">, HelpText<"Suppress the default global configuration request, that is otherwise sent before any other request (except for the global-config request itself)">; diff --git a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp index ee577379698a8..7b49e636d0933 100644 --- a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp @@ -371,29 +371,6 @@ bool TestOptions::parseArgs(llvm::ArrayRef Args) { VFSName = InputArg->getValue(); break; - case OPT_optimize_for_ide: { - bool Value; - if (StringRef(InputArg->getValue()).getAsInteger(10, Value)) { - llvm::errs() << "error: expected 0 or 1 for 'for-ide'\n"; - return true; - } - OptimizeForIde = Value; - break; - } - - case OPT_completion_check_dependency_interval: { - int64_t Value; - if (StringRef(InputArg->getValue()).getAsInteger(10, Value)) { - llvm::errs() << "error: expected number for inteval\n"; - return true; - } else if (Value < 0) { - llvm::errs() << "error: completion-check-dependency-interval must be > 0\n"; - return true; - } - CompletionCheckDependencyInterval = Value; - break; - } - case OPT_suppress_config_request: SuppressDefaultConfigRequest = true; break; diff --git a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp index b9f2b3eaf373b..925fea4e93638 100644 --- a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp @@ -538,15 +538,17 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) { case SourceKitRequest::GlobalConfiguration: sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestGlobalConfiguration); - if (Opts.OptimizeForIde.hasValue()) - sourcekitd_request_dictionary_set_int64( - Req, KeyOptimizeForIDE, - static_cast(Opts.OptimizeForIde.getValue())); - if (Opts.CompletionCheckDependencyInterval.hasValue()) - sourcekitd_request_dictionary_set_int64( - Req, KeyCompletionCheckDependencyInterval, - static_cast( - Opts.CompletionCheckDependencyInterval.getValue())); + + for (auto &Opt : Opts.RequestOptions) { + auto KeyValue = StringRef(Opt).split('='); + std::string KeyStr("key."); + KeyStr.append(KeyValue.first.str()); + sourcekitd_uid_t Key = sourcekitd_uid_get_from_cstr(KeyStr.c_str()); + + int64_t Value = 0; + KeyValue.second.getAsInteger(0, Value); + sourcekitd_request_dictionary_set_int64(Req, Key, Value); + } break; case SourceKitRequest::ProtocolVersion: diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp b/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp index 42f632ef79194..d95425de1bd4b 100644 --- a/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp +++ b/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp @@ -437,23 +437,27 @@ void handleRequestImpl(sourcekitd_object_t ReqObj, ResponseReceiver Rec) { ResponseBuilder RB; auto dict = RB.getDictionary(); - Optional OptimizeForIDE; - int64_t EditorMode = true; - if (!Req.getInt64(KeyOptimizeForIDE, EditorMode, true)) { - OptimizeForIDE = EditorMode; - } + Optional OptimizeForIDE = + Req.getOptionalInt64(KeyOptimizeForIDE) + .map([](int64_t v) -> bool { return v; }); + Optional CompletionMaxASTContextReuseCount = + Req.getOptionalInt64(KeyCompletionMaxASTContextReuseCount) + .map([](int64_t v) -> unsigned { return v; }); Optional CompletionCheckDependencyInterval = - Req.getOptionalInt64(KeyCompletionCheckDependencyInterval) - .map([](int64_t v)->unsigned{return v;}); + Req.getOptionalInt64(KeyCompletionCheckDependencyInterval) + .map([](int64_t v) -> unsigned { return v; }); - GlobalConfig::Settings UpdatedConfig = Config->update( - OptimizeForIDE, CompletionCheckDependencyInterval); + GlobalConfig::Settings UpdatedConfig = + Config->update(OptimizeForIDE, CompletionMaxASTContextReuseCount, + CompletionCheckDependencyInterval); getGlobalContext().getSwiftLangSupport().globalConfigurationUpdated(Config); dict.set(KeyOptimizeForIDE, UpdatedConfig.OptimizeForIDE); + dict.set(KeyCompletionMaxASTContextReuseCount, + UpdatedConfig.CompletionOpts.MaxASTContextReuseCount); dict.set(KeyCompletionCheckDependencyInterval, - UpdatedConfig.CompletionCheckDependencyInterval); + UpdatedConfig.CompletionOpts.CheckDependencyInterval); return Rec(RB.createResponse()); } diff --git a/tools/driver/autolink_extract_main.cpp b/tools/driver/autolink_extract_main.cpp index a9976ac021a50..39c338e239310 100644 --- a/tools/driver/autolink_extract_main.cpp +++ b/tools/driver/autolink_extract_main.cpp @@ -166,7 +166,7 @@ extractLinkerFlagsFromObjectFile(const llvm::object::WasmObjectFile *ObjectFile, SegmentData.split(SplitFlags, llvm::StringRef("\0", 1), -1, /*KeepEmpty=*/false); for (const auto &Flag : SplitFlags) - LinkerFlags.push_back(Flag); + LinkerFlags.push_back(Flag.str()); } } return false; diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index ff189f773ab28..318fc77746dd7 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -140,14 +140,15 @@ static int run_driver(StringRef ExecName, argv.data()+argv.size()), argv[0], (void *)(intptr_t)getExecutablePath); } - } - // Run the integrated Swift frontend when called as "swift-frontend" but - // without a leading "-frontend". - if (ExecName == "swift-frontend") { - return performFrontend(llvm::makeArrayRef(argv.data()+1, - argv.data()+argv.size()), - argv[0], (void *)(intptr_t)getExecutablePath); + // Run the integrated Swift frontend when called as "swift-frontend" but + // without a leading "-frontend". + if (!FirstArg.startswith("--driver-mode=") + && ExecName == "swift-frontend") { + return performFrontend(llvm::makeArrayRef(argv.data()+1, + argv.data()+argv.size()), + argv[0], (void *)(intptr_t)getExecutablePath); + } } std::string Path = getExecutablePath(argv[0]); @@ -191,6 +192,8 @@ static int run_driver(StringRef ExecName, if (C) { std::unique_ptr TQ = TheDriver.buildTaskQueue(*C); + if (!TQ) + return 1; return C->performJobs(std::move(TQ)); } diff --git a/tools/driver/modulewrap_main.cpp b/tools/driver/modulewrap_main.cpp index 510cf5d3edabf..3ef145ad07e3a 100644 --- a/tools/driver/modulewrap_main.cpp +++ b/tools/driver/modulewrap_main.cpp @@ -176,15 +176,15 @@ int modulewrap_main(ArrayRef Args, const char *Argv0, SourceManager SrcMgr; TypeCheckerOptions TypeCheckOpts; LangOptions LangOpts; + ClangImporterOptions ClangImporterOpts; LangOpts.Target = Invocation.getTargetTriple(); ASTContext &ASTCtx = *ASTContext::get(LangOpts, TypeCheckOpts, SearchPathOpts, - SrcMgr, Instance.getDiags()); + ClangImporterOpts, SrcMgr, + Instance.getDiags()); registerParseRequestFunctions(ASTCtx.evaluator); registerTypeCheckerRequestFunctions(ASTCtx.evaluator); - ClangImporterOptions ClangImporterOpts; - ASTCtx.addModuleLoader(ClangImporter::create(ASTCtx, ClangImporterOpts, ""), - true); + ASTCtx.addModuleLoader(ClangImporter::create(ASTCtx, ""), true); ModuleDecl *M = ModuleDecl::create(ASTCtx.getIdentifier("swiftmodule"), ASTCtx); SILOptions SILOpts; std::unique_ptr TC(new Lowering::TypeConverter(*M)); diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp index 490bf85550abb..f4d2b4490cf3b 100644 --- a/tools/sil-opt/SILOpt.cpp +++ b/tools/sil-opt/SILOpt.cpp @@ -274,6 +274,11 @@ static llvm::cl::opt llvm::cl::desc("Enable C++ interop."), llvm::cl::init(false)); +static llvm::cl::opt + IgnoreAlwaysInline("ignore-always-inline", + llvm::cl::desc("Ignore [always_inline] attribute."), + llvm::cl::init(false)); + static void runCommandLineSelectedPasses(SILModule *Module, irgen::IRGenModule *IRGenMod) { auto &opts = Module->getOptions(); @@ -398,6 +403,7 @@ int main(int argc, char **argv) { } SILOpts.EnableSpeculativeDevirtualization = EnableSpeculativeDevirtualization; + SILOpts.IgnoreAlwaysInline = IgnoreAlwaysInline; serialization::ExtendedValidationInfo extendedInfo; llvm::ErrorOr> FileBufOrErr = diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp index 9e91584e84659..813a7bd843097 100644 --- a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp +++ b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp @@ -1603,6 +1603,11 @@ SDKContext::shouldIgnore(Decl *D, const Decl* Parent) const { if (isa(VD)) return true; } + // Exclude decls with @_alwaysEmitIntoClient if we are checking ABI. + // These decls are considered effectively public because they are usable + // from inline, so we have to manually exclude them here. + if (D->getAttrs().hasAttribute()) + return true; } else { if (D->isPrivateStdlibDecl(false)) return true; diff --git a/tools/swift-api-digester/ModuleDiagsConsumer.cpp b/tools/swift-api-digester/ModuleDiagsConsumer.cpp index 6e4d2b9dcbd52..7ded7259b744e 100644 --- a/tools/swift-api-digester/ModuleDiagsConsumer.cpp +++ b/tools/swift-api-digester/ModuleDiagsConsumer.cpp @@ -78,7 +78,7 @@ static StringRef getCategoryName(uint32_t ID) { case LocalDiagID::not_inheriting_convenience_inits: return "/* Class Inheritance Change */"; default: - return StringRef(); + return "/* Others */"; } } } @@ -122,3 +122,28 @@ swift::ide::api::ModuleDifferDiagsConsumer::~ModuleDifferDiagsConsumer() { } } } + +bool swift::ide::api:: +FilteringDiagnosticConsumer::shouldProceed(const DiagnosticInfo &Info) { + if (allowedBreakages->empty()) { + return true; + } + llvm::SmallString<256> Text; + { + llvm::raw_svector_ostream Out(Text); + DiagnosticEngine::formatDiagnosticText(Out, Info.FormatString, + Info.FormatArgs); + } + return allowedBreakages->count(Text.str()) == 0; +} + +void swift::ide::api:: +FilteringDiagnosticConsumer::handleDiagnostic(SourceManager &SM, + const DiagnosticInfo &Info) { + if (shouldProceed(Info)) { + if (Info.Kind == DiagnosticKind::Error) { + HasError = true; + } + subConsumer->handleDiagnostic(SM, Info); + } +} diff --git a/tools/swift-api-digester/ModuleDiagsConsumer.h b/tools/swift-api-digester/ModuleDiagsConsumer.h index df83c808baa88..cb23ef5d301ea 100644 --- a/tools/swift-api-digester/ModuleDiagsConsumer.h +++ b/tools/swift-api-digester/ModuleDiagsConsumer.h @@ -41,6 +41,30 @@ class ModuleDifferDiagsConsumer: public PrintingDiagnosticConsumer { ~ModuleDifferDiagsConsumer(); void handleDiagnostic(SourceManager &SM, const DiagnosticInfo &Info) override; }; + +class FilteringDiagnosticConsumer: public DiagnosticConsumer { + bool HasError = false; + std::unique_ptr subConsumer; + std::unique_ptr> allowedBreakages; + bool shouldProceed(const DiagnosticInfo &Info); +public: + FilteringDiagnosticConsumer(std::unique_ptr subConsumer, + std::unique_ptr> allowedBreakages): + subConsumer(std::move(subConsumer)), + allowedBreakages(std::move(allowedBreakages)) {} + ~FilteringDiagnosticConsumer() = default; + + bool finishProcessing() override { return subConsumer->finishProcessing(); } + bool hasError() const { return HasError; } + void flush() override { subConsumer->flush(); } + + void informDriverOfIncompleteBatchModeCompilation() override { + subConsumer->informDriverOfIncompleteBatchModeCompilation(); + } + + void handleDiagnostic(SourceManager &SM, + const DiagnosticInfo &Info) override; +}; } } } diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index 6e69d0cf36eb8..e5820cae73a3d 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -26,6 +26,7 @@ // can be reflected as source-breaking changes for API users. If they are, // the output of api-digester will include such changes. +#include "swift/Basic/Platform.h" #include "swift/Frontend/PrintingDiagnosticConsumer.h" #include "swift/Frontend/SerializedDiagnosticConsumer.h" #include "swift/AST/DiagnosticsModuleDiffer.h" @@ -72,7 +73,7 @@ ModuleList("module-list-file", llvm::cl::cat(Category)); static llvm::cl::opt -ProtReqWhiteList("protocol-requirement-white-list", +ProtReqAllowList("protocol-requirement-allow-list", llvm::cl::desc("File containing a new-line separated list of protocol names"), llvm::cl::cat(Category)); @@ -264,6 +265,11 @@ SerializedDiagPath("serialize-diagnostics-path", llvm::cl::desc("Serialize diagnostics to a path"), llvm::cl::cat(Category)); +static llvm::cl::opt +BreakageAllowlistPath("breakage-allowlist-path", + llvm::cl::desc("An allowlist of breakages to not complain about"), + llvm::cl::cat(Category)); + } // namespace options namespace { @@ -1057,6 +1063,17 @@ void swift::ide::api::SDKNodeTypeFunc::diagnose(SDKNode *Right) { } namespace { +static void diagnoseRemovedDecl(const SDKNodeDecl *D) { + if (D->getSDKContext().checkingABI()) { + // Don't complain about removing @_alwaysEmitIntoClient if we are checking ABI. + // We shouldn't include these decls in the ABI baseline file. This line is + // added so the checker is backward compatible. + if (D->hasDeclAttribute(DeclAttrKind::DAK_AlwaysEmitIntoClient)) + return; + } + D->emitDiag(SourceLoc(), diag::removed_decl, D->isDeprecated()); +} + // This is first pass on two given SDKNode trees. This pass removes the common part // of two versions of SDK, leaving only the changed part. class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { @@ -1074,7 +1091,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { SDKContext &Ctx; UpdatedNodesMap &UpdateMap; - llvm::StringSet<> ProtocolReqWhitelist; + llvm::StringSet<> ProtocolReqAllowlist; SDKNodeRoot *LeftRoot; SDKNodeRoot *RightRoot; @@ -1123,10 +1140,10 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { public: PrunePass(SDKContext &Ctx): Ctx(Ctx), UpdateMap(Ctx.getNodeUpdateMap()) {} - PrunePass(SDKContext &Ctx, llvm::StringSet<> prWhitelist): + PrunePass(SDKContext &Ctx, llvm::StringSet<> prAllowlist): Ctx(Ctx), UpdateMap(Ctx.getNodeUpdateMap()), - ProtocolReqWhitelist(std::move(prWhitelist)) {} + ProtocolReqAllowlist(std::move(prAllowlist)) {} void diagnoseMissingAvailable(SDKNodeDecl *D) { // For extensions of external types, we diagnose individual member's missing @@ -1178,7 +1195,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { ShouldComplain = false; } if (ShouldComplain && - ProtocolReqWhitelist.count(getParentProtocolName(D))) { + ProtocolReqAllowlist.count(getParentProtocolName(D))) { // Ignore protocol requirement additions if the protocol has been added // to the allowlist. ShouldComplain = false; @@ -1241,7 +1258,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { TD->isProtocol()); } if (auto *Acc = dyn_cast(Left)) { - Acc->emitDiag(SourceLoc(), diag::removed_decl, Acc->isDeprecated()); + diagnoseRemovedDecl(Acc); } return; case NodeMatchReason::FuncToProperty: @@ -2084,7 +2101,7 @@ static bool diagnoseRemovedExtensionMembers(const SDKNode *Node) { if (DT->isExtension()) { for (auto *C: DT->getChildren()) { auto *MD = cast(C); - MD->emitDiag(SourceLoc(), diag::removed_decl, MD->isDeprecated()); + diagnoseRemovedDecl(MD); } return true; } @@ -2161,7 +2178,7 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) { } bool handled = diagnoseRemovedExtensionMembers(Node); if (!handled) - Node->emitDiag(SourceLoc(), diag::removed_decl, Node->isDeprecated()); + diagnoseRemovedDecl(Node); return; } case NodeAnnotation::Rename: { @@ -2309,9 +2326,52 @@ createDiagConsumer(llvm::raw_ostream &OS, bool &FailOnError) { } } +static int readFileLineByLine(StringRef Path, llvm::StringSet<> &Lines) { + auto FileBufOrErr = llvm::MemoryBuffer::getFile(Path); + if (!FileBufOrErr) { + llvm::errs() << "error opening file '" << Path << "': " + << FileBufOrErr.getError().message() << '\n'; + return 1; + } + + StringRef BufferText = FileBufOrErr.get()->getBuffer(); + while (!BufferText.empty()) { + StringRef Line; + std::tie(Line, BufferText) = BufferText.split('\n'); + Line = Line.trim(); + if (Line.empty()) + continue; + if (Line.startswith("// ")) // comment. + continue; + Lines.insert(Line); + } + return 0; +} + +static bool readBreakageAllowlist(SDKContext &Ctx, llvm::StringSet<> &lines) { + if (options::BreakageAllowlistPath.empty()) + return 0; + CompilerInstance instance; + CompilerInvocation invok; + invok.setModuleName("ForClangImporter"); + if (instance.setup(invok)) + return 1; + auto importer = ClangImporter::create(instance.getASTContext()); + SmallString<128> preprocessedFilePath; + if (auto error = llvm::sys::fs::createTemporaryFile( + "breakage-allowlist-", "txt", preprocessedFilePath)) { + return 1; + } + if (importer->runPreprocessor(options::BreakageAllowlistPath, + preprocessedFilePath.str())) { + return 1; + } + return readFileLineByLine(preprocessedFilePath, lines); +} + static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule, SDKNodeRoot *RightModule, StringRef OutputPath, - llvm::StringSet<> ProtocolReqWhitelist) { + llvm::StringSet<> ProtocolReqAllowlist) { assert(LeftModule); assert(RightModule); llvm::raw_ostream *OS = &llvm::errs(); @@ -2326,28 +2386,33 @@ static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule, OS = FileOS.get(); } bool FailOnError; - std::unique_ptr pConsumer = - createDiagConsumer(*OS, FailOnError); - + auto allowedBreakages = std::make_unique>(); + if (readBreakageAllowlist(Ctx, *allowedBreakages)) { + Ctx.getDiags().diagnose(SourceLoc(), diag::cannot_read_allowlist, + options::BreakageAllowlistPath); + } + auto pConsumer = std::make_unique( + createDiagConsumer(*OS, FailOnError), std::move(allowedBreakages)); + SWIFT_DEFER { pConsumer->finishProcessing(); }; Ctx.addDiagConsumer(*pConsumer); Ctx.setCommonVersion(std::min(LeftModule->getJsonFormatVersion(), RightModule->getJsonFormatVersion())); TypeAliasDiffFinder(LeftModule, RightModule, Ctx.getTypeAliasUpdateMap()).search(); - PrunePass Prune(Ctx, std::move(ProtocolReqWhitelist)); + PrunePass Prune(Ctx, std::move(ProtocolReqAllowlist)); Prune.pass(LeftModule, RightModule); ChangeRefinementPass RefinementPass(Ctx.getNodeUpdateMap()); RefinementPass.pass(LeftModule, RightModule); // Find member hoist changes to help refine diagnostics. findTypeMemberDiffs(LeftModule, RightModule, Ctx.getTypeMemberDiffs()); DiagnosisEmitter::diagnosis(LeftModule, RightModule, Ctx); - return FailOnError && Ctx.getDiags().hadAnyError() ? 1 : 0; + return FailOnError && pConsumer->hasError() ? 1 : 0; } static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath, StringRef OutputPath, CheckerOptions Opts, - llvm::StringSet<> ProtocolReqWhitelist) { + llvm::StringSet<> ProtocolReqAllowlist) { if (!fs::exists(LeftPath)) { llvm::errs() << LeftPath << " does not exist\n"; return 1; @@ -2361,9 +2426,8 @@ static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath, LeftCollector.deSerialize(LeftPath); SwiftDeclCollector RightCollector(Ctx); RightCollector.deSerialize(RightPath); - diagnoseModuleChange(Ctx, LeftCollector.getSDKRoot(), RightCollector.getSDKRoot(), - OutputPath, std::move(ProtocolReqWhitelist)); - return options::CompilerStyleDiags && Ctx.getDiags().hadAnyError() ? 1 : 0; + return diagnoseModuleChange(Ctx, LeftCollector.getSDKRoot(), + RightCollector.getSDKRoot(), OutputPath, std::move(ProtocolReqAllowlist)); } static void populateAliasChanges(NodeMap &AliasMap, DiffVector &AllItems, @@ -2482,28 +2546,6 @@ static int generateMigrationScript(StringRef LeftPath, StringRef RightPath, return 0; } -static int readFileLineByLine(StringRef Path, llvm::StringSet<> &Lines) { - auto FileBufOrErr = llvm::MemoryBuffer::getFile(Path); - if (!FileBufOrErr) { - llvm::errs() << "error opening file '" << Path << "': " - << FileBufOrErr.getError().message() << '\n'; - return 1; - } - - StringRef BufferText = FileBufOrErr.get()->getBuffer(); - while (!BufferText.empty()) { - StringRef Line; - std::tie(Line, BufferText) = BufferText.split('\n'); - Line = Line.trim(); - if (Line.empty()) - continue; - if (Line.startswith("// ")) // comment. - continue; - Lines.insert(Line); - } - return 0; -} - // This function isn't referenced outside its translation unit, but it // can't use the "static" keyword because its address is used for // getMainExecutable (since some platforms don't support taking the @@ -2548,6 +2590,8 @@ static int prepareForDump(const char *Main, InitInvok.getLangOptions().Target.isOSDarwin(); InitInvok.getClangImporterOptions().ModuleCachePath = options::ModuleCachePath; + // Module recovery issue shouldn't bring down the tool. + InitInvok.getLangOptions().AllowDeserializingImplementationOnly = true; if (!options::SwiftVersion.empty()) { using version::Version; @@ -2661,7 +2705,7 @@ static CheckerOptions getCheckOpts(int argc, char *argv[]) { Opts.ToolArgs.push_back(argv[i]); if (!options::SDK.empty()) { - auto Ver = getSDKVersion(options::SDK); + auto Ver = getSDKBuildVersion(options::SDK); if (!Ver.empty()) { Opts.ToolArgs.push_back("-sdk-version"); Opts.ToolArgs.push_back(Ver); @@ -2805,7 +2849,7 @@ static std::string getJsonOutputFilePath(llvm::Triple Triple, bool ABI) { exit(1); } llvm::sys::path::append(OutputPath, getBaselineFilename(Triple)); - return OutputPath.str(); + return OutputPath.str().str(); } llvm::errs() << "Unable to decide output file path\n"; exit(1); @@ -2835,9 +2879,9 @@ int main(int argc, char *argv[]) { case ActionType::MigratorGen: case ActionType::DiagnoseSDKs: { ComparisonInputMode Mode = checkComparisonInputMode(); - llvm::StringSet<> protocolWhitelist; - if (!options::ProtReqWhiteList.empty()) { - if (readFileLineByLine(options::ProtReqWhiteList, protocolWhitelist)) + llvm::StringSet<> protocolAllowlist; + if (!options::ProtReqAllowList.empty()) { + if (readFileLineByLine(options::ProtReqAllowList, protocolAllowlist)) return 1; } if (options::Action == ActionType::MigratorGen) { @@ -2851,21 +2895,21 @@ int main(int argc, char *argv[]) { return diagnoseModuleChange(options::SDKJsonPaths[0], options::SDKJsonPaths[1], options::OutputFile, Opts, - std::move(protocolWhitelist)); + std::move(protocolAllowlist)); } case ComparisonInputMode::BaselineJson: { SDKContext Ctx(Opts); return diagnoseModuleChange(Ctx, getBaselineFromJson(argv[0], Ctx), getSDKRoot(argv[0], Ctx, false), options::OutputFile, - std::move(protocolWhitelist)); + std::move(protocolAllowlist)); } case ComparisonInputMode::BothLoad: { SDKContext Ctx(Opts); return diagnoseModuleChange(Ctx, getSDKRoot(argv[0], Ctx, true), getSDKRoot(argv[0], Ctx, false), options::OutputFile, - std::move(protocolWhitelist)); + std::move(protocolAllowlist)); } } } diff --git a/tools/swift-def-to-yaml-converter/CMakeLists.txt b/tools/swift-def-to-yaml-converter/CMakeLists.txt new file mode 100644 index 0000000000000..558a737c8257e --- /dev/null +++ b/tools/swift-def-to-yaml-converter/CMakeLists.txt @@ -0,0 +1,7 @@ +add_swift_host_tool(swift-def-to-yaml-converter + swift-def-to-yaml-converter.cpp + SWIFT_COMPONENT tools +) + +target_link_libraries(swift-def-to-yaml-converter PRIVATE + swiftLocalization) diff --git a/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp new file mode 100644 index 0000000000000..0d49088111374 --- /dev/null +++ b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp @@ -0,0 +1,102 @@ +//===--- swift-def-to-yaml-converter.cpp ----------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Create a YAML file from the diagnostic messages text in `.def` files. +// +//===----------------------------------------------------------------------===// + +#include "swift/Basic/LLVMInitialize.h" +#include "swift/Localization/LocalizationFormat.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include + +static constexpr const char *const diagnosticID[] = { +#define DIAG(KIND, ID, Options, Text, Signature) #ID, +#include "swift/AST/DiagnosticsAll.def" +}; + +static constexpr const char *const diagnosticMessages[] = { +#define DIAG(KIND, ID, Options, Text, Signature) Text, +#include "swift/AST/DiagnosticsAll.def" +}; + +enum LocalDiagID : uint32_t { +#define DIAG(KIND, ID, Options, Text, Signature) ID, +#include "swift/AST/DiagnosticsAll.def" + NumDiags +}; + +namespace options { + +static llvm::cl::OptionCategory Category("swift-def-to-yaml-converter Options"); + +static llvm::cl::opt + OutputDirectory("output-directory", + llvm::cl::desc("Directory for the output file"), + llvm::cl::cat(Category)); + +static llvm::cl::opt + OutputFilename("output-filename", + llvm::cl::desc("Filename for the output file"), + llvm::cl::cat(Category)); + +} // namespace options + +int main(int argc, char *argv[]) { + PROGRAM_START(argc, argv); + + llvm::cl::HideUnrelatedOptions(options::Category); + llvm::cl::ParseCommandLineOptions(argc, argv, + "Swift `.def` to YAML Converter\n"); + + llvm::SmallString<128> LocalizedFilePath; + if (options::OutputFilename.empty()) { + // The default language for localization is English + std::string defaultLocaleCode = "en"; + LocalizedFilePath = options::OutputDirectory; + llvm::sys::path::append(LocalizedFilePath, defaultLocaleCode); + llvm::sys::path::replace_extension(LocalizedFilePath, ".yaml"); + } else { + LocalizedFilePath = options::OutputFilename; + } + + std::error_code error; + llvm::raw_fd_ostream OS(LocalizedFilePath.str(), error, + llvm::sys::fs::F_None); + + if (OS.has_error() || error) { + llvm::errs() << "Error has occurred while trying to write to " + << LocalizedFilePath.str() + << " with error code: " << error.message() << "\n"; + return EXIT_FAILURE; + } + + llvm::ArrayRef ids(diagnosticID, LocalDiagID::NumDiags); + llvm::ArrayRef messages(diagnosticMessages, + LocalDiagID::NumDiags); + + swift::diag::DefToYAMLConverter converter(ids, messages); + converter.convert(OS); + + return EXIT_SUCCESS; +} diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index 691318b4885db..a17fba4f13646 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -829,7 +829,7 @@ static bool doCodeCompletionImpl( CompletionInstance CompletionInst; auto isSuccess = CompletionInst.performOperation( Invocation, /*Args=*/{}, llvm::vfs::getRealFileSystem(), CleanFile.get(), - Offset, /*EnableASTCaching=*/false, Error, + Offset, Error, CodeCompletionDiagnostics ? &PrintDiags : nullptr, [&](CompilerInstance &CI, bool reusingASTContext) { assert(!reusingASTContext && "reusing AST context without enabling it"); @@ -1207,8 +1207,7 @@ static int doBatchCodeCompletion(const CompilerInvocation &InitInvok, bool wasASTContextReused = false; bool isSuccess = CompletionInst.performOperation( Invocation, /*Args=*/{}, FileSystem, completionBuffer.get(), Offset, - /*EnableASTCaching=*/true, Error, - CodeCompletionDiagnostics ? &PrintDiags : nullptr, + Error, CodeCompletionDiagnostics ? &PrintDiags : nullptr, [&](CompilerInstance &CI, bool reusingASTContext) { // Create a CodeCompletionConsumer. std::unique_ptr Consumer( diff --git a/tools/swift-inspect/Sources/swift-inspect/Inspector.swift b/tools/swift-inspect/Sources/swift-inspect/Inspector.swift index 80f3668f111b3..05b77192adf68 100644 --- a/tools/swift-inspect/Sources/swift-inspect/Inspector.swift +++ b/tools/swift-inspect/Sources/swift-inspect/Inspector.swift @@ -121,8 +121,10 @@ private func QueryDataLayoutFn(context: UnsafeMutableRawPointer?, type: DataLayoutQueryType, inBuffer: UnsafeMutableRawPointer?, outBuffer: UnsafeMutableRawPointer?) -> CInt { + let is64 = MemoryLayout.stride == 8 + switch type { - case DLQ_GetPointerSize: + case DLQ_GetPointerSize, DLQ_GetSizeSize: let size = UInt8(MemoryLayout.stride) outBuffer!.storeBytes(of: size, toByteOffset: 0, as: UInt8.self) return 1 @@ -130,6 +132,26 @@ private func QueryDataLayoutFn(context: UnsafeMutableRawPointer?, let mask = GetPtrauthMask() outBuffer!.storeBytes(of: mask, toByteOffset: 0, as: UInt.self) return 1 + case DLQ_GetObjCReservedLowBits: + var size: UInt8 = 0 +#if os(macOS) + // The low bit is reserved only on 64-bit macOS. + if is64 { + size = 1 + } +#endif + outBuffer!.storeBytes(of: size, toByteOffset: 0, as: UInt8.self) + return 1 + case DLQ_GetLeastValidPointerValue: + var value: UInt64 = 0x1000 +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) + // 64-bit Apple platforms reserve the low 4GB. + if is64 { + value = 0x100000000 + } +#endif + outBuffer!.storeBytes(of: value, toByteOffset: 0, as: UInt64.self) + return 1 default: return 0 } diff --git a/tools/swift-llvm-opt/LLVMOpt.cpp b/tools/swift-llvm-opt/LLVMOpt.cpp index a1db84b4edc35..bd01da64bda25 100644 --- a/tools/swift-llvm-opt/LLVMOpt.cpp +++ b/tools/swift-llvm-opt/LLVMOpt.cpp @@ -36,7 +36,7 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeWriterPass.h" -#include "llvm/CodeGen/CommandFlags.inc" +#include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" @@ -68,6 +68,8 @@ using namespace swift; +static llvm::codegen::RegisterCodeGenFlags CGF; + //===----------------------------------------------------------------------===// // Option Declarations //===----------------------------------------------------------------------===// @@ -96,19 +98,19 @@ static llvm::cl::opt PrintStats("print-stats", llvm::cl::desc("Should LLVM Statistics be printed")); -static cl::opt InputFilename(cl::Positional, - cl::desc(""), - cl::init("-"), - cl::value_desc("filename")); +static llvm::cl::opt InputFilename(llvm::cl::Positional, + llvm::cl::desc(""), + llvm::cl::init("-"), + llvm::cl::value_desc("filename")); -static cl::opt OutputFilename("o", - cl::desc("Override output filename"), - cl::value_desc("filename")); +static llvm::cl::opt + OutputFilename("o", llvm::cl::desc("Override output filename"), + llvm::cl::value_desc("filename")); -static cl::opt DefaultDataLayout( +static llvm::cl::opt DefaultDataLayout( "default-data-layout", - cl::desc("data layout string to use if not specified by module"), - cl::value_desc("layout-string"), cl::init("")); + llvm::cl::desc("data layout string to use if not specified by module"), + llvm::cl::value_desc("layout-string"), llvm::cl::init("")); //===----------------------------------------------------------------------===// // Helper Methods @@ -117,8 +119,8 @@ static cl::opt DefaultDataLayout( static llvm::CodeGenOpt::Level GetCodeGenOptLevel() { // TODO: Is this the right thing to do here? if (Optimized) - return CodeGenOpt::Default; - return CodeGenOpt::None; + return llvm::CodeGenOpt::Default; + return llvm::CodeGenOpt::None; } // Returns the TargetMachine instance or zero if no triple is provided. @@ -126,8 +128,8 @@ static llvm::TargetMachine * getTargetMachine(llvm::Triple TheTriple, StringRef CPUStr, StringRef FeaturesStr, const llvm::TargetOptions &Options) { std::string Error; - const auto *TheTarget = - llvm::TargetRegistry::lookupTarget(MArch, TheTriple, Error); + const auto *TheTarget = llvm::TargetRegistry::lookupTarget( + llvm::codegen::getMArch(), TheTriple, Error); // Some modules don't specify a triple, and this is okay. if (!TheTarget) { return nullptr; @@ -135,12 +137,13 @@ getTargetMachine(llvm::Triple TheTriple, StringRef CPUStr, return TheTarget->createTargetMachine( TheTriple.getTriple(), CPUStr, FeaturesStr, Options, - Optional(RelocModel), getCodeModel(), GetCodeGenOptLevel()); + Optional(llvm::codegen::getExplicitRelocModel()), + llvm::codegen::getExplicitCodeModel(), GetCodeGenOptLevel()); } static void dumpOutput(llvm::Module &M, llvm::raw_ostream &os) { // For now just always dump assembly. - legacy::PassManager EmitPasses; + llvm::legacy::PassManager EmitPasses; EmitPasses.add(createPrintModulePass(os)); EmitPasses.run(M); } @@ -152,11 +155,12 @@ static void dumpOutput(llvm::Module &M, llvm::raw_ostream &os) { // without being given the address of a function in the main executable). void anchorForGetMainExecutable() {} -static inline void addPass(legacy::PassManagerBase &PM, Pass *P) { +static inline void addPass(llvm::legacy::PassManagerBase &PM, llvm::Pass *P) { // Add the pass to the pass manager... PM.add(P); if (P->getPassID() == &SwiftAAWrapperPass::ID) { - PM.add(createExternalAAWrapperPass([](Pass &P, Function &, AAResults &AAR) { + PM.add(llvm::createExternalAAWrapperPass([](llvm::Pass &P, llvm::Function &, + llvm::AAResults &AAR) { if (auto *WrapperPass = P.getAnalysisIfAvailable()) AAR.addAAResult(WrapperPass->getResult()); })); @@ -164,7 +168,7 @@ static inline void addPass(legacy::PassManagerBase &PM, Pass *P) { // If we are verifying all of the intermediate steps, add the verifier... if (VerifyEach) - PM.add(createVerifierPass()); + PM.add(llvm::createVerifierPass()); } static void runSpecificPasses(StringRef Binary, llvm::Module *M, @@ -172,7 +176,7 @@ static void runSpecificPasses(StringRef Binary, llvm::Module *M, llvm::Triple &ModuleTriple) { llvm::legacy::PassManager Passes; llvm::TargetLibraryInfoImpl TLII(ModuleTriple); - Passes.add(new TargetLibraryInfoWrapperPass(TLII)); + Passes.add(new llvm::TargetLibraryInfoWrapperPass(TLII)); const llvm::DataLayout &DL = M->getDataLayout(); if (DL.isDefault() && !DefaultDataLayout.empty()) { @@ -180,13 +184,13 @@ static void runSpecificPasses(StringRef Binary, llvm::Module *M, } // Add internal analysis passes from the target machine. - Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis() - : TargetIRAnalysis())); + Passes.add(createTargetTransformInfoWrapperPass( + TM ? TM->getTargetIRAnalysis() : llvm::TargetIRAnalysis())); if (TM) { // FIXME: We should dyn_cast this when supported. - auto <M = static_cast(*TM); - Pass *TPC = LTM.createPassConfig(Passes); + auto <M = static_cast(*TM); + llvm::Pass *TPC = LTM.createPassConfig(Passes); Passes.add(TPC); } @@ -195,8 +199,9 @@ static void runSpecificPasses(StringRef Binary, llvm::Module *M, if (PassInfo->getNormalCtor()) P = PassInfo->getNormalCtor()(); else - errs() << Binary << ": cannot create pass: " << PassInfo->getPassName() - << "\n"; + llvm::errs() << Binary + << ": cannot create pass: " << PassInfo->getPassName() + << "\n"; if (P) { addPass(Passes, P); } @@ -215,7 +220,7 @@ int main(int argc, char **argv) { INITIALIZE_LLVM(); // Initialize passes - PassRegistry &Registry = *PassRegistry::getPassRegistry(); + llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry(); initializeCore(Registry); initializeScalarOpts(Registry); initializeObjCARCOpts(Registry); @@ -252,16 +257,16 @@ int main(int argc, char **argv) { // Load the input module... auto LLVMContext = std::make_unique(); - std::unique_ptr M = + std::unique_ptr M = parseIRFile(InputFilename, Err, *LLVMContext.get()); if (!M) { - Err.print(argv[0], errs()); + Err.print(argv[0], llvm::errs()); return 1; } - if (verifyModule(*M, &errs())) { - errs() << argv[0] << ": " << InputFilename + if (verifyModule(*M, &llvm::errs())) { + llvm::errs() << argv[0] << ": " << InputFilename << ": error: input module is broken!\n"; return 1; } @@ -280,18 +285,19 @@ int main(int argc, char **argv) { Out.reset( new llvm::ToolOutputFile(OutputFilename, EC, llvm::sys::fs::F_None)); if (EC) { - errs() << EC.message() << '\n'; + llvm::errs() << EC.message() << '\n'; return 1; } llvm::Triple ModuleTriple(M->getTargetTriple()); std::string CPUStr, FeaturesStr; llvm::TargetMachine *Machine = nullptr; - const llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); + const llvm::TargetOptions Options = + llvm::codegen::InitTargetOptionsFromCodeGenFlags(); if (ModuleTriple.getArch()) { - CPUStr = getCPUStr(); - FeaturesStr = getFeaturesStr(); + CPUStr = llvm::codegen::getCPUStr(); + FeaturesStr = llvm::codegen::getFeaturesStr(); Machine = getTargetMachine(ModuleTriple, CPUStr, FeaturesStr, Options); } @@ -299,7 +305,7 @@ int main(int argc, char **argv) { // Override function attributes based on CPUStr, FeaturesStr, and command line // flags. - setFunctionAttributes(CPUStr, FeaturesStr, *M); + llvm::codegen::setFunctionAttributes(CPUStr, FeaturesStr, *M); if (Optimized) { IRGenOptions Opts; diff --git a/tools/swift-reflection-dump/swift-reflection-dump.cpp b/tools/swift-reflection-dump/swift-reflection-dump.cpp index c06ec35de5f81..ab6472dcdf206 100644 --- a/tools/swift-reflection-dump/swift-reflection-dump.cpp +++ b/tools/swift-reflection-dump/swift-reflection-dump.cpp @@ -583,25 +583,28 @@ class ObjectMemoryReader : public MemoryReader { using ReflectionContextOwner = std::unique_ptr; -template -static std::pair -makeReflectionContextForMetadataReader( - std::shared_ptr reader) { +struct ReflectionContextHolder { + ReflectionContextOwner Owner; + TypeRefBuilder &Builder; + ObjectMemoryReader &Reader; +}; + +template +static ReflectionContextHolder makeReflectionContextForMetadataReader( + std::shared_ptr reader) { using ReflectionContext = ReflectionContext; auto context = new ReflectionContext(reader); auto &builder = context->getBuilder(); for (unsigned i = 0, e = reader->getImages().size(); i < e; ++i) { context->addImage(reader->getImageStartAddress(i)); } - return {ReflectionContextOwner(context, - [](void *x){ delete (ReflectionContext*)x; }), - builder}; + return {ReflectionContextOwner( + context, [](void *x) { delete (ReflectionContext *)x; }), + builder, *reader}; } - -static std::pair -makeReflectionContextForObjectFiles( - const std::vector &objectFiles) { +static ReflectionContextHolder makeReflectionContextForObjectFiles( + const std::vector &objectFiles) { auto Reader = std::make_shared(objectFiles); uint8_t pointerSize; @@ -651,7 +654,7 @@ static int doDumpReflectionSections(ArrayRef BinaryFilenames, } auto context = makeReflectionContextForObjectFiles(ObjectFiles); - auto &builder = context.second; + auto &builder = context.Builder; switch (Action) { case ActionType::DumpReflectionSections: @@ -668,15 +671,18 @@ static int doDumpReflectionSections(ArrayRef BinaryFilenames, Demangle::Demangler Dem; auto Demangled = Dem.demangleType(Line); - auto *TypeRef = - swift::Demangle::decodeMangledType(builder, Demangled); - if (TypeRef == nullptr) { - fprintf(file, "Invalid typeref:%s\n", Line.c_str()); + auto Result = swift::Demangle::decodeMangledType(builder, Demangled); + if (Result.isError()) { + auto *error = Result.getError(); + char *str = error->copyErrorString(); + fprintf(file, "Invalid typeref:%s - %s\n", Line.c_str(), str); + error->freeErrorString(str); continue; } + auto TypeRef = Result.getType(); TypeRef->dump(file); - auto *TypeInfo = builder.getTypeConverter().getTypeInfo(TypeRef); + auto *TypeInfo = builder.getTypeConverter().getTypeInfo(TypeRef, nullptr); if (TypeInfo == nullptr) { fprintf(file, "Invalid lowering\n"); continue; diff --git a/tools/swift-serialize-diagnostics/CMakeLists.txt b/tools/swift-serialize-diagnostics/CMakeLists.txt index 13cf756c13c49..4a1ab49b59ed3 100644 --- a/tools/swift-serialize-diagnostics/CMakeLists.txt +++ b/tools/swift-serialize-diagnostics/CMakeLists.txt @@ -2,6 +2,5 @@ add_swift_host_tool(swift-serialize-diagnostics swift-serialize-diagnostics.cpp SWIFT_COMPONENT tools ) -target_link_libraries(swift-serialize-diagnostics - PRIVATE - swiftAST) +target_link_libraries(swift-serialize-diagnostics PRIVATE + swiftLocalization) diff --git a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp index 01ea696002637..03b0118f2eef4 100644 --- a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp +++ b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp @@ -14,9 +14,9 @@ // //===----------------------------------------------------------------------===// -#include "swift/AST/LocalizationFormat.h" #include "swift/Basic/LLVMInitialize.h" #include "swift/Basic/STLExtras.h" +#include "swift/Localization/LocalizationFormat.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" diff --git a/tools/swift-syntax-test/swift-syntax-test.cpp b/tools/swift-syntax-test/swift-syntax-test.cpp index 7edcaae19779c..c492162111927 100644 --- a/tools/swift-syntax-test/swift-syntax-test.cpp +++ b/tools/swift-syntax-test/swift-syntax-test.cpp @@ -610,7 +610,6 @@ int parseFile( Invocation.getLangOptions().VerifySyntaxTree = options::VerifySyntaxTree; Invocation.getLangOptions().RequestEvaluatorGraphVizPath = options::GraphVisPath; Invocation.getLangOptions().DisablePoundIfEvaluation = true; - Invocation.getLangOptions().EnableExperimentalConcurrency = true; Invocation.getFrontendOptions().InputsAndOutputs.addInputFile(InputFileName); diff --git a/unittests/AST/TestContext.cpp b/unittests/AST/TestContext.cpp index 7b86295f5c179..174cf90630097 100644 --- a/unittests/AST/TestContext.cpp +++ b/unittests/AST/TestContext.cpp @@ -34,8 +34,8 @@ static Decl *createOptionalType(ASTContext &ctx, SourceFile *fileForLookups, } TestContext::TestContext(ShouldDeclareOptionalTypes optionals) - : Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SearchPathOpts, SourceMgr, - Diags)) { + : Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SearchPathOpts, + ClangImporterOpts, SourceMgr, Diags)) { registerParseRequestFunctions(Ctx.evaluator); registerTypeCheckerRequestFunctions(Ctx.evaluator); auto stdlibID = Ctx.getIdentifier(STDLIB_NAME); diff --git a/unittests/AST/TestContext.h b/unittests/AST/TestContext.h index 46aa8d985b62b..328f7a5ac598f 100644 --- a/unittests/AST/TestContext.h +++ b/unittests/AST/TestContext.h @@ -17,6 +17,8 @@ #include "swift/Basic/LangOptions.h" #include "swift/Basic/SourceManager.h" +#include "llvm/Support/Host.h" + namespace swift { namespace unittest { @@ -29,6 +31,7 @@ class TestContextBase { LangOptions LangOpts; TypeCheckerOptions TypeCheckerOpts; SearchPathOptions SearchPathOpts; + ClangImporterOptions ClangImporterOpts; SourceManager SourceMgr; DiagnosticEngine Diags; diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 0aa744d919f6c..5c6daa804cff8 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -9,6 +9,7 @@ if(SWIFT_INCLUDE_TOOLS) add_subdirectory(ClangImporter) add_subdirectory(Driver) add_subdirectory(FrontendTool) + add_subdirectory(Localization) add_subdirectory(IDE) add_subdirectory(Parse) add_subdirectory(SwiftDemangle) diff --git a/unittests/ClangImporter/ClangImporterTests.cpp b/unittests/ClangImporter/ClangImporterTests.cpp index e353fba57745f..94e46f4cee09b 100644 --- a/unittests/ClangImporter/ClangImporterTests.cpp +++ b/unittests/ClangImporter/ClangImporterTests.cpp @@ -5,7 +5,6 @@ #include "swift/Basic/LangOptions.h" #include "swift/Basic/SourceManager.h" #include "swift/ClangImporter/ClangImporter.h" -#include "swift/ClangImporter/ClangImporterOptions.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -75,8 +74,9 @@ TEST(ClangImporterTest, emitPCHInMemory) { swift::SourceManager sourceMgr; swift::DiagnosticEngine diags(sourceMgr); std::unique_ptr context( - ASTContext::get(langOpts, typeckOpts, searchPathOpts, sourceMgr, diags)); - auto importer = ClangImporter::create(*context, options); + ASTContext::get(langOpts, typeckOpts, searchPathOpts, options, + sourceMgr, diags)); + auto importer = ClangImporter::create(*context); std::string PCH = createFilename(cache, "bridging.h.pch"); ASSERT_FALSE(importer->canReadPCH(PCH)); diff --git a/unittests/FrontendTool/ModuleLoadingTests.cpp b/unittests/FrontendTool/ModuleLoadingTests.cpp index 7e343aaeeeab1..0d80267cd90a9 100644 --- a/unittests/FrontendTool/ModuleLoadingTests.cpp +++ b/unittests/FrontendTool/ModuleLoadingTests.cpp @@ -98,8 +98,10 @@ class ModuleInterfaceLoaderTest : public testing::Test { LangOptions langOpts; langOpts.Target = llvm::Triple(llvm::sys::getDefaultTargetTriple()); SearchPathOptions searchPathOpts; + ClangImporterOptions clangImpOpts; auto ctx = - ASTContext::get(langOpts, typeckOpts, searchPathOpts, sourceMgr, diags); + ASTContext::get(langOpts, typeckOpts, searchPathOpts, clangImpOpts, + sourceMgr, diags); auto loader = ModuleInterfaceLoader::create( *ctx, cacheDir, prebuiltCacheDir, @@ -116,7 +118,7 @@ class ModuleInterfaceLoaderTest : public testing::Test { loader->findModuleFilesInDirectory({moduleName, SourceLoc()}, SerializedModuleBaseName(tempDir, SerializedModuleBaseName("Library")), /*ModuleInterfacePath*/nullptr, - &moduleBuffer, &moduleDocBuffer, &moduleSourceInfoBuffer); + &moduleBuffer, &moduleDocBuffer, &moduleSourceInfoBuffer, /*IsFramework*/false); ASSERT_FALSE(error); ASSERT_FALSE(diags.hadAnyError()); diff --git a/unittests/IDE/CMakeLists.txt b/unittests/IDE/CMakeLists.txt index f55846dd2c6ad..607a574214a71 100644 --- a/unittests/IDE/CMakeLists.txt +++ b/unittests/IDE/CMakeLists.txt @@ -1,5 +1,6 @@ add_swift_unittest(SwiftIDETests CodeCompletionToken.cpp + FuzzyStringMatcherTest.cpp Placeholders.cpp ) target_link_libraries(SwiftIDETests diff --git a/unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp b/unittests/IDE/FuzzyStringMatcherTest.cpp similarity index 99% rename from unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp rename to unittests/IDE/FuzzyStringMatcherTest.cpp index e0e7e83b4220c..e190933fcd988 100644 --- a/unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp +++ b/unittests/IDE/FuzzyStringMatcherTest.cpp @@ -10,10 +10,10 @@ // //===----------------------------------------------------------------------===// -#include "SourceKit/Support/FuzzyStringMatcher.h" +#include "swift/IDE/FuzzyStringMatcher.h" #include "gtest/gtest.h" -using FuzzyStringMatcher = SourceKit::FuzzyStringMatcher; +using FuzzyStringMatcher = swift::ide::FuzzyStringMatcher; TEST(FuzzyStringMatcher, BasicMatching) { { diff --git a/unittests/Localization/CMakeLists.txt b/unittests/Localization/CMakeLists.txt new file mode 100644 index 0000000000000..618d892709403 --- /dev/null +++ b/unittests/Localization/CMakeLists.txt @@ -0,0 +1,10 @@ +add_swift_unittest(swiftLocalizationTests + DefToYAMLConverterTests.cpp + SerializationTests.cpp) + +target_link_libraries(swiftLocalizationTests + PRIVATE + swiftLocalization) + +target_compile_definitions(swiftLocalizationTests PRIVATE + SWIFTLIB_DIR=\"${SWIFTLIB_DIR}\") diff --git a/unittests/Localization/DefToYAMLConverterTests.cpp b/unittests/Localization/DefToYAMLConverterTests.cpp new file mode 100644 index 0000000000000..1683537cdb05b --- /dev/null +++ b/unittests/Localization/DefToYAMLConverterTests.cpp @@ -0,0 +1,80 @@ +//===--- DefToYAMLConverterTests.cpp -------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "LocalizationTest.h" +#include "swift/Localization/LocalizationFormat.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" +#include +#include +#include +#include + +using namespace swift; +using namespace swift::diag; +using namespace swift::unittests; + +static std::string getMainExecutablePath() { + llvm::StringRef libPath = llvm::sys::path::parent_path(SWIFTLIB_DIR); + llvm::SmallString<128> MainExecutablePath(libPath); + llvm::sys::path::remove_filename(MainExecutablePath); // Remove /lib + llvm::sys::path::remove_filename(MainExecutablePath); // Remove /. + return std::string(MainExecutablePath); +} + +static std::string getDefaultLocalizationPath() { + llvm::SmallString<128> DefaultDiagnosticMessagesDir(getMainExecutablePath()); + llvm::sys::path::append(DefaultDiagnosticMessagesDir, "share", "swift", + "diagnostics"); + return std::string(DefaultDiagnosticMessagesDir); +} + +TEST_F(LocalizationTest, MissingLocalizationFiles) { + ASSERT_TRUE(llvm::sys::fs::exists(getDefaultLocalizationPath())); + llvm::SmallString<128> EnglishLocalization(getDefaultLocalizationPath()); + llvm::sys::path::append(EnglishLocalization, "en"); + llvm::sys::path::replace_extension(EnglishLocalization, ".yaml"); + ASSERT_TRUE(llvm::sys::fs::exists(EnglishLocalization)); + llvm::sys::path::replace_extension(EnglishLocalization, ".db"); + ASSERT_TRUE(llvm::sys::fs::exists(EnglishLocalization)); +} + +TEST_F(LocalizationTest, ConverterTestMatchDiagnosticMessagesSequentially) { + YAMLLocalizationProducer yaml(YAMLPath); + yaml.forEachAvailable([](swift::DiagID id, llvm::StringRef translation) { + llvm::StringRef msg = diagnosticMessages[static_cast(id)]; + ASSERT_EQ(msg, translation); + }); +} + +TEST_F(LocalizationTest, ConverterTestMatchDiagnosticMessagesRandomly) { + YAMLLocalizationProducer yaml(YAMLPath); + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> distr(50, LocalDiagID::NumDiags); + unsigned numberOfQueries = distr(gen); + while (numberOfQueries--) { + unsigned randomNum = RandNumber(LocalDiagID::NumDiags); + DiagID randomId = static_cast(randomNum); + llvm::StringRef msg = diagnosticMessages[randomNum]; + llvm::StringRef translation = yaml.getMessageOr(randomId, ""); + ASSERT_EQ(msg, translation); + } +} diff --git a/unittests/Localization/LocalizationTest.h b/unittests/Localization/LocalizationTest.h new file mode 100644 index 0000000000000..865f998088cb3 --- /dev/null +++ b/unittests/Localization/LocalizationTest.h @@ -0,0 +1,98 @@ +//===--- LocalizationTest.h - Helper for setting up locale tests -*- C++-*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef LOCALIZATION_TEST_H +#define LOCALIZATION_TEST_H + +#include "swift/Localization/LocalizationFormat.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace swift::diag; + +namespace swift { +namespace unittests { + +enum LocalDiagID : uint32_t { +#define DIAG(KIND, ID, Options, Text, Signature) ID, +#include "swift/AST/DiagnosticsAll.def" + NumDiags +}; + +static constexpr const char *const diagnosticID[] = { +#define DIAG(KIND, ID, Options, Text, Signature) #ID, +#include "swift/AST/DiagnosticsAll.def" +}; + +static constexpr const char *const diagnosticMessages[] = { +#define DIAG(KIND, ID, Options, Text, Signature) Text, +#include "swift/AST/DiagnosticsAll.def" +}; + +struct LocalizationTest : public ::testing::Test { + std::string YAMLPath; + + LocalizationTest() { + YAMLPath = std::string(createTemporaryFile("en", "yaml")); + } + + void SetUp() override { + bool failed = convertDefIntoYAML(YAMLPath); + assert(!failed && "failed to generate a YAML file"); + } + + static std::string createTemporaryFile(std::string prefix, + std::string suffix) { + llvm::SmallString<128> tempFile; + std::error_code error = + llvm::sys::fs::createTemporaryFile(prefix, suffix, tempFile); + assert(!error); + llvm::sys::RemoveFileOnSignal(tempFile); + return std::string(tempFile); + } + + /// Random number in [0,n) + unsigned RandNumber(unsigned n) { return unsigned(rand()) % n; } + +protected: + static bool convertDefIntoYAML(std::string outputPath) { + std::error_code error; + llvm::raw_fd_ostream OS(outputPath, error, llvm::sys::fs::F_None); + if (OS.has_error() || error) + return true; + + llvm::ArrayRef ids(diagnosticID, LocalDiagID::NumDiags); + llvm::ArrayRef messages(diagnosticMessages, + LocalDiagID::NumDiags); + + DefToYAMLConverter converter(ids, messages); + converter.convert(OS); + + OS.flush(); + + return OS.has_error(); + } +}; + +} // end namespace unittests +} // end namespace swift + +#endif diff --git a/unittests/Localization/SerializationTests.cpp b/unittests/Localization/SerializationTests.cpp new file mode 100644 index 0000000000000..5eea041977759 --- /dev/null +++ b/unittests/Localization/SerializationTests.cpp @@ -0,0 +1,113 @@ +//===--- LocalizationProducerTests.cpp -------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "LocalizationTest.h" +#include "swift/Localization/LocalizationFormat.h" +#include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" +#include +#include + +using namespace swift::diag; +using namespace swift::unittests; + +TEST_F(LocalizationTest, TestYAMLSerialization) { + YAMLLocalizationProducer yaml(YAMLPath); + + auto dbFile = createTemporaryFile("en", "db"); + + // First, let's serialize English translations + { + SerializedLocalizationWriter writer; + + yaml.forEachAvailable([&writer](swift::DiagID id, llvm::StringRef translation) { + writer.insert(id, translation); + }); + + ASSERT_FALSE(writer.emit(dbFile)); + } + + // Now, let's make sure that serialized version matches "source" YAML + auto dbContent = llvm::MemoryBuffer::getFile(dbFile); + ASSERT_TRUE(dbContent); + + SerializedLocalizationProducer db(std::move(dbContent.get())); + yaml.forEachAvailable([&db](swift::DiagID id, llvm::StringRef translation) { + ASSERT_EQ(translation, db.getMessageOr(id, "")); + }); +} + +TEST_F(LocalizationTest, TestSerializationOfEmptyFile) { + auto dbFile = createTemporaryFile("by", "db"); + SerializedLocalizationWriter writer; + ASSERT_FALSE(writer.emit(dbFile)); + + YAMLLocalizationProducer yaml(YAMLPath); + + // Reading of the empty `db` file should always return default message. + { + auto dbContent = llvm::MemoryBuffer::getFile(dbFile); + ASSERT_TRUE(dbContent); + + SerializedLocalizationProducer db(std::move(dbContent.get())); + yaml.forEachAvailable([&db](swift::DiagID id, llvm::StringRef translation) { + ASSERT_EQ("<<>>", + db.getMessageOr(id, "<<>>")); + }); + } +} + +TEST_F(LocalizationTest, TestSerializationWithGaps) { + // Initially all of the messages are included. + llvm::SmallBitVector includedMessages(LocalDiagID::NumDiags, true); + + // Let's punch some holes in the diagnostic content. + for (unsigned i = 0, n = 200; i != n; ++i) { + unsigned position = RandNumber(LocalDiagID::NumDiags); + includedMessages.flip(position); + } + + YAMLLocalizationProducer yaml(YAMLPath); + auto dbFile = createTemporaryFile("en", "db"); + + { + SerializedLocalizationWriter writer; + + yaml.forEachAvailable([&](swift::DiagID id, llvm::StringRef translation) { + if (includedMessages.test((unsigned)id)) + writer.insert(id, translation); + }); + + ASSERT_FALSE(writer.emit(dbFile)); + } + + + { + auto dbContent = llvm::MemoryBuffer::getFile(dbFile); + ASSERT_TRUE(dbContent); + + SerializedLocalizationProducer db(std::move(dbContent.get())); + yaml.forEachAvailable([&](swift::DiagID id, llvm::StringRef translation) { + auto position = (unsigned)id; + + std::string expectedMessage = includedMessages.test(position) + ? std::string(translation) + : "<<>>"; + + ASSERT_EQ(expectedMessage, db.getMessageOr(id, "<<>>")); + }); + } +} diff --git a/unittests/SourceKit/Support/CMakeLists.txt b/unittests/SourceKit/Support/CMakeLists.txt index da17a059b87b3..54cbdce081c87 100644 --- a/unittests/SourceKit/Support/CMakeLists.txt +++ b/unittests/SourceKit/Support/CMakeLists.txt @@ -1,5 +1,4 @@ add_swift_unittest(SourceKitSupportTests - FuzzyStringMatcherTest.cpp ImmutableTextBufferTest.cpp ) diff --git a/unittests/runtime/CompatibilityOverride.cpp b/unittests/runtime/CompatibilityOverride.cpp index 2dece35195619..6056f26117930 100644 --- a/unittests/runtime/CompatibilityOverride.cpp +++ b/unittests/runtime/CompatibilityOverride.cpp @@ -35,8 +35,8 @@ namespace { return MetadataResponse{nullptr, MetadataState::Complete}; } - template<> - TypeInfo getEmptyValue() { + template <> + TypeLookupErrorOr getEmptyValue>() { return TypeInfo(); } } @@ -168,22 +168,17 @@ TEST_F(CompatibilityOverrideTest, test_swift_conformsToProtocol) { ASSERT_EQ(Result, nullptr); } -TEST_F(CompatibilityOverrideTest, test_swift_conformsToSwiftProtocol) { - auto Result = swift_conformsToSwiftProtocol(nullptr, nullptr, StringRef()); - ASSERT_EQ(Result, nullptr); -} - TEST_F(CompatibilityOverrideTest, test_swift_getTypeByMangledNode) { Demangler demangler; auto Result = swift_getTypeByMangledNode(MetadataState::Abstract, demangler, nullptr, nullptr, nullptr,nullptr); - ASSERT_EQ(Result.getMetadata(), nullptr); + ASSERT_EQ(Result.getType().getMetadata(), nullptr); } TEST_F(CompatibilityOverrideTest, test_swift_getTypeByMangledName) { auto Result = swift_getTypeByMangledName(MetadataState::Abstract, "", nullptr, nullptr, nullptr); - ASSERT_EQ(Result.getMetadata(), nullptr); + ASSERT_EQ(Result.getType().getMetadata(), nullptr); } TEST_F(CompatibilityOverrideTest, test_swift_getAssociatedTypeWitnessSlow) { diff --git a/unittests/runtime/Concurrent.cpp b/unittests/runtime/Concurrent.cpp index 3f78805c53ff7..141b804f099d4 100644 --- a/unittests/runtime/Concurrent.cpp +++ b/unittests/runtime/Concurrent.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -13,6 +13,8 @@ #include "swift/Runtime/Concurrent.h" #include "gtest/gtest.h" +#include "ThreadingHelpers.h" + using namespace swift; TEST(ConcurrentReadableArrayTest, SingleThreaded) { @@ -42,3 +44,458 @@ TEST(ConcurrentReadableArrayTest, SingleThreaded) { add(1000000); check(); } + +TEST(ConcurrentReadableArrayTest, MultiThreaded) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 100000; + + struct Value { + int threadNumber; + int x; + }; + ConcurrentReadableArray array; + + // The writers will append values with their thread number and increasing + // values of x. + auto writer = [&](int threadNumber) { + for (int i = 0; i < insertCount; i++) + array.push_back({ threadNumber, i }); + }; + + auto reader = [&] { + // Track the maximum value we've seen for each writer thread. + int maxByThread[writerCount]; + bool done = false; + while (!done) { + for (int i = 0; i < writerCount; i++) + maxByThread[i] = -1; + for (auto element : array.snapshot()) { + ASSERT_LT(element.threadNumber, writerCount); + // Each element we see must be larger than the maximum element we've + // previously seen for that writer thread, otherwise that means that + // we're seeing mutations out of order. + ASSERT_GT(element.x, maxByThread[element.threadNumber]); + maxByThread[element.threadNumber] = element.x; + } + + // If the max for each thread is the max that'll be inserted, then we're + // done and should exit. + done = true; + for (int i = 0; i < writerCount; i++) { + if (maxByThread[i] < insertCount - 1) + done = false; + } + } + }; + + threadedExecute(writerCount + readerCount, [&](int i) { + if (i < writerCount) + writer(i); + else + reader(); + }); + + ASSERT_EQ(array.snapshot().count(), (size_t)writerCount * insertCount); +} + +TEST(ConcurrentReadableArrayTest, MultiThreaded2) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 100000; + + struct Value { + int threadNumber; + int x; + }; + ConcurrentReadableArray array; + + // The writers will append values with their thread number and increasing + // values of x. + auto writer = [&](int threadNumber) { + for (int i = 0; i < insertCount; i++) + array.push_back({ threadNumber, i }); + }; + + auto reader = [&] { + // Track the maximum value we've seen for each writer thread. + int maxByThread[writerCount]; + for (int i = 0; i < writerCount; i++) + maxByThread[i] = -1; + bool done = false; + while (!done) { + auto snapshot = array.snapshot(); + // Don't do anything until some data is actually added. + if (snapshot.count() == 0) + continue; + + // Grab the last element in the snapshot. + auto element = snapshot.begin()[snapshot.count() - 1]; + ASSERT_LT(element.threadNumber, writerCount); + // Each element we see must be equal to or larger than the maximum element + // we've previously seen for that writer thread, otherwise that means that + // we're seeing mutations out of order. + ASSERT_GE(element.x, maxByThread[element.threadNumber]); + maxByThread[element.threadNumber] = element.x; + + // We'll eventually see some thread add its maximum value. We'll call it + // done when we reach that point. + if (element.x == insertCount - 1) + done = true; + } + }; + + threadedExecute(writerCount + readerCount, [&](int i) { + if (i < writerCount) + writer(i); + else + reader(); + }); + + ASSERT_EQ(array.snapshot().count(), (size_t)writerCount * insertCount); +} + +struct SingleThreadedValue { + size_t key; + size_t x; + SingleThreadedValue(size_t key, size_t x) : key(key), x(x) {} + bool matchesKey(size_t key) { return this->key == key; } + friend llvm::hash_code hash_value(const SingleThreadedValue &value) { + return llvm::hash_value(value.key); + } +}; + +TEST(ConcurrentReadableHashMapTest, SingleThreaded) { + ConcurrentReadableHashMap map; + + auto permute = [](size_t value) { return value ^ 0x33333333U; }; + + auto add = [&](size_t limit) { + for (size_t i = 0; i < limit; i++) + map.getOrInsert(permute(i), + [&](SingleThreadedValue *value, bool created) { + if (created) + new (value) SingleThreadedValue(permute(i), i); + return true; + }); + }; + auto check = [&](size_t limit) { + auto snapshot = map.snapshot(); + ASSERT_EQ(snapshot.find((size_t)~0), nullptr); + for (size_t i = 0; i < limit; i++) { + auto *value = snapshot.find(permute(i)); + ASSERT_NE(value, nullptr); + ASSERT_EQ(permute(i), value->key); + ASSERT_EQ(i, value->x); + } + }; + + check(0); + add(1); + check(1); + add(16); + check(16); + add(100); + check(100); + add(1000); + check(1000); + add(1000000); + check(1000000); + + map.clear(); + check(0); + + add(1); + check(1); + map.clear(); + check(0); + + add(16); + check(16); + map.clear(); + check(0); + + add(100); + check(100); + map.clear(); + check(0); + + add(1000); + check(1000); + map.clear(); + check(0); + + add(1000000); + check(1000000); + map.clear(); + check(0); +} + +struct MultiThreadedKey { + int threadNumber; + int n; + friend llvm::hash_code hash_value(const MultiThreadedKey &value) { + return llvm::hash_combine(value.threadNumber, value.n); + } +}; + +struct MultiThreadedValue { + int threadNumber; + int n; + int x; + MultiThreadedValue(MultiThreadedKey key, int x) + : threadNumber(key.threadNumber), n(key.n), x(x) {} + bool matchesKey(const MultiThreadedKey &key) { + return threadNumber == key.threadNumber && n == key.n; + } + friend llvm::hash_code hash_value(const MultiThreadedValue &value) { + return llvm::hash_combine(value.threadNumber, value.n); + } +}; + +// Test simultaneous readers and writers. +TEST(ConcurrentReadableHashMapTest, MultiThreaded) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 10000; + + ConcurrentReadableHashMap map; + + // NOTE: The bizarre lambdas around the ASSERT_ statements works around the + // fact that these macros emit return statements, which conflict with our + // need to return true/false from these lambdas. Wrapping them in a lambda + // neutralizes the return. + + auto writer = [&](int threadNumber) { + // Insert half, then insert all, to test adding an existing key. + for (int i = 0; i < insertCount / 2; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, [&](MultiThreadedValue + *value, + bool created) { + [&] { ASSERT_TRUE(created); }(); + new (value) MultiThreadedValue(MultiThreadedKey{threadNumber, i}, i); + return true; + }); + // Test discarding a new entry. + for (int i = 0; i < insertCount; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, + [&](MultiThreadedValue *value, bool created) { + [&] { ASSERT_EQ(created, i >= insertCount / 2); }(); + return false; + }); + for (int i = 0; i < insertCount; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, [&](MultiThreadedValue + *value, + bool created) { + if (created) { + [&] { ASSERT_GE(i, insertCount / 2); }(); + new (value) MultiThreadedValue(MultiThreadedKey{threadNumber, i}, i); + } else { + [&] { ASSERT_LT(i, insertCount / 2); }(); + } + return true; + }); + }; + + auto reader = [&] { + bool done = false; + while (!done) { + done = true; + for (int threadNumber = 0; threadNumber < writerCount; threadNumber++) { + // Read from the top down. We should see zero or more missing entries, + // and then the rest are present. Any hole is a bug. + int firstSeen = -1; + auto snapshot = map.snapshot(); + for (int i = insertCount - 1; i >= 0; i--) { + MultiThreadedKey key = {threadNumber, i}; + const MultiThreadedValue *value = snapshot.find(key); + if (value) { + if (firstSeen == -1) + firstSeen = value->x; + ASSERT_EQ(value->x, i); + } else { + ASSERT_EQ(firstSeen, -1); + done = false; + } + } + } + } + }; + + threadedExecute(writerCount + readerCount, [&](int i) { + if (i < writerCount) + writer(i); + else + reader(); + }); +} + +// Test readers and writers while also constantly clearing the map. +TEST(ConcurrentReadableHashMapTest, MultiThreaded2) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 10000; + + ConcurrentReadableHashMap map; + + std::atomic writerDoneCount = {0}; + auto writer = [&](int threadNumber) { + for (int i = 0; i < insertCount; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, [&](MultiThreadedValue + *value, + bool created) { + [&] { ASSERT_TRUE(created); }(); + new (value) MultiThreadedValue(MultiThreadedKey{threadNumber, i}, i); + return true; + }); + writerDoneCount.fetch_add(1, std::memory_order_relaxed); + }; + + auto reader = [&] { + while (writerDoneCount.load(std::memory_order_relaxed) < writerCount) { + for (int threadNumber = 0; threadNumber < writerCount; threadNumber++) { + // Read from the top down. We should see a single contiguous region of + // entries. Multiple regions indicates a bug. + int firstSeen = -1; + int lastSeen = -1; + auto snapshot = map.snapshot(); + for (int i = insertCount - 1; i >= 0; i--) { + MultiThreadedKey key = {threadNumber, i}; + const MultiThreadedValue *value = snapshot.find(key); + if (value) { + if (firstSeen == -1) + firstSeen = value->x; + if (lastSeen != -1) + ASSERT_EQ(lastSeen, i + 1); + lastSeen = value->x; + ASSERT_EQ(value->x, i); + } + } + } + } + }; + + auto clear = [&] { + while (writerDoneCount.load(std::memory_order_relaxed) < writerCount) { + map.clear(); + } + }; + + threadedExecute(writerCount + readerCount + 1, [&](int i) { + if (i < writerCount) + writer(i); + else if (i < writerCount + readerCount) + reader(); + else + clear(); + }); +} + +// Test readers and writers, with readers taking lots of snapshots. +TEST(ConcurrentReadableHashMapTest, MultiThreaded3) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 10000; + + ConcurrentReadableHashMap map; + + std::atomic writerDoneCount = {0}; + auto writer = [&](int threadNumber) { + for (int i = 0; i < insertCount; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, [&](MultiThreadedValue + *value, + bool created) { + [&] { ASSERT_TRUE(created); }(); + new (value) MultiThreadedValue(MultiThreadedKey{threadNumber, i}, i); + return true; + }); + writerDoneCount.fetch_add(1, std::memory_order_relaxed); + }; + + auto reader = [&] { + while (writerDoneCount.load(std::memory_order_relaxed) < writerCount) { + for (int threadNumber = 0; threadNumber < writerCount; threadNumber++) { + // Read from the top down. When we're not clearing the map, we should + // see zero or more missing entries, and then the rest are present. Any + // hole is a bug. + int firstSeen = -1; + int lastSeen = -1; + for (int i = insertCount - 1; i >= 0; i--) { + auto snapshot = map.snapshot(); + MultiThreadedKey key = {threadNumber, i}; + const MultiThreadedValue *value = snapshot.find(key); + if (value) { + if (firstSeen == -1) + firstSeen = value->x; + if (lastSeen != -1) + ASSERT_EQ(lastSeen, i + 1); + lastSeen = value->x; + ASSERT_EQ(value->x, i); + } + } + } + } + }; + + threadedExecute(writerCount + readerCount, [&](int i) { + if (i < writerCount) + writer(i); + else + reader(); + }); +} + +// Test readers and writers, with readers taking lots of snapshots, and +// simultaneous clearing. +TEST(ConcurrentReadableHashMapTest, MultiThreaded4) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 10000; + + ConcurrentReadableHashMap map; + + std::atomic writerDoneCount = {0}; + auto writer = [&](int threadNumber) { + for (int i = 0; i < insertCount; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, [&](MultiThreadedValue + *value, + bool created) { + [&] { ASSERT_TRUE(created); }(); + new (value) MultiThreadedValue(MultiThreadedKey{threadNumber, i}, i); + return true; + }); + writerDoneCount.fetch_add(1, std::memory_order_relaxed); + }; + + auto reader = [&] { + while (writerDoneCount.load(std::memory_order_relaxed) < writerCount) { + for (int threadNumber = 0; threadNumber < writerCount; threadNumber++) { + // With clearing, we can't expect any particular pattern. Just validate + // the values we do see, and make sure we don't crash. + for (int i = insertCount - 1; i >= 0; i--) { + auto snapshot = map.snapshot(); + MultiThreadedKey key = {threadNumber, i}; + const MultiThreadedValue *value = snapshot.find(key); + if (value) { + ASSERT_EQ(value->x, i); + } + } + } + } + }; + + auto clear = [&] { + while (writerDoneCount.load(std::memory_order_relaxed) < writerCount) { + map.clear(); + } + }; + + threadedExecute(writerCount + readerCount + 1, [&](int i) { + if (i < writerCount) + writer(i); + else if (i < writerCount + readerCount) + reader(); + else + clear(); + }); +} diff --git a/unittests/runtime/Mutex.cpp b/unittests/runtime/Mutex.cpp index 7d5dac159b923..eb634d5346449 100644 --- a/unittests/runtime/Mutex.cpp +++ b/unittests/runtime/Mutex.cpp @@ -16,125 +16,10 @@ #include #include #include -#include -using namespace swift; - -// When true many of the threaded tests log activity to help triage issues. -static bool trace = false; - -template -void threadedExecute(int threadCount, ThreadBody threadBody, - AfterSpinRelease afterSpinRelease) { - - std::vector threads; - - // Block the threads we are about to create. - std::atomic spinWait(true); - std::atomic readyCount(0); - std::atomic activeCount(0); - - for (int i = 0; i < threadCount; ++i) { - threads.push_back(std::thread([&, i] { - readyCount++; - - while (spinWait) { - std::this_thread::sleep_for(std::chrono::microseconds(10)); - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - activeCount++; - - threadBody(i); - })); - } - - while (readyCount < threadCount) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - // Allow our threads to fight for the lock. - spinWait = false; - - while (activeCount < threadCount) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - afterSpinRelease(); - - // Wait until all of our threads have finished. - for (auto &thread : threads) { - thread.join(); - } -} - -template -void threadedExecute(int threadCount, ThreadBody threadBody) { - threadedExecute(threadCount, threadBody, [] {}); -} - -template -void threadedExecute(M &mutex, C &condition, bool &doneCondition, - ConsumerBody consumerBody, ProducerBody producerBody) { - - std::vector producers; - std::vector consumers; +#include "ThreadingHelpers.h" - // Block the threads we are about to create. - std::atomic spinWait(true); - - for (int i = 1; i <= 8; ++i) { - consumers.push_back(std::thread([&, i] { - while (spinWait) { - std::this_thread::sleep_for(std::chrono::microseconds(10)); - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - consumerBody(i); - - if (trace) - printf("### Consumer[%d] thread exiting.\n", i); - })); - } - - for (int i = 1; i <= 5; ++i) { - producers.push_back(std::thread([&, i] { - while (spinWait) { - std::this_thread::sleep_for(std::chrono::microseconds(10)); - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - producerBody(i); - - if (trace) - printf("### Producer[%d] thread exiting.\n", i); - })); - } - - // Poor mans attempt to get as many threads ready as possible before - // dropping spinWait, it doesn't have to be perfect. - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - // Allow our threads to fight for the lock. - spinWait = false; - - // Wait until all of our producer threads have finished. - for (auto &thread : producers) { - thread.join(); - } - - // Inform consumers that producers are done. - mutex.withLockThenNotifyAll(condition, [&] { - if (trace) - printf("### Informing consumers we are done.\n"); - doneCondition = true; - }); - - // Wait for consumers to finish. - for (auto &thread : consumers) { - thread.join(); - } -} +using namespace swift; // ----------------------------------------------------------------------------- diff --git a/unittests/runtime/ThreadingHelpers.h b/unittests/runtime/ThreadingHelpers.h new file mode 100644 index 0000000000000..667c847959744 --- /dev/null +++ b/unittests/runtime/ThreadingHelpers.h @@ -0,0 +1,134 @@ +//===--- Concurrent.cpp - Concurrent data structure tests -----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef THREADING_HELPERS_H +#define THREADING_HELPERS_H + +#include + +// When true many of the threaded tests log activity to help triage issues. +static bool trace = false; + +template +void threadedExecute(int threadCount, ThreadBody threadBody, + AfterSpinRelease afterSpinRelease) { + + std::vector threads; + + // Block the threads we are about to create. + std::atomic spinWait(true); + std::atomic readyCount(0); + std::atomic activeCount(0); + + for (int i = 0; i < threadCount; ++i) { + threads.push_back(std::thread([&, i] { + readyCount++; + + while (spinWait) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + activeCount++; + + threadBody(i); + })); + } + + while (readyCount < threadCount) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + // Allow our threads to fight for the lock. + spinWait = false; + + while (activeCount < threadCount) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + afterSpinRelease(); + + // Wait until all of our threads have finished. + for (auto &thread : threads) { + thread.join(); + } +} + +template +void threadedExecute(int threadCount, ThreadBody threadBody) { + threadedExecute(threadCount, threadBody, [] {}); +} + +template +void threadedExecute(M &mutex, C &condition, bool &doneCondition, + ConsumerBody consumerBody, ProducerBody producerBody) { + + std::vector producers; + std::vector consumers; + + // Block the threads we are about to create. + std::atomic spinWait(true); + + for (int i = 1; i <= 8; ++i) { + consumers.push_back(std::thread([&, i] { + while (spinWait) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + consumerBody(i); + + if (trace) + printf("### Consumer[%d] thread exiting.\n", i); + })); + } + + for (int i = 1; i <= 5; ++i) { + producers.push_back(std::thread([&, i] { + while (spinWait) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + producerBody(i); + + if (trace) + printf("### Producer[%d] thread exiting.\n", i); + })); + } + + // Poor mans attempt to get as many threads ready as possible before + // dropping spinWait, it doesn't have to be perfect. + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Allow our threads to fight for the lock. + spinWait = false; + + // Wait until all of our producer threads have finished. + for (auto &thread : producers) { + thread.join(); + } + + // Inform consumers that producers are done. + mutex.withLockThenNotifyAll(condition, [&] { + if (trace) + printf("### Informing consumers we are done.\n"); + doneCondition = true; + }); + + // Wait for consumers to finish. + for (auto &thread : consumers) { + thread.join(); + } +} + +#endif diff --git a/userdocs/diagnostics/nominal-types.md b/userdocs/diagnostics/nominal-types.md index a4a085308c9cd..bd3c55312ece5 100644 --- a/userdocs/diagnostics/nominal-types.md +++ b/userdocs/diagnostics/nominal-types.md @@ -1,6 +1,9 @@ -# Nominal types -In Swift, a type is considered a nominal type if it is named. In other words, it has been defined by declaring the type somewhere in code. Examples of nominal types include classes, structs and enums, all of which must be declared before using them. Nominal types are an important concept in Swift because they can be extended, explicitly initialized using the `MyType()` syntax, and may conform to protocols. +# Nominal Types -In contrast, non-nominal types have none of these capabilities. A non-nominal type is any type which is not nominal. They are sometimes called "structural types" because they are usually obtained by composing other types. Examples include function types like `(Int) -> (String)`, tuple types like `(Int, String)`, metatypes like `Int.Type`, and special types like `Any` and `AnyObject`. +In Swift, a type is considered a nominal type if it has been explicitly named by a declaration somewhere in code. Examples of nominal types include classes, structures and enumerations. Nominal types are an important concept in Swift because they may conform to protocols, be extended, and have values created using the initializer syntax `MyType()`. -Whether the name of a protocol refers to a nominal or non-nominal type depends on where it appears in code. When used in a declaration or extension like `extension MyProtocol { … }`, `MyProtocol` refers to a protocol type, which is nominal. This means that it may be extended and conform to protocols. However, when written as the type of a constant or variable, `MyProtocol` instead refers to a non-nominal, existential type. As a result, code like `let value: MyProtocol = MyProtocol()` is not allowed because `MyProtocol` refers to a non-nominal type in this context and cannot be explicitly initialized. +In contrast, non-nominal types do not have these capabilities. Many are obtained by composing other types. Examples include function types like `(Int) -> (String)`, tuple types like `(Int, String)`, metatypes like `Int.Type`, and special types like `Any` and `AnyObject`. + +Since a protocol is named by a declaration in code, it may conform to (in other words, refine) other protocols and it may be extended. However, when written as the type of a constant or variable such as `let value: MyProtocol`, the name refers to a distinct, non-nominal existential type that provides a "box" for a value of any concrete type that conforms to the protocol. The existential type itself does not conform to any protocols and cannot be extended, and a value cannot be created using the initializer syntax `MyProtocol()`. + +For more on using existential types, see [Protocols as Types](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID275) in _The Swift Programming Language_. \ No newline at end of file diff --git a/userdocs/diagnostics/protocol-type-non-conformance.md b/userdocs/diagnostics/protocol-type-non-conformance.md index 47cc95193a130..11771460941e1 100644 --- a/userdocs/diagnostics/protocol-type-non-conformance.md +++ b/userdocs/diagnostics/protocol-type-non-conformance.md @@ -1,46 +1,92 @@ -# Protocol type not conforming to itself -Protocols in Swift may be used as types. Protocols as types are sometimes called existential types. +# Protocol Types Cannot Conform to Protocols +In Swift, a protocol that does not have `Self` or associated type requirements can be used as a type. You can use a variable or constant of a protocol type, also called an __existential type__, to hold a value of any conforming type: ```swift -protocol P {} - -struct S: P {} +protocol Animal { + func makeNoise() + static var species: String { get } +} +struct Dog: Animal { + func makeNoise() { print("Woof") } + static var species: String = "Canus familiaris" +} +struct Cat: Animal { + func makeNoise() { print("Meow") } + static var species: String = "Felis catus" +} -var s: P = S() // This creates existential type because the protocol P is used as a type +var animal: Animal // `Animal` is used here as a type. +animal = Dog() +animal.makeNoise() // Prints "Woof". +animal = Cat() +animal.makeNoise() // Prints "Meow". ``` -However, a protocol type does not conform to protocols - not even the protocol itself. -Allowing existential types to conform to protocols is unsound. For protocols with static method, initializer, or associated type requirements, the implementation of these requirements cannot be accessed from the protocol type - accessing these kinds of requirements must be done using a concrete type. +Notice that it is possible to invoke the method `makeNoise()` on a value of type `Animal`, just as it is possible to do so on a value of concrete type `Dog` or `Cat`. However, the static property `species` is not available for the existential type: + +```swift +print(Dog.species) // Prints "Canus familiaris" +print(Cat.species) // Prints "Felis catus" +print(Animal.species) // error: static member 'species' cannot be used... +``` -Let's walk through the example below: +Since a type conforms to a protocol only when it satisfies _all_ of that protocol's requirements, the existential type `Animal` does not conform to the protocol `Animal` because it cannot satisfy the protocol's requirement for the static property `species`: ```swift -protocol Word: Hashable { - var word: String { get } +func declareAnimalSpecies(_ animal: T) { + animal.makeNoise() + print("My species is known as \(T.species)") } -struct Singular: Word { - var word: String -} +let dog = Dog() +declareAnimalSpecies(dog) +// Prints: +// "Woof" +// "My species is known as Canus familiaris" +declareAnimalSpecies(animal) +// error: protocol type 'Animal' cannot conform to 'Animal'... +``` -struct Plural: Word { - var word: String -} +In general, any initializers, static members, and associated types required by a protocol can be used only via conforming concrete types. Although Swift allows a protocol that requires initializers or static members to be used as a type, that type _does not and cannot_ conform to the protocol itself. -let singularWord = Singular(word: "mango") -let pluralWord = Plural(word: "mangoes") +Currently, even if a protocol `P` requires no initializers or static members, the existential type `P` does not conform to `P` (with exceptions below). This restriction allows library authors to add such requirements (initializers or static members) to an existing protocol without breaking their users' source code. -let wordPairDict: [Word: Word] = [singularWord: pluralWord] // Error -``` +## Exceptions -One workaround to fix this problem is to use type erasure for the protocol `Word`. Think of type erasure as a way to hide an object's type. Since `Word` is of type `Hashable`, we already have `AnyHashable` type erasure available in the standard library which we can easily use here. +When used as a type, the Swift protocol `Error` conforms to itself; `@objc` protocols with no static requirements can also be used as types that conform to themselves. -```swift -// The fix -let wordPairDict: [AnyHashable: AnyHashable] = [singularWord: pluralWord] +## Alternatives + +Concrete types that _do_ conform to protocols can provide functionality similar to that of existential types. For example, the standard library provides the `AnyHashable` type for `Hashable` values. Manual implementation of such __type erasure__ can require specific knowledge of the semantic requirements for each protocol involved and is beyond the scope of this discussion. + +In certain scenarios, you might avoid any need for manual type erasure by reworking generic APIs to use existential types instead: + +```swift +func declareAnimalSpeciesDynamically(_ animal: Animal) { + animal.makeNoise() + print("My species is known as \(type(of: animal).species)") +} + +declareAnimalSpeciesDynamically(animal) +// Prints: +// "Meow" +// "My species is known as Felis catus" ``` -# Exceptions -`@objc` protocol type with no static requirements however do conform to its own protocol. Another exception is the `Error` Swift protocol. +(Note that there is a distinction between the _static_ type of a value as given by the generic parameter `T` and the _dynamic_ type of a value obtained by invoking `type(of:)`. For example, the static type of `animal` is `Animal`, while its dynamic type is `Cat`. Therefore, the two functions `declareAnimalSpecies(_:)` and `declareAnimalSpeciesDynamically(_:)` are not exact replacements of each other.) + +The same technique might be applicable to members of generic types: + +```swift +// Instead of... +struct Habitat { + var animal: T +} +// ...consider: +struct Habitat { + var animal: Animal +} +``` +For more on using existential types, see [Protocols as Types](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID275) in _The Swift Programming Language_. diff --git a/userdocs/diagnostics/trailing-closure-matching.md b/userdocs/diagnostics/trailing-closure-matching.md index d373191f27839..f1ce7c0fdf939 100644 --- a/userdocs/diagnostics/trailing-closure-matching.md +++ b/userdocs/diagnostics/trailing-closure-matching.md @@ -1,102 +1,110 @@ # Argument Matching for Trailing Closures -In Swift, calling a function with one or more trailing closure arguments requires the label of the first trailing closure argument to be omitted. As a result, the compiler must consider additional context when determining which function parameter the trailing closure should satisfy. - -Before Swift 5.3, the compiler used a backward scanning rule to match a trailing closure to a function parameter. Starting from the end of the parameter list, it moved backwards until finding a parameter which could accept a trailing closure argument (a function type, unconstrained generic parameter, `Any`, etc.). This could sometimes lead to unexpected behavior. Consider the following example: +Where trailing closures are used to pass one or more arguments to a function, the argument label for the first trailing closure is always omitted: ```swift func animate( withDuration duration: Double, animations: () -> Void, completion: (() -> Void)? = nil -) {} +) { /* ... */ } -// OK -animate(withDuration: 0.3, animations: { /* Animate Something */ }) { - // Done! +animate(withDuration: 0.3) /* `animations:` is unwritten. */ { + // Animate something. +} completion: { + // Completion handler. } +``` -// error: missing argument for parameter 'animations' in call +Sometimes, an unlabeled trailing closure argument can be matched to more than one function parameter. Before Swift 5.3, the compiler would use a __backward scanning rule__ to match the unlabeled trailing closure, scanning backwards from the end of the parameter list until finding a parameter that can accept a closure argument (a function type, unconstrained generic type, `Any`, etc.): + +```swift animate(withDuration: 0.3) { - // Animate Something + // Animate something? + // The compiler matches this to the `completion` parameter. } +// error: missing argument for parameter 'animations' in call ``` -The second call to `animate` results in a compiler error because the backward scanning rule matches the trailing closure to the `completion` parameter instead of `animations`. +We encounter a compiler error in this example because the backward scanning rule matches the trailing closure to the `completion` parameter instead of the `animations` parameter, even though `completion` has a default value while `animations` does not. -Beginning in Swift 5.3, the compiler uses a new, forward scanning rule to match trailing closures to function parameters. When matching function arguments to parameters, the forward scan first matches all non-trailing arguments from left-to-right. Then, it continues matching trailing closures in a left-to-right manner. This leads to more predictable and easy-to-understand behavior in many situations. With the new rule, the example above now works as expected without any modifications: +Swift 5.3 introduces a new __forward scanning rule__, which matches trailing closures to function parameters from left to right (after matching non-trailing arguments). This leads to more predictable and easy-to-understand behavior in many situations. With the new rule, the unlabeled closure in the example above is matched to the `animations` parameter, just as most users would expect: ```swift -// Remains valid -animate(withDuration: 0.3, animations: { /* Animate Something */ }) { - // Done! -} - -// Also OK! animate(withDuration: 0.3) { - // Animate Something -} + // Animate something. +} // `completion` has the default value `nil`. ``` -When scanning forwards to match an unlabeled trailing closure argument, the compiler may sometimes need to "skip over" defaulted and variadic arguments. The new rule will skip any parameter that does not structurally resemble a function type. This allows writing a modified version of the above example where `withDuration` also has a default argument value: +When scanning forwards to match an unlabeled trailing closure argument, the compiler will skip any parameter that does not __structurally resemble__ a function type and also apply a __heuristic__ to skip parameters that do not require an argument in favor of a subsequent parameter that does (see below). These rules make possible the ergonomic use of a modified version of the API given in the example above, where `withDuration` has a default value: ```swift func animate( withDuration duration: Double = 1.0, animations: () -> Void, completion: (() -> Void)? = nil -) {} +) { /* ... */ } -// Allowed! The forward scanning rule skips `withDuration` because it does not -// structurally resemble a function type. animate { - // Animate Something + // Animate something. + // + // The closure is not matched to `withDuration` but to `animations` because + // the first parameter doesn't structurally resemble a function type. + // + // If, in place of `withDuration`, there is a parameter with a default value + // that does structurally resemble a function type, the closure would still be + // matched to `animations` because it requires an argument while the first + // parameter does not. } ``` +For source compatibility in Swift 5, the compiler will attempt to apply *both* the new forward scanning rule and the old backward scanning rule when it encounters a function call with a single trailing closure. If the forward and backward scans produce *different valid* matches of arguments to parameters, the compiler will prefer the result of the backward scanning rule and produce a warning. To silence this warning, rewrite the function call to label the argument explicitly without using trailing closure syntax. + +## Structural Resemblance to a Function Type + A parameter structurally resembles a function type if both of the following are true: -- The parameter is not `inout` -- The adjusted type of the parameter is a function type +- the parameter is not `inout`, and +- the __adjusted type__ of the parameter is a function type. The adjusted type of the parameter is the parameter's type as it appears in the function declaration, looking through any type aliases, and performing three additional adjustments: -- If the parameter is an `@autoclosure`, using the result type of the parameter's declared (function) type, before performing the second adjustment. -- If the parameter is variadic, looking at the base element type. -- Removing all outer "optional" types. +1. If the parameter is an `@autoclosure`, use the result type of the parameter's declared (function) type before performing the second adjustment. +2. If the parameter is variadic, look at the base element type. +3. Remove all outer "optional" types. + +## Heuristic for Skipping Parameters -To maintain source compatibility with code that was written before Swift 5.3, the forward scanning rule applies an additional heuristic when matching trailing closure arguments. If, +To maintain source compatibility, the forward scanning rule applies an additional heuristic when matching trailing closure arguments. If: - the parameter that would match an unlabeled trailing closure argument according to the forward scanning rule does not require an argument (because it is variadic or has a default argument), _and_ -- there are parameters _following_ that parameter that _do_ require an argument, which appear before the first parameter whose label matches that of the _next_ trailing closure (if any) +- there are parameters _following_ that parameter that _do_ require an argument, which appear before the first parameter whose label matches that of the _next_ trailing closure (if any), -then the compiler does not match the unlabeled trailing closure to that parameter. Instead, it skips it and examines the next parameter to see if that should be matched against the unlabeled trailing closure. This can be seen in the following example: +then the compiler does not match the unlabeled trailing closure to that parameter. Instead, it examines the next parameter to see if that should be matched to the unlabeled trailing closure, as in the following example: ```swift func showAlert( message: String, onPresentation: (() -> Void)? = nil, onDismissal: () -> Void -) {} +) { /* ... */ } -// The unlabeled trailing closure matches `onDismissal` because `onPresentation` -// does not require an argument, but `onDismissal` does and there are no other -// trailing closures which could match it. +// `onPresentation` does not require an argument, but `onDismissal` does, and +// there is no subsequent trailing closure labeled `onDismissal`. +// Therefore, the unlabeled trailing closure is matched to `onDismissal`. showAlert(message: "Hello, World!") { - // On dismissal action + // On dismissal action. } -// The unlabeled trailing closure matches `onPresentation` because although -// `onPresentation` does not require an argument, there are no parameters -// following it which require an argument and appear before the parameter -// whose label matches the next trailing closure argument (`onDismissal`). +// Although `onPresentation` does not require an argument, there are no +// subsequent parameters that require an argument before the parameter whose +// label matches the next trailing closure (`onDismissal`). +// Therefore, the unlabeled trailing closure is matched to `onPresentation`. showAlert(message: "Hello, World!") { - // On presentation action + // On presentation action. } onDismissal: { - // On dismissal action + // On dismissal action. } ``` -Additionally, the Swift 5 compiler will attempt to apply both the new forward scanning rule and the old backward scanning rule when it encounters a call with a single trailing closure. If the forward and backward scans produce *different* valid assignments of arguments to parameters, the compiler will prefer the result of the backward scanning rule and produce a warning. - To learn more about argument matching for trailing closures, see [Swift Evolution Proposal SE-0286](https://github.com/apple/swift-evolution/blob/master/proposals/0286-forward-scan-trailing-closures.md). diff --git a/utils/api_checker/dump-sdk.sh b/utils/api_checker/dump-sdk.sh new file mode 100755 index 0000000000000..5757eb23bdad4 --- /dev/null +++ b/utils/api_checker/dump-sdk.sh @@ -0,0 +1,65 @@ +#!/bin/bash +set -e + +DIR="$( cd "$( dirname "$0" )" && pwd )" +sh "$DIR/sdk-module-lists/create-module-lists.sh" + +MacSDKPath=$(xcrun -sdk macosx -show-sdk-path) +IphoneOSSDKPath=$(xcrun -sdk iphoneos -show-sdk-path) +AppleTVOSSDKPath=$(xcrun -sdk appletvos -show-sdk-path) +WathOSSDKPath=$(xcrun -sdk watchos -show-sdk-path) + +XCTestMac="$MacSDKPath/../../Library/Frameworks/" +XCTestIphone="$IphoneOSSDKPath/../../Library/Frameworks/" +XCTestTV="$AppleTVOSSDKPath/../../Library/Frameworks/" + +BASEDIR="$DIR/../../swift-sdk-digests/" + +mkdir -p "${BASEDIR}" + +DumpDir="/tmp/SDKDump" +rm -rf "/tmp/SDKDump" +mkdir "/tmp/SDKDump" + +XCODE_VER=$(xcodebuild -version | sed '1d' | sed 's/Build version //g') + +SWIFT_VER=${SWIFT_VER-3} +echo "SWIFT VERSION: ${SWIFT_VER}" + +function sdk_info() { + echo "Xcode Build: $XCODE_VER" + echo "macOS SDK Build: $(xcodebuild -version -sdk macosx ProductBuildVersion)" + echo "iOS SDK Build: $(xcodebuild -version -sdk iphoneos ProductBuildVersion)" + echo "watchOS SDK Build: $(xcodebuild -version -sdk watchos ProductBuildVersion)" + echo "tvOS SDK Build: $(xcodebuild -version -sdk appletvos ProductBuildVersion)" +} + +sdk_info + +XCODE_VER=-base-$SWIFT_VER + +if [[ -z "$MODULE" ]]; then + $SWIFT_API_DIGESTER -target x86_64-apple-macosx10.15 -o "$BASEDIR/macos$XCODE_VER.json" -dump-sdk -sdk "$MacSDKPath" -module-list-file "/tmp/modules-osx.txt" -F "$XCTestMac" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target arm64-apple-ios13.5 -o "$BASEDIR/ios$XCODE_VER.json" -dump-sdk -sdk "$IphoneOSSDKPath" -module-list-file "/tmp/modules-iphoneos.txt" -F "$XCTestIphone" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target arm64-apple-tvos13.4 -o "$BASEDIR/tvos$XCODE_VER.json" -dump-sdk -sdk "$AppleTVOSSDKPath" -module-list-file "/tmp/modules-tvos.txt" -F "$XCTestTV" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target armv7k-apple-watchos6.2 -o "$BASEDIR/watchos$XCODE_VER.json" -dump-sdk -sdk "$WathOSSDKPath" -module-list-file "/tmp/modules-watchos.txt" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target x86_64-apple-macosx10.15 -o "$BASEDIR/macos-stdlib$XCODE_VER.json" -dump-sdk -sdk "$MacSDKPath" -module Swift -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER +else + ALL_MODULE_DIR="$BASEDIR/Xcode$XCODE_VER" + rm -rf "$ALL_MODULE_DIR" + mkdir "$ALL_MODULE_DIR" + declare -a MODULE_NAMES=("Accelerate" "Foundation" "AppKit" "UIKit" "AudioToolbox" "Automator" "AVFoundation" + "AVKit" "CloudKit" "CoreBluetooth" "GameKit" "iAd" "Metal" "MetalKit" + "MetalPerformanceShaders" "OpenGLES" "Quartz" "XCTest" "UserNotifications" "CoreMedia" "VideoToolbox" "MediaToolbox" "MapKit") + for MODULE in "${MODULE_NAMES[@]}" + do + echo "Generating baseline for framework ${MODULE}" + MODULE_DIR="$ALL_MODULE_DIR/$MODULE" + rm -rf "$MODULE_DIR" + mkdir "$MODULE_DIR" + $SWIFT_API_DIGESTER -target x86_64-apple-macosx10.15 -o "$MODULE_DIR/macos.json" -dump-sdk -sdk "$MacSDKPath" -module "$MODULE" -F "$XCTestMac" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target arm64-apple-ios13.5 -o "$MODULE_DIR/ios.json" -dump-sdk -sdk "$IphoneOSSDKPath" -module "$MODULE" -F "$XCTestIphone" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target arm64-apple-tvos13.4 -o "$MODULE_DIR/tvos.json" -dump-sdk -sdk "$AppleTVOSSDKPath" -module "$MODULE" -F "$XCTestTV" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target armv7k-apple-watchos6.2 -o "$MODULE_DIR/watchos.json" -dump-sdk -sdk "$WathOSSDKPath" -module "$MODULE" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + done +fi diff --git a/utils/api_checker/sdk-module-lists/create-module-lists.sh b/utils/api_checker/sdk-module-lists/create-module-lists.sh new file mode 100755 index 0000000000000..c794567fcb043 --- /dev/null +++ b/utils/api_checker/sdk-module-lists/create-module-lists.sh @@ -0,0 +1,13 @@ +DIR="$( cd "$( dirname "$0" )" && pwd )" +$DIR/infer-imports.py -s $(xcrun --sdk macosx --show-sdk-path) > /tmp/modules-osx.txt && \ +$DIR/infer-imports.py -s $(xcrun --sdk iphoneos --show-sdk-path) > /tmp/modules-iphoneos.txt && \ +$DIR/infer-imports.py -s $(xcrun --sdk appletvos --show-sdk-path) > /tmp/modules-tvos.txt && \ +$DIR/infer-imports.py -s $(xcrun --sdk watchos --show-sdk-path) > /tmp/modules-watchos.txt && \ +cat $DIR/fixed-clang-modules-common.txt >> /tmp/modules-osx.txt && \ +cat $DIR/fixed-clang-modules-macosx.txt >> /tmp/modules-osx.txt && \ +cat $DIR/fixed-clang-modules-common.txt >> /tmp/modules-iphoneos.txt && \ +cat $DIR/fixed-clang-modules-iphoneos.txt >> /tmp/modules-iphoneos.txt && \ +cat $DIR/fixed-clang-modules-common.txt >> /tmp/modules-tvos.txt && \ +cat $DIR/fixed-clang-modules-appletvos.txt >> /tmp/modules-tvos.txt && \ +cat $DIR/fixed-clang-modules-common.txt >> /tmp/modules-watchos.txt && \ +cat $DIR/fixed-clang-modules-watchos.txt >> /tmp/modules-watchos.txt diff --git a/utils/api_checker/sdk-module-lists/fixed-clang-modules-appletvos.txt b/utils/api_checker/sdk-module-lists/fixed-clang-modules-appletvos.txt index 5154bd4dff5d3..7c352a57bb1d6 100644 --- a/utils/api_checker/sdk-module-lists/fixed-clang-modules-appletvos.txt +++ b/utils/api_checker/sdk-module-lists/fixed-clang-modules-appletvos.txt @@ -1 +1,3 @@ -XCTest \ No newline at end of file +XCTest +SceneKit.ModelIO +CoreImage.CIFilterBuiltins diff --git a/utils/api_checker/sdk-module-lists/fixed-clang-modules-iosmac.txt b/utils/api_checker/sdk-module-lists/fixed-clang-modules-iosmac.txt index d15abba59766b..bef2b6a46493e 100644 --- a/utils/api_checker/sdk-module-lists/fixed-clang-modules-iosmac.txt +++ b/utils/api_checker/sdk-module-lists/fixed-clang-modules-iosmac.txt @@ -1 +1,3 @@ // Empty +SceneKit.ModelIO +CoreImage.CIFilterBuiltins diff --git a/utils/api_checker/sdk-module-lists/fixed-clang-modules-iphoneos.txt b/utils/api_checker/sdk-module-lists/fixed-clang-modules-iphoneos.txt index 5154bd4dff5d3..7c352a57bb1d6 100644 --- a/utils/api_checker/sdk-module-lists/fixed-clang-modules-iphoneos.txt +++ b/utils/api_checker/sdk-module-lists/fixed-clang-modules-iphoneos.txt @@ -1 +1,3 @@ -XCTest \ No newline at end of file +XCTest +SceneKit.ModelIO +CoreImage.CIFilterBuiltins diff --git a/utils/api_checker/sdk-module-lists/fixed-clang-modules-macosx.txt b/utils/api_checker/sdk-module-lists/fixed-clang-modules-macosx.txt index 14aaee023d9ca..23fa920569b58 100644 --- a/utils/api_checker/sdk-module-lists/fixed-clang-modules-macosx.txt +++ b/utils/api_checker/sdk-module-lists/fixed-clang-modules-macosx.txt @@ -1,2 +1,4 @@ XPC XCTest +SceneKit.ModelIO +CoreImage.CIFilterBuiltins diff --git a/utils/api_checker/sdk-module-lists/infer-imports.py b/utils/api_checker/sdk-module-lists/infer-imports.py index a923c6b2f441c..c85348db9bcce 100755 --- a/utils/api_checker/sdk-module-lists/infer-imports.py +++ b/utils/api_checker/sdk-module-lists/infer-imports.py @@ -8,7 +8,8 @@ denylist = [ "Kernel", "Ruby", "Tk", "DriverKit", "HIDDriverKit", "SkywalkDriverKit", # has C++ code - "NetworkingDriverKit", "USBSerialDriverKit", # has C++ code + "NetworkingDriverKit", "USBSerialDriverKit", "PCIDriverKit", # has C++ code + "USBDriverKit", # has C++ code ] @@ -46,6 +47,8 @@ def get_frameworks(sdk_path, swift_frameworks_only): frameworks_path = sdk_path + "/System/Library/Frameworks" names = [] for frame in os.listdir(frameworks_path): + if frame[0] == '_': + continue if frame.endswith(".framework"): name = frame[:-len(".framework")] header_dir_path = frameworks_path + '/' + frame + '/Headers' @@ -106,8 +109,6 @@ def should_exclude_framework(frame_path): contents = open(module_map_path).read() if "requires !swift" in contents: return True - if "requires unavailable" in contents: - return True return False diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 630e4c7c7cb0f..c8346fbb83e7e 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -212,21 +212,6 @@ skip-test-ios-simulator skip-test-tvos-simulator skip-test-watchos-simulator -[preset: buildbot,tools=RA,stdlib=RD,single-thread] -mixin-preset= - mixin_buildbot_tools_RA_stdlib_RD - -dash-dash - -# Enable non-atomic build of the stdlib -swift-stdlib-use-nonatomic-rc=true - -# Don't run host tests for iOS, tvOS and watchOS platforms to make the build -# faster. -skip-test-ios-host -skip-test-tvos-host -skip-test-watchos-host - [preset: buildbot,tools=R,stdlib=RD] mixin-preset= mixin_buildbot_tools_R_stdlib_RD @@ -371,6 +356,7 @@ libcxx # Build llbuild & swiftpm here llbuild swiftpm +swift-driver indexstore-db sourcekit-lsp @@ -396,6 +382,7 @@ install-llvm install-swift install-llbuild install-swiftpm +install-swift-driver install-libcxx [preset: buildbot_incremental,tools=RA,stdlib=RA,xcode] @@ -418,6 +405,7 @@ swift-primary-variant-arch=x86_64 skip-build-llbuild skip-test-llbuild skip-test-swiftpm +skip-test-swift-driver skip-test-playgroundsupport # This preset is used by CI to test swift-corelibs-xctest. @@ -602,12 +590,14 @@ build-ninja libcxx llbuild swiftpm +swift-driver indexstore-db sourcekit-lsp install-llvm install-swift install-llbuild install-swiftpm +install-swift-driver install-libcxx # We need to build the unittest extras so we can test @@ -786,11 +776,12 @@ llvm-install-components=llvm-cov;llvm-profdata;IndexStore;clang;clang-resource-h [preset: mixin_linux_installation] mixin-preset= - mixin_lightweight_assertions + mixin_lightweight_assertions,no-stdlib-asserts mixin_linux_install_components_with_clang llbuild swiftpm +swift-driver xctest libicu libcxx @@ -803,6 +794,7 @@ install-swift install-lldb install-llbuild install-swiftpm +install-swift-driver install-xctest install-libicu install-prefix=/usr @@ -859,6 +851,7 @@ skip-test-lldb skip-test-swift skip-test-llbuild skip-test-swiftpm +skip-test-swift-driver skip-test-xctest skip-test-foundation skip-test-libdispatch @@ -1020,6 +1013,7 @@ lldb #test foundation swiftpm +swift-driver xctest build-subdir=buildbot_linux @@ -1032,6 +1026,7 @@ install-lldb install-llbuild install-foundation install-swiftpm +install-swift-driver install-xctest install-prefix=/usr swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;swift-remote-mirror;sdk-overlay;dev @@ -1079,6 +1074,7 @@ libcxx libicu llbuild swiftpm +swift-driver xctest foundation libdispatch @@ -1092,6 +1088,7 @@ install-swift install-llbuild install-libicu install-swiftpm +install-swift-driver install-foundation install-libdispatch install-xctest @@ -1195,6 +1192,7 @@ watchos lldb llbuild swiftpm +swift-driver swiftsyntax skstresstester swiftevolve @@ -1214,6 +1212,9 @@ compiler-vendor=apple dash-dash +# Cross compile for Apple Silicon +cross-compile-hosts=macosx-arm64 + lldb-no-debugserver lldb-use-system-debugserver lldb-build-type=Release @@ -1221,11 +1222,22 @@ verbose-build build-ninja build-swift-stdlib-unittest-extra +# When building for an Xcode toolchain, don't copy the Swift Resource/ directory +# into the LLDB.framework. LLDB.framework will be installed alongside a Swift +# compiler, so LLDB should use its resource directory directly. +# Also, to reduce the size of the final toolchain, limit debug info to be +# line-tables only. +extra-cmake-options= + -DLLDB_FRAMEWORK_COPY_SWIFT_RESOURCES=0 + -DCMAKE_C_FLAGS="-gline-tables-only" + -DCMAKE_CXX_FLAGS="-gline-tables-only" + install-llvm install-swift install-lldb install-llbuild install-swiftpm +install-swift-driver install-swiftsyntax install-skstresstester install-swiftevolve @@ -1268,6 +1280,7 @@ darwin-toolchain-display-name-short=%(darwin_toolchain_display_name_short)s darwin-toolchain-name=%(darwin_toolchain_xctoolchain_name)s darwin-toolchain-version=%(darwin_toolchain_version)s darwin-toolchain-alias=%(darwin_toolchain_alias)s +darwin-toolchain-require-use-os-runtime=0 [preset: mixin_osx_package_test] build-subdir=buildbot_osx @@ -1287,6 +1300,8 @@ lldb-test-swift-only # Path to the .tar.gz package we would create. installable-package=%(installable_package)s +[preset: mixin_osx_package,use_os_runtime]: +darwin-toolchain-require-use-os-runtime=1 [preset: buildbot_osx_package] mixin-preset= @@ -1294,6 +1309,13 @@ mixin-preset= mixin_osx_package_test mixin_lightweight_assertions,no-stdlib-asserts +# SKIP LLDB TESTS (67923799) +skip-test-lldb + +[preset: buildbot_osx_package,use_os_runtime] +mixin-preset= + buildbot_osx_package + mixin_osx_package,use_os_runtime [preset: buildbot_osx_package,no_assertions] mixin-preset= @@ -1304,12 +1326,20 @@ dash-dash no-assertions +[preset: buildbot_osx_package,no_assertions,use_os_runtime] +mixin-preset= + buildbot_osx_package,no_assertions + mixin_osx_package,use_os_runtime [preset: buildbot_osx_package,no_assertions,lto] mixin-preset=buildbot_osx_package,no_assertions lto +[preset: buildbot_osx_package,no_assertions,lto,use_os_runtime] +mixin-preset= + buildbot_osx_package,no_assertions,lto + mixin_osx_package,use_os_runtime [preset: buildbot_osx_package,no_assertions,no_test] mixin-preset= @@ -1319,6 +1349,7 @@ dash-dash skip-test-swift skip-test-swiftpm +skip-test-swift-driver skip-test-llbuild skip-test-lldb skip-test-cmark @@ -1327,6 +1358,10 @@ skip-test-swiftsyntax skip-test-skstresstester skip-test-swiftevolve +[preset: buildbot_osx_package,no_assertions,no_test,use_os_runtime] +mixin-preset= + buildbot_osx_package,no_assertions,no_test + mixin_osx_package,use_os_runtime # Debug version of the compilers, release version of the stdlib. [preset: buildbot_osx_package,tools=DA,stdlib=R] @@ -1340,16 +1375,15 @@ debug-llvm debug-swift no-swift-stdlib-assertions - -# macOS package with out test -[preset: buildbot_osx_package,no_test] +[preset: buildbot_osx_package,tools=DA,stdlib=R,use_os_runtime] mixin-preset= - buildbot_osx_package - -dash-dash + buildbot_osx_package,tools=DA,stdlib=R + mixin_osx_package,use_os_runtime +[preset: mixin_buildbot_osx_package,no_test] skip-test-swift skip-test-swiftpm +skip-test-swift-driver skip-test-llbuild skip-test-lldb skip-test-cmark @@ -1358,9 +1392,19 @@ skip-test-swiftsyntax skip-test-skstresstester skip-test-swiftevolve -extra-cmake-options= - -DCMAKE_C_FLAGS="-gline-tables-only" - -DCMAKE_CXX_FLAGS="-gline-tables-only" +# macOS package with out test +[preset: buildbot_osx_package,no_test] +mixin-preset= + buildbot_osx_package + mixin_buildbot_osx_package,no_test + +# macOS package without test that when linked against uses the OS runtime +# instead of the toolchain runtime. +[preset: buildbot_osx_package,no_test,use_os_runtime] +mixin-preset= + buildbot_osx_package + mixin_buildbot_osx_package,no_test + mixin_osx_package,use_os_runtime #===------------------------------------------------------------------------===# # LLDB build configurations @@ -1487,6 +1531,7 @@ libcxx # Build llbuild & swiftpm here llbuild swiftpm +swift-driver swiftsyntax # Don't generate the SwiftSyntax gyb files. Instead verify that up-to-date ones @@ -1500,6 +1545,7 @@ install-llvm install-swift install-llbuild install-swiftpm +install-swift-driver install-libcxx # Build the stress tester and SwiftEvolve @@ -1686,6 +1732,22 @@ assertions # Downstream projects that import llbuild+SwiftPM. sourcekit-lsp +#===------------------------------------------------------------------------===# +# Test Swift Driver (new) +#===------------------------------------------------------------------------===# + +[preset: buildbot_swift-driver_macos] +mixin-preset=mixin_swiftpm_package_macos_platform +release +assertions +swift-driver + +[preset: buildbot_swift-driver_linux] +mixin-preset=mixin_swiftpm_package_linux_platform +release +assertions +swift-driver + #===------------------------------------------------------------------------===# # Test Swift Syntax #===------------------------------------------------------------------------===# @@ -2365,6 +2427,48 @@ mixin-preset=stdlib_DA_standalone,build test validation-test +[preset: stdlib_S_standalone,build] +mixin-preset=stdlib_base_standalone + +build-subdir=stdlib_S_standalone +min-size-release +no-assertions + +verbose-build + +[preset: stdlib_SA_standalone,build] +mixin-preset=stdlib_base_standalone + +build-subdir=stdlib_SA_standalone +min-size-release +assertions + +verbose-build + +[preset: mixin_stdlib_minimal] +enable-experimental-differentiable-programming=0 +enable-experimental-concurrency=0 +build-swift-dynamic-sdk-overlay=0 +build-swift-dynamic-stdlib=0 +build-swift-static-stdlib=1 +swift-objc-interop=0 +swift-enable-compatibility-overrides=0 +swift-runtime-macho-no-dyld=1 +swift-stdlib-single-threaded-runtime=1 + +[preset: stdlib_S_standalone_minimal_macho_x86_64,build] +mixin-preset= + stdlib_S_standalone,build + mixin_stdlib_minimal + +stdlib-deployment-targets=freestanding-x86_64 +swift-primary-variant-sdk=FREESTANDING +swift-primary-variant-arch=x86_64 +swift-freestanding-sdk=macosx +# For now, until clang/swiftc works correctly with "none-macho" as the OS part of target triple. +swift-freestanding-triple-name=macosx11.0 +swift-freestanding-archs=x86_64 + #===----------------------------------------------------------------------===# # Preset for Source Compatibility Suite #===----------------------------------------------------------------------===# @@ -2373,10 +2477,12 @@ validation-test build-ninja llbuild swiftpm +swift-driver install-llbuild install-llvm install-swift install-swiftpm +install-swift-driver reconfigure verbose-build skip-build-benchmarks @@ -2419,21 +2525,25 @@ swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;s mixin-preset=source_compat_suite_macos_base debug assertions +cross-compile-hosts=macosx-arm64 [preset: source_compat_suite_macos_RA] mixin-preset=source_compat_suite_macos_base release assertions +cross-compile-hosts=macosx-arm64 [preset: source_compat_suite_macos_R] mixin-preset=source_compat_suite_macos_base release no-assertions +cross-compile-hosts=macosx-arm64 [preset: source_compat_suite_macos_D] mixin-preset=source_compat_suite_macos_base debug no-assertions +cross-compile-hosts=macosx-arm64 [preset: source_compat_suite_linux_DA] mixin-preset=source_compat_suite_linux_base @@ -2468,9 +2578,10 @@ skip-build-benchmarks llvm-targets-to-build=X86;AArch64;WebAssembly install-destdir=%(INSTALL_DESTDIR)s swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;sdk-overlay;parser-lib;editor-integration;tools;testsuite-tools;toolchain-tools;license;sourcekit-inproc;swift-remote-mirror;swift-remote-mirror-headers;clang-resource-dir-symlink -llvm-install-components=clang +llvm-install-components=clang;compiler-rt;lld;llvm-ar;llvm-ranlib install-swift install-prefix=/%(TOOLCHAIN_NAME)s/usr +swift-darwin-supported-archs=x86_64 [preset: webassembly-host] @@ -2512,6 +2623,8 @@ skip-test-xctest mixin-preset=webassembly wasm verbose +# Install lld, compiler-rt and clang +install-llvm build-stdlib-deployment-targets=wasi-wasm32 build-swift-dynamic-sdk-overlay=false build-swift-dynamic-stdlib=false @@ -2529,11 +2642,13 @@ extra-cmake-options= -DSWIFT_PRIMARY_VARIANT_SDK:STRING=WASI -DSWIFT_PRIMARY_VARIANT_ARCH:STRING=wasm32 -DSWIFT_SDKS='WASI;LINUX' + -DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME=TRUE -DSWIFT_BUILD_SOURCEKIT=FALSE -DSWIFT_ENABLE_SOURCEKIT_TESTS=FALSE -DSWIFT_BUILD_SYNTAXPARSERLIB=FALSE - -DCMAKE_AR="%(SOURCE_PATH)s/wasi-sdk/bin/llvm-ar" - -DCMAKE_RANLIB="%(SOURCE_PATH)s/wasi-sdk/bin/llvm-ranlib" + -DCMAKE_AR="%(TOOLS_BIN_DIR)s/llvm-ar" + -DCMAKE_RANLIB="%(TOOLS_BIN_DIR)s/llvm-ranlib" + -DCLANG_COMPILER_RT_CMAKE_ARGS='-DCMAKE_TOOLCHAIN_FILE=%(SOURCE_PATH)s/swift/utils/webassembly/compiler-rt-cache.cmake' -DSWIFTWASM_DISABLE_REFLECTION_TEST=TRUE [preset: webassembly-macos-target] @@ -2544,10 +2659,13 @@ extra-cmake-options= -DWASI_ICU_MD5:STRING="25943864ebbfff15cf5aee8d9d5cc4d7" -DSWIFT_PRIMARY_VARIANT_SDK:STRING=WASI -DSWIFT_PRIMARY_VARIANT_ARCH:STRING=wasm32 + -DSWIFT_SDKS='WASI' + -DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME=TRUE -DSWIFT_OSX_x86_64_ICU_STATICLIB=TRUE -DSWIFT_BUILD_SOURCEKIT=FALSE -DSWIFT_ENABLE_SOURCEKIT_TESTS=FALSE -DSWIFT_BUILD_SYNTAXPARSERLIB=FALSE - -DCMAKE_AR='/usr/local/opt/llvm/bin/llvm-ar' - -DCMAKE_RANLIB='/usr/local/opt/llvm/bin/llvm-ranlib' + -DCMAKE_AR='%(TOOLS_BIN_DIR)s/llvm-ar' + -DCMAKE_RANLIB='%(TOOLS_BIN_DIR)s/llvm-ranlib' + -DCLANG_COMPILER_RT_CMAKE_ARGS='-DCMAKE_TOOLCHAIN_FILE=%(SOURCE_PATH)s/swift/utils/webassembly/compiler-rt-cache.cmake' -DSWIFTWASM_DISABLE_REFLECTION_TEST=TRUE diff --git a/utils/build-script b/utils/build-script index 27097dea10d23..e0a52978361e7 100755 --- a/utils/build-script +++ b/utils/build-script @@ -563,9 +563,6 @@ class BuildScriptInvocation(object): impl_args += ["--skip-build"] if not args.build_benchmarks: impl_args += ["--skip-build-benchmarks"] - # Currently we do not build external benchmarks by default. - if args.build_external_benchmarks: - impl_args += ["--skip-build-external-benchmarks=0"] # Then add subproject install flags that either skip building them /or/ # if we are going to build them and install_all is set, we also install @@ -599,26 +596,6 @@ class BuildScriptInvocation(object): if args.build_swift_static_sdk_overlay: impl_args += ["--build-swift-static-sdk-overlay"] - if not args.build_linux: - impl_args += ["--skip-build-linux"] - if not args.build_freebsd: - impl_args += ["--skip-build-freebsd"] - if not args.build_cygwin: - impl_args += ["--skip-build-cygwin"] - if not args.build_osx: - impl_args += ["--skip-build-osx"] - if not args.build_ios_device: - impl_args += ["--skip-build-ios-device"] - if not args.build_ios_simulator: - impl_args += ["--skip-build-ios-simulator"] - if not args.build_tvos_device: - impl_args += ["--skip-build-tvos-device"] - if not args.build_tvos_simulator: - impl_args += ["--skip-build-tvos-simulator"] - if not args.build_watchos_device: - impl_args += ["--skip-build-watchos-device"] - if not args.build_watchos_simulator: - impl_args += ["--skip-build-watchos-simulator"] if not args.build_android: impl_args += ["--skip-build-android"] if not args.build_wasm: @@ -638,36 +615,6 @@ class BuildScriptInvocation(object): "--skip-test-libdispatch", "--skip-test-libicu", ] - if not args.test_linux: - impl_args += ["--skip-test-linux"] - if not args.test_freebsd: - impl_args += ["--skip-test-freebsd"] - if not args.test_cygwin: - impl_args += ["--skip-test-cygwin"] - if not args.test_osx: - impl_args += ["--skip-test-osx"] - if not args.test_ios_host: - impl_args += ["--skip-test-ios-host"] - if not args.test_ios_simulator: - impl_args += ["--skip-test-ios-simulator"] - if not args.test_ios_32bit_simulator: - impl_args += ["--skip-test-ios-32bit-simulator"] - if not args.test_tvos_host: - impl_args += ["--skip-test-tvos-host"] - if not args.test_tvos_simulator: - impl_args += ["--skip-test-tvos-simulator"] - if not args.test_watchos_host: - impl_args += ["--skip-test-watchos-host"] - if not args.test_watchos_simulator: - impl_args += ["--skip-test-watchos-simulator"] - if not args.test_android: - impl_args += ["--skip-test-android"] - if not args.test_android_host: - impl_args += ["--skip-test-android-host"] - if not args.test_wasm: - impl_args += ["--skip-test-wasm"] - if not args.test_wasm_host: - impl_args += ["--skip-test-wasm-host"] if args.build_runtime_with_host_compiler: impl_args += ["--build-runtime-with-host-compiler"] if args.validation_test: @@ -682,12 +629,6 @@ class BuildScriptInvocation(object): impl_args += ["--only-executable-test"] if not args.benchmark: impl_args += ["--skip-test-benchmarks"] - if not args.test_optimized: - impl_args += ["--skip-test-optimized"] - if not args.test_optimize_for_size: - impl_args += ["--skip-test-optimize-for-size"] - if not args.test_optimize_none_with_implicit_dynamic: - impl_args += ["--skip-test-optimize-none-with-implicit-dynamic"] if args.build_libparser_only: impl_args += ["--build-libparser-only"] if args.android: @@ -1013,6 +954,9 @@ class BuildScriptInvocation(object): for product_class in impl_product_classes: self._execute_install_action(host_target, product_class) + # Core Lipo... + self._execute_merged_host_lipo_core_action() + # Non-build-script-impl products... # Note: currently only supports building for the host. for host_target in [self.args.host_target]: @@ -1032,6 +976,9 @@ class BuildScriptInvocation(object): toolchain=self.toolchain, source_dir=self.workspace.source_dir(product_source), build_dir=build_dir) + if product.should_clean(host_target): + print("--- Cleaning %s ---" % product_name) + product.clean(host_target) if product.should_build(host_target): print("--- Building %s ---" % product_name) product.build(host_target) @@ -1081,6 +1028,9 @@ class BuildScriptInvocation(object): def _execute_merged_host_lipo_action(self): self._execute_action("merged-hosts-lipo") + def _execute_merged_host_lipo_core_action(self): + self._execute_action("merged-hosts-lipo-core") + def _execute_action(self, action_name): shell.call_without_sleeping( [BUILD_SCRIPT_IMPL_PATH] + self.impl_args + diff --git a/utils/build-script-impl b/utils/build-script-impl index c8d80d53f028d..8fcb2baba84da 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -114,6 +114,7 @@ KNOWN_SETTINGS=( darwin-toolchain-installer-package "" "The path to installer pkg" darwin-toolchain-name "" "Directory name for xctoolchain" darwin-toolchain-version "" "Version for xctoolchain info plist and installer pkg" + darwin-toolchain-require-use-os-runtime "0" "When setting up a plist for a toolchain, require the users of the toolchain to link against the OS instead of the packaged toolchain runtime. 0 for false, 1 for true" darwin-xcrun-toolchain "default" "the name of the toolchain to use on Darwin" ## WebAssembly/WASI Options @@ -125,47 +126,14 @@ KNOWN_SETTINGS=( ## Skip Build ... skip-build "" "set to configure as usual while skipping the build step" skip-build-android "" "set to skip building Swift stdlibs for Android" + skip-build-wasm "" "set to skip building Swift stdlibs for WebAssembly" skip-build-benchmarks "" "set to skip building Swift Benchmark Suite" skip-build-clang-tools-extra "" "set to skip building clang-tools-extra as part of llvm" skip-build-compiler-rt "" "set to skip building Compiler-RT" skip-build-lld "" "set to skip building lld as part of llvm (linux only)" - skip-build-cygwin "" "set to skip building Swift stdlibs for Cygwin" - skip-build-external-benchmarks "1" "set to skip building the external Swift Benchmark Suite. (skipped by default)" - skip-build-freebsd "" "set to skip building Swift stdlibs for FreeBSD" - skip-build-haiku "" "set to skip building Swift stdlibs for Haiku" - skip-build-ios-device "" "set to skip building Swift stdlibs for iOS devices (i.e. build simulators only)" - skip-build-ios-simulator "" "set to skip building Swift stdlibs for iOS simulators (i.e. build devices only)" - skip-build-linux "" "set to skip building Swift stdlibs for Linux" - skip-build-maccatalyst "" "set to skip building Swift stdlibs for macCatalyst" - skip-build-osx "" "set to skip building Swift stdlibs for OS X" - skip-build-tvos-device "" "set to skip building Swift stdlibs for tvOS devices (i.e. build simulators only)" - skip-build-tvos-simulator "" "set to skip building Swift stdlibs for tvOS simulators (i.e. build devices only)" - skip-build-wasm "" "set to skip building Swift stdlibs for WebAssembly" - skip-build-watchos-device "" "set to skip building Swift stdlibs for Apple watchOS devices (i.e. build simulators only)" - skip-build-watchos-simulator "" "set to skip building Swift stdlibs for Apple watchOS simulators (i.e. build devices only)" ## Skip Test ... - skip-test-android "" "set to skip testing Swift stdlibs for Android" - skip-test-android-host "" "set to skip testing the host parts of the Android toolchain" - skip-test-cygwin "" "set to skip testing Swift stdlibs for Cygwin" - skip-test-freebsd "" "set to skip testing Swift stdlibs for FreeBSD" - skip-test-haiku "" "set to skip testing Swift stdlibs for Haiku" - skip-test-ios-32bit-simulator "" "set to skip testing Swift stdlibs for iOS 32bit simulators" - skip-test-ios-host "" "set to skip testing the host parts of the iOS toolchain" - skip-test-ios-simulator "" "set to skip testing Swift stdlibs for iOS simulators (i.e. test devices only)" - skip-test-linux "" "set to skip testing Swift stdlibs for Linux" - skip-test-maccatalyst "" "set to skip testing Swift stdlibs for macCatalyst" - skip-test-osx "" "set to skip testing Swift stdlibs for OS X" - skip-test-tvos-host "" "set to skip testing the host parts of the tvOS toolchain" - skip-test-tvos-simulator "" "set to skip testing Swift stdlibs for tvOS simulators (i.e. test devices only)" - skip-test-wasm "" "set to skip testing Swift stdlibs for WebAssembly" - skip-test-wasm-host "" "set to skip testing the host parts of the WebAssembly toolchain" - skip-test-watchos-host "" "set to skip testing the host parts of the watchOS toolchain" - skip-test-watchos-simulator "" "set to skip testing Swift stdlibs for Apple watchOS simulators (i.e. test devices only)" skip-test-benchmarks "" "set to skip running Swift Benchmark Suite" - skip-test-optimized "" "set to skip testing the test suite in optimized mode" - skip-test-optimize-for-size "" "set to skip testing the test suite in optimize for size mode" - skip-test-optimize-none-with-implicit-dynamic "" "set to skip testing the test suite in optimize none with implicit dynamic mode" skip-test-sourcekit "" "set to skip testing SourceKit" ## Extra ... CMake Options @@ -223,12 +191,20 @@ KNOWN_SETTINGS=( swift-primary-variant-sdk "" "default SDK for target binaries" swift-runtime-enable-leak-checker "0" "Enable leaks checking routines in the runtime" swift-stdlib-enable-assertions "1" "enable assertions in Swift" - swift-stdlib-use-nonatomic-rc "0" "build the Swift stdlib and overlays with nonatomic reference count operations enabled" swift-tools-enable-lto "" "enable LTO compilation of Swift tools. *NOTE* This does not include the swift standard library and runtime. Must be set to one of 'thin' or 'full'" extra-swift-args "" "Extra arguments to pass to swift modules which match regex. Assumed to be a flattened cmake list consisting of [module_regexp, args, module_regexp, args, ...]" report-statistics "0" "set to 1 to generate compilation statistics files for swift libraries" sil-verify-all "0" "If enabled, run the SIL verifier after each transform when building Swift files during this build process" stdlib-deployment-targets "" "space-separated list of targets to configure the Swift standard library to be compiled or cross-compiled for" + swift-objc-interop "" "whether to enable interoperability with Objective-C, default is 1 on Apple platfors, 0 otherwise" + swift-enable-compatibility-overrides "1" "whether to support back-deploying compatibility fixes for newer apps running on older runtimes" + swift-runtime-macho-no-dyld "0" "whether to build stdlib assuming the runtime environment does not support dynamic modules" + swift-stdlib-single-threaded-runtime "0" "whether to build stdlib as a single-threaded runtime only" + + ## FREESTANDING Stdlib Options + swift-freestanding-sdk "" "which SDK to use when building the FREESTANDING stdlib" + swift-freestanding-triple-name "" "which triple name (e.g. 'none-macho') to use when building the FREESTANDING stdlib" + swift-freestanding-archs "" "space-separated list of which architectures to build when building the FREESTANDING stdlib" ## Uncategorised install-prefix "" "installation prefix" @@ -454,6 +430,7 @@ function set_build_options_for_host() { swift_cmake_options=() cmark_cmake_options=() lldb_cmake_options=() + llbuild_cmake_options=() SWIFT_HOST_VARIANT= SWIFT_HOST_VARIANT_SDK= SWIFT_HOST_VARIANT_ARCH= @@ -675,6 +652,7 @@ function set_build_options_for_host() { -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})" -DCMAKE_OSX_SYSROOT:PATH="${cmake_os_sysroot}" -DCMAKE_OSX_DEPLOYMENT_TARGET="${cmake_osx_deployment_target}" + -DCMAKE_OSX_ARCHITECTURES="${architecture}" ) llvm_cmake_options=( -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING="${cmake_osx_deployment_target}" @@ -684,6 +662,7 @@ function set_build_options_for_host() { -DCOMPILER_RT_ENABLE_TVOS:BOOL=FALSE -DSANITIZER_MIN_OSX_VERSION="${cmake_osx_deployment_target}" -DLLVM_ENABLE_MODULES:BOOL="$(true_false ${LLVM_ENABLE_MODULES})" + -DCMAKE_OSX_ARCHITECTURES="${architecture}" ) if [[ $(is_llvm_lto_enabled) == "TRUE" ]]; then llvm_cmake_options+=( @@ -715,6 +694,10 @@ function set_build_options_for_host() { lldb_cmake_options+=( -DCMAKE_OSX_SYSROOT:PATH="${cmake_os_sysroot}" + -DCMAKE_OSX_ARCHITECTURES="${architecture}" + ) + llbuild_cmake_options+=( + -DCMAKE_OSX_ARCHITECTURES="${architecture}" ) ;; esac @@ -1261,9 +1244,6 @@ function build_directory_bin() { ;; libicu) ;; - playgroundsupport) - echo "${root}/${PLAYGROUNDSUPPORT_BUILD_TYPE}/bin" - ;; *) echo "error: unknown product: ${product}" exit 1 @@ -1385,9 +1365,6 @@ function cmake_config_opt() { ;; libicu) ;; - playgroundsupport) - echo "--config ${PLAYGROUNDSUPPORT_BUILD_TYPE}" - ;; *) echo "error: unknown product: ${product}" exit 1 @@ -1446,6 +1423,13 @@ for host in "${ALL_HOSTS[@]}"; do fi fi + if [[ "${NATIVE_CLANG_TOOLS_PATH}" ]] ; then + common_cmake_options_host+=( + -DCMAKE_C_COMPILER="${NATIVE_CLANG_TOOLS_PATH}/clang" + -DCMAKE_CXX_COMPILER="${NATIVE_CLANG_TOOLS_PATH}/clang++" + ) + fi + llvm_cmake_options=( "${llvm_cmake_options[@]}" -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})" @@ -1581,13 +1565,14 @@ for host in "${ALL_HOSTS[@]}"; do # build of Swift depend on these for building and testing. build_targets=(llvm-tblgen clang-resource-headers intrinsics_gen clang-tablegen-targets) # If we are not performing a toolchain only build, then we - # also want to include FileCheck and not for testing + # also want to include FileCheck, not, llvm-nm for testing # purposes. if [[ ! "${BUILD_TOOLCHAIN_ONLY}" ]] ; then build_targets=( "${build_targets[@]}" FileCheck not + llvm-nm ) fi fi @@ -1637,10 +1622,23 @@ for host in "${ALL_HOSTS[@]}"; do # # This makes it easier to build target stdlibs on systems that # have old toolchains without more modern linker features. - if [[ "$(uname -s)" != "Darwin" ]] ; then + + # wasm: lld should be built when cross building for wasm + # After enabling stdlib cross compile, add if statement + # to build only when cross compiling for wasm + # if [[ "$(uname -s)" != "Darwin" ]] ; then if [[ ! "${SKIP_BUILD_LLD}" ]]; then llvm_enable_projects+=("lld") fi + # fi + + # wasm: SWIFT_WASI_SDK_PATH is used to determine wasi-sysroot + # to build compiler-rt for wasm32-wasi + if [[ ! "${SKIP_BUILD_WASM}" ]]; then + cmake_options=( + "${cmake_options[@]}" + -DCOMPILER_RT_SWIFT_WASI_SDK_PATH:STRING="${WASI_SDK}" + ) fi cmake_options+=( @@ -1797,15 +1795,15 @@ for host in "${ALL_HOSTS[@]}"; do "${cmake_options[@]}" -DCMAKE_C_FLAGS="$(swift_c_flags ${host})" -DCMAKE_CXX_FLAGS="$(swift_c_flags ${host})" - -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG" - -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG" -DCMAKE_BUILD_TYPE:STRING="${SWIFT_BUILD_TYPE}" -DLLVM_ENABLE_ASSERTIONS:BOOL=$(true_false "${SWIFT_ENABLE_ASSERTIONS}") -DSWIFT_ANALYZE_CODE_COVERAGE:STRING=$(toupper "${SWIFT_ANALYZE_CODE_COVERAGE}") -DSWIFT_STDLIB_BUILD_TYPE:STRING="${SWIFT_STDLIB_BUILD_TYPE}" -DSWIFT_STDLIB_ASSERTIONS:BOOL=$(true_false "${SWIFT_STDLIB_ENABLE_ASSERTIONS}") - -DSWIFT_STDLIB_USE_NONATOMIC_RC:BOOL=$(true_false "${SWIFT_STDLIB_USE_NONATOMIC_RC}") + -DSWIFT_ENABLE_COMPATIBILITY_OVERRIDES:BOOL=$(true_false "${SWIFT_ENABLE_COMPATIBILITY_OVERRIDES}") + -DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME:BOOL=$(true_false "${SWIFT_STDLIB_SINGLE_THREADED_RUNTIME}") -DSWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS:BOOL=$(true_false "${SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS}") + -DSWIFT_RUNTIME_MACHO_NO_DYLD:BOOL=$(true_false "${SWIFT_RUNTIME_MACHO_NO_DYLD}") -DSWIFT_NATIVE_LLVM_TOOLS_PATH:STRING="${native_llvm_tools_path}" -DSWIFT_NATIVE_CLANG_TOOLS_PATH:STRING="${native_clang_tools_path}" -DSWIFT_NATIVE_SWIFT_TOOLS_PATH:STRING="${native_swift_tools_path}" @@ -1859,6 +1857,13 @@ for host in "${ALL_HOSTS[@]}"; do ) fi + if [[ "${SWIFT_OBJC_INTEROP}" == "0" ]] ; then + cmake_options=( + "${cmake_options[@]}" + -DSWIFT_DISABLE_OBJC_INTEROP:BOOL=True + ) + fi + if [[ "${SWIFT_PRIMARY_VARIANT_SDK}" ]] ; then cmake_options=( "${cmake_options[@]}" @@ -1880,6 +1885,27 @@ for host in "${ALL_HOSTS[@]}"; do ) fi + if [ "${SWIFT_FREESTANDING_SDK}" ] ; then + cmake_options=( + "${cmake_options[@]}" + -DSWIFT_FREESTANDING_SDK:STRING="${SWIFT_FREESTANDING_SDK}" + ) + fi + + if [ "${SWIFT_FREESTANDING_TRIPLE_NAME}" ] ; then + cmake_options=( + "${cmake_options[@]}" + -DSWIFT_FREESTANDING_TRIPLE_NAME:STRING="${SWIFT_FREESTANDING_TRIPLE_NAME}" + ) + fi + + if [[ "${SWIFT_FREESTANDING_ARCHS}" ]] ; then + cmake_options=( + "${cmake_options[@]}" + -DSWIFT_FREESTANDING_ARCHS:STRING="$(join ";" ${SWIFT_FREESTANDING_ARCHS[@]})" + ) + fi + if [[ ! "${SKIP_BUILD_LLDB}" ]] ; then lldb_build_dir=$(build_directory ${host} lldb) cmake_options=( @@ -1956,6 +1982,7 @@ for host in "${ALL_HOSTS[@]}"; do DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}/Sources/Foundation" DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}/Sources/FoundationNetworking" DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}/Sources/FoundationXML" + DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}/lib" DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${LIBDISPATCH_BUILD_DIR}" DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${LIBDISPATCH_BUILD_DIR}/src" DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}" @@ -1963,6 +1990,7 @@ for host in "${ALL_HOSTS[@]}"; do DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}/Sources/Foundation" DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}/Sources/FoundationNetworking" DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}/Sources/FoundationXML" + DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}/lib" fi # Watchpoint testing is currently disabled: see rdar://38566150. @@ -2035,6 +2063,7 @@ for host in "${ALL_HOSTS[@]}"; do llbuild) cmake_options=( "${cmake_options[@]}" + "${llbuild_cmake_options[@]}" -DCMAKE_BUILD_TYPE:STRING="${LLBUILD_BUILD_TYPE}" -DCMAKE_C_COMPILER:PATH="${CLANG_BIN}/clang" @@ -2998,12 +3027,13 @@ for host in "${ALL_HOSTS[@]}"; do # # Exclude shell scripts and static archives. # Exclude swift-api-digester dSYM to reduce debug toolchain size. + # Run sequentially -- dsymutil is multithreaded and can be memory intensive (cd "${host_symroot}" && find ./"${CURRENT_PREFIX}" -perm -0111 -type f -print | \ grep -v '.py$' | \ grep -v '.a$' | \ grep -v 'swift-api-digester' | \ - xargs -n 1 -P ${BUILD_JOBS} ${dsymutil_path}) + xargs -n 1 -P 1 ${dsymutil_path}) # Strip executables, shared libraries and static libraries in # `host_install_destdir`. @@ -3040,11 +3070,7 @@ function build_and_test_installable_package() { local host_install_destdir="$(get_host_install_destdir ${host})" local host_install_prefix="$(get_host_install_prefix ${host})" - if [[ $(has_cross_compile_hosts) ]]; then - package_for_host="${INSTALLABLE_PACKAGE}-${host}" - else - package_for_host="${INSTALLABLE_PACKAGE}" - fi + package_for_host="${INSTALLABLE_PACKAGE}" echo "--- Creating installable package ---" echo "-- Package file: ${package_for_host} --" @@ -3062,6 +3088,11 @@ function build_and_test_installable_package() { COMPATIBILITY_VERSION_DISPLAY_STRING="Xcode 8.0" DARWIN_TOOLCHAIN_CREATED_DATE="$(date -u +'%a %b %d %T GMT %Y')" + SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME="YES" + if [[ "${DARWIN_TOOLCHAIN_REQUIRE_USE_OS_RUNTIME}" -eq "1" ]]; then + SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME="NO" + fi + echo "-- Removing: ${DARWIN_TOOLCHAIN_INFO_PLIST}" call rm -f ${DARWIN_TOOLCHAIN_INFO_PLIST} @@ -3080,7 +3111,7 @@ function build_and_test_installable_package() { call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_DISABLE_REQUIRED_ARCLITE string 'YES'" "${DARWIN_TOOLCHAIN_INFO_PLIST}" call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_LINK_OBJC_RUNTIME string 'YES'" "${DARWIN_TOOLCHAIN_INFO_PLIST}" call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_DEVELOPMENT_TOOLCHAIN string 'YES'" "${DARWIN_TOOLCHAIN_INFO_PLIST}" - call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME string 'YES'" "${DARWIN_TOOLCHAIN_INFO_PLIST}" + call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME string '${SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME}'" "${DARWIN_TOOLCHAIN_INFO_PLIST}" call chmod a+r "${DARWIN_TOOLCHAIN_INFO_PLIST}" @@ -3114,7 +3145,7 @@ function build_and_test_installable_package() { PKG_TESTS_SANDBOX_PARENT="$(build_directory swift_package_sandbox_${host} none)" PKG_TESTS_TEMPS="${PKG_TESTS_SANDBOX_PARENT}"/"tests" - if [[ "${host}" == "macosx-"* ]] ; then + if [[ "${host}" == "macosx-"* ]] || [[ "${host}" == "merged-hosts" ]]; then PKG_TESTS_SANDBOX="${PKG_TESTS_SANDBOX_PARENT}"/"${TOOLCHAIN_PREFIX}" else # Linux PKG_TESTS_SANDBOX="${PKG_TESTS_SANDBOX_PARENT}" @@ -3128,8 +3159,11 @@ function build_and_test_installable_package() { with_pushd "${PKG_TESTS_SANDBOX_PARENT}" \ call tar xzf "${package_for_host}" + if python -c "import psutil" ; then + TIMEOUT_ARGS=--timeout=1200 # 20 minutes + fi with_pushd "${PKG_TESTS_SOURCE_DIR}" \ - call python "${LIT_EXECUTABLE_PATH}" . -sv --param package-path="${PKG_TESTS_SANDBOX}" --param test-exec-root="${PKG_TESTS_TEMPS}" --param llvm-bin-dir="${LLVM_BIN_DIR}" + call python "${LIT_EXECUTABLE_PATH}" . -sv --param package-path="${PKG_TESTS_SANDBOX}" --param test-exec-root="${PKG_TESTS_TEMPS}" --param llvm-bin-dir="${LLVM_BIN_DIR}" ${TIMEOUT_ARGS} fi fi } @@ -3155,7 +3189,7 @@ if [[ ${#LIPO_SRC_DIRS[@]} -gt 0 ]]; then # This is from multiple hosts; Which host should we say it is? # Let's call it 'merged-hosts' so that we can identify it. - if [[ $(should_execute_action "${mergedHost}-lipo") ]]; then + if [[ $(should_execute_action "${mergedHost}-lipo") || $(should_execute_action "${mergedHost}-lipo-core") ]]; then # Allow passing lipo with --host-lipo if [[ -z "${HOST_LIPO}" ]] ; then LIPO_PATH=$(xcrun_find_tool lipo) @@ -3164,8 +3198,10 @@ if [[ ${#LIPO_SRC_DIRS[@]} -gt 0 ]]; then fi call "${SWIFT_SOURCE_DIR}"/utils/recursive-lipo --lipo=${LIPO_PATH} --copy-subdirs="$(get_host_install_prefix ${host})lib/swift $(get_host_install_prefix ${host})lib/swift_static" --destination="$(get_host_install_destdir ${mergedHost})" ${LIPO_SRC_DIRS[@]} - # Build and test the lipo-ed package. - build_and_test_installable_package ${mergedHost} + if [[ $(should_execute_action "${mergedHost}-lipo") ]]; then + # Build and test the lipo-ed package. + build_and_test_installable_package ${mergedHost} + fi fi fi # END diff --git a/utils/build-toolchain b/utils/build-toolchain index f89f30f3faf1d..7768339ec1537 100755 --- a/utils/build-toolchain +++ b/utils/build-toolchain @@ -29,6 +29,15 @@ function usage() { echo "--distcc" echo "Build with distcc to speed up the toolchain build" echo "" + echo "--preset-file" + echo "load build-script presets from the specified file" + echo "" + echo "--preset-prefix" + echo "Customize the preset invoked by prepending a prefix" + echo "" + echo "--use-os-runtime" + echo "Require this toolchain to link against against the OS runtime rather than the toolchains packaged runtime" + echo "" } RESULT_DIR=$PWD @@ -38,6 +47,10 @@ cd "$(dirname $0)/.." || exit DISTCC_FLAG= DRY_RUN= BUNDLE_PREFIX= +PRESET_FILE_FLAGS= +PRESET_PREFIX= +PRESET_SUFFIX= + case $(uname -s) in Darwin) SWIFT_PACKAGE=buildbot_osx_package,no_test @@ -69,6 +82,17 @@ while [ $# -ne 0 ]; do ;; --distcc) DISTCC_FLAG="--distcc" + ;; + --preset-file) + shift + PRESET_FILE_FLAGS="${PRESET_FILE_FLAGS} --preset-file=$1" + ;; + --preset-prefix) + shift + PRESET_PREFIX="$1" + ;; + --use-os-runtime) + PRESET_SUFFIX=",use_os_runtime" ;; -h|--help) usage @@ -115,8 +139,10 @@ SWIFT_TOOLCHAIN_DIR="/Library/Developer/Toolchains/${TOOLCHAIN_NAME}.xctoolchain SYMBOLS_PACKAGE="${RESULT_DIR}/${SYM_ARCHIVE}" DRY_RUN="${DRY_RUN}" DISTCC_FLAG="${DISTCC_FLAG}" +PRESET_FILE_FLAGS="${PRESET_FILE_FLAGS}" -./utils/build-script ${DRY_RUN} ${DISTCC_FLAG} --preset="${SWIFT_PACKAGE}" \ +./utils/build-script ${DRY_RUN} ${DISTCC_FLAG} ${PRESET_FILE_FLAGS} \ + --preset="${PRESET_PREFIX}${SWIFT_PACKAGE}${PRESET_SUFFIX}" \ install_destdir="${SWIFT_INSTALL_DIR}" \ installable_package="${SWIFT_INSTALLABLE_PACKAGE}" \ install_toolchain_dir="${SWIFT_TOOLCHAIN_DIR}" \ @@ -127,4 +153,5 @@ DISTCC_FLAG="${DISTCC_FLAG}" darwin_toolchain_display_name_short="${DISPLAY_NAME_SHORT}" \ darwin_toolchain_xctoolchain_name="${TOOLCHAIN_NAME}" \ darwin_toolchain_version="${TOOLCHAIN_VERSION}" \ - darwin_toolchain_alias="Local" + darwin_toolchain_alias="Local" \ + darwin_toolchain_require_use_os_runtime="${REQUIRE_USE_OS_RUNTIME}" diff --git a/utils/build-windows.bat b/utils/build-windows.bat index 3c9c11e65ff49..a524e3ff01f14 100644 --- a/utils/build-windows.bat +++ b/utils/build-windows.bat @@ -176,6 +176,7 @@ cmake^ -DLLVM_ENABLE_OCAMLDOC:BOOL=NO^ -DLLVM_ENABLE_LIBXML2:BOOL=NO^ -DLLVM_ENABLE_ZLIB:BOOL=NO^ + -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ -DENABLE_X86_RELAX_RELOCATIONS:BOOL=YES^ -DLLVM_INSTALL_BINUTILS_SYMLINKS:BOOL=YES^ -DLLVM_INSTALL_TOOLCHAIN_ONLY:BOOL=YES^ @@ -232,6 +233,7 @@ cmake^ -DSWIFT_PATH_TO_CMARK_SOURCE:PATH=%source_root%\cmark^ -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE:PATH=%source_root%\swift-corelibs-libdispatch^ -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ + -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ -DSWIFT_INCLUDE_DOCS:BOOL=NO^ -DSWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE:PATH=%source_root%\icu-%icu_version%\include\unicode^ -DSWIFT_WINDOWS_x86_64_ICU_UC:PATH=%source_root%\icu-%icu_version%\lib64\icuuc.lib^ @@ -277,8 +279,8 @@ cmake^ -B "%build_root%\lldb"^ -G Ninja^ -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ - -DCMAKE_C_COMPILER=clang-cl^ - -DCMAKE_CXX_COMPILER=clang-cl^ + -DCMAKE_C_COMPILER=cl^ + -DCMAKE_CXX_COMPILER=cl^ -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ -DClang_DIR:PATH=%build_root%\llvm\lib\cmake\clang^ @@ -291,6 +293,7 @@ cmake^ -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ -DLLDB_DISABLE_PYTHON=YES^ -DLLDB_INCLUDE_TESTS:BOOL=NO^ + -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ -S "%source_root%\lldb" %exitOnError% cmake --build "%build_root%\lldb" %exitOnError% diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index ae6403e0eaf0c..52426d85824d2 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -564,16 +564,16 @@ def create_argument_parser(): # ------------------------------------------------------------------------- in_group('Options to select projects') - option('--infer', store_true('infer_dependencies'), + option('--infer', toggle_true('infer_dependencies'), help='Infer any downstream dependencies from enabled projects') - option(['-l', '--lldb'], store_true('build_lldb'), + option(['-l', '--lldb'], toggle_true('build_lldb'), help='build LLDB') - option(['-b', '--llbuild'], store_true('build_llbuild'), + option(['-b', '--llbuild'], toggle_true('build_llbuild'), help='build llbuild') - option(['--libcxx'], store_true('build_libcxx'), + option(['--libcxx'], toggle_true('build_libcxx'), help='build libcxx') option(['-p', '--swiftpm'], toggle_true('build_swiftpm'), @@ -582,16 +582,16 @@ def create_argument_parser(): option(['--install-swiftpm'], toggle_true('install_swiftpm'), help='install swiftpm') - option(['--swiftsyntax'], store_true('build_swiftsyntax'), + option(['--swiftsyntax'], toggle_true('build_swiftsyntax'), help='build swiftSyntax') - option(['--skstresstester'], store_true('build_skstresstester'), + option(['--skstresstester'], toggle_true('build_skstresstester'), help='build the SourceKit stress tester') - option(['--swiftformat'], store_true('build_swiftformat'), + option(['--swiftformat'], toggle_true('build_swiftformat'), help='build swift-format') - option(['--swiftevolve'], store_true('build_swiftevolve'), + option(['--swiftevolve'], toggle_true('build_swiftevolve'), help='build the swift-evolve tool') option(['--swift-driver'], toggle_true('build_swift_driver'), @@ -645,13 +645,13 @@ def create_argument_parser(): option('--playgroundsupport', toggle_true('build_playgroundsupport'), help='build PlaygroundSupport') option('--install-playgroundsupport', - store_true('install_playgroundsupport'), + toggle_true('install_playgroundsupport'), help='install playground support') option('--build-ninja', toggle_true, help='build the Ninja tool') - option(['--build-libparser-only'], store_true('build_libparser_only'), + option(['--build-libparser-only'], toggle_true('build_libparser_only'), help='build only libParser for SwiftSyntax') option('--skip-build-clang-tools-extra', @@ -695,6 +695,11 @@ def create_argument_parser(): help='build the Release variant of everything (default is ' '%(default)s)') + option(['--min-size-release'], store('build_variant'), + const='MinSizeRel', + help='build the MinSizeRel variant of everything (default is ' + '%(default)s)') + # ------------------------------------------------------------------------- in_group('Override build variant for a specific project') @@ -1021,6 +1026,11 @@ def create_argument_parser(): help='skip testing Android device targets on the host machine (the ' 'phone itself)') + option('--skip-clean-swiftpm', toggle_false('clean_swiftpm'), + help='skip cleaning up swiftpm') + option('--skip-clean-swift-driver', toggle_false('clean_swift_driver'), + help='skip cleaning up Swift driver') + option('--skip-test-wasm', toggle_false('test_wasm'), help='skip testing all WebAssembly targets.') diff --git a/utils/build_swift/tests/expected_options.py b/utils/build_swift/tests/expected_options.py index bbcd8577d94b3..e0381cb842fc2 100644 --- a/utils/build_swift/tests/expected_options.py +++ b/utils/build_swift/tests/expected_options.py @@ -205,6 +205,8 @@ defaults.SWIFT_MAX_PARALLEL_LTO_LINK_JOBS, 'swift_user_visible_version': defaults.SWIFT_USER_VISIBLE_VERSION, 'symbols_package': None, + 'clean_swiftpm': True, + 'clean_swift_driver': True, 'test': None, 'test_android': False, 'test_android_host': False, @@ -412,6 +414,8 @@ class BuildScriptImplOption(_BaseOption): SetOption('--release', dest='build_variant', value='Release'), SetOption('--release-debuginfo', dest='build_variant', value='RelWithDebInfo'), + SetOption('--min-size-release', + dest='build_variant', value='MinSizeRel'), SetOption('--xcode', dest='cmake_generator', value='Xcode'), SetOption('-R', dest='build_variant', value='Release'), SetOption('-d', dest='build_variant', value='Debug'), @@ -565,6 +569,8 @@ class BuildScriptImplOption(_BaseOption): dest='build_watchos_device'), DisableOption('--skip-build-watchos-simulator', dest='build_watchos_simulator'), + DisableOption('--skip-clean-swiftpm', dest='clean_swiftpm'), + DisableOption('--skip-clean-swift-driver', dest='clean_swift_driver'), DisableOption('--skip-test-android', dest='test_android'), DisableOption('--skip-test-android-host', dest='test_android_host'), DisableOption('--skip-test-cygwin', dest='test_cygwin'), diff --git a/utils/gyb_sourcekit_support/UIDs.py b/utils/gyb_sourcekit_support/UIDs.py index e8d1eb947b3c6..41b5dab310480 100644 --- a/utils/gyb_sourcekit_support/UIDs.py +++ b/utils/gyb_sourcekit_support/UIDs.py @@ -181,6 +181,8 @@ def __init__(self, internal_name, external_name): KEY('OptimizeForIDE', 'key.optimize_for_ide'), KEY('RequiredBystanders', 'key.required_bystanders'), KEY('ReusingASTContext', 'key.reusingastcontext'), + KEY('CompletionMaxASTContextReuseCount', + 'key.completion_max_astcontext_reuse_count'), KEY('CompletionCheckDependencyInterval', 'key.completion_check_dependency_interval'), KEY('AnnotatedTypename', 'key.annotated.typename'), diff --git a/utils/gyb_syntax_support/ExprNodes.py b/utils/gyb_syntax_support/ExprNodes.py index 8b442d8c307a1..59801e8e98244 100644 --- a/utils/gyb_syntax_support/ExprNodes.py +++ b/utils/gyb_syntax_support/ExprNodes.py @@ -49,7 +49,9 @@ # await foo() Node('AwaitExpr', kind='Expr', children=[ - Child('AwaitKeyword', kind='AwaitToken'), + Child('AwaitKeyword', kind='IdentifierToken', + classification='Keyword', + text_choices=['await']), Child('Expression', kind='Expr'), ]), @@ -390,6 +392,9 @@ Child('SimpleInput', kind='ClosureParamList'), Child('Input', kind='ParameterClause'), ]), + Child('AsyncKeyword', kind='IdentifierToken', + classification='Keyword', + text_choices=['async'], is_optional=True), Child('ThrowsTok', kind='ThrowsToken', is_optional=True), Child('Output', kind='ReturnClause', is_optional=True), Child('InTok', kind='InToken'), diff --git a/utils/gyb_syntax_support/Token.py b/utils/gyb_syntax_support/Token.py index 5abe6794e61d7..6a2eb85ac5318 100644 --- a/utils/gyb_syntax_support/Token.py +++ b/utils/gyb_syntax_support/Token.py @@ -196,7 +196,6 @@ def macro_name(self): ExprKeyword('True', 'true', serialization_code=51), ExprKeyword('Try', 'try', serialization_code=52), ExprKeyword('Throws', 'throws', serialization_code=53), - ExprKeyword('Await', '__await', serialization_code=123), Keyword('__FILE__', '__FILE__', serialization_code=54), Keyword('__LINE__', '__LINE__', serialization_code=55), diff --git a/utils/parser-lib/darwin-extract-symbols b/utils/parser-lib/darwin-extract-symbols index a4ee1e4c61e96..1e10f61c7c11b 100755 --- a/utils/parser-lib/darwin-extract-symbols +++ b/utils/parser-lib/darwin-extract-symbols @@ -46,11 +46,12 @@ function xcrun_find_tool() { # Run dsymutil on executables and shared libraries. # # Exclude shell scripts. +# Run sequentially -- dsymutil is multithreaded and can be memory intensive (cd "${INSTALL_SYMROOT}" && find ./"${INSTALL_PREFIX}" -perm -0111 -type f -print | \ grep -v crashlog.py | \ grep -v symbolication.py | \ - xargs -n 1 -P ${BUILD_JOBS} $(xcrun_find_tool dsymutil)) + xargs -n 1 -P 1 $(xcrun_find_tool dsymutil)) # Strip executables, shared libraries and static libraries in INSTALL_DIR. find "${INSTALL_DIR}${INSTALL_PREFIX}/" \ diff --git a/utils/recursive-lipo b/utils/recursive-lipo index 056b5f3576ef6..df3d302e651fd 100755 --- a/utils/recursive-lipo +++ b/utils/recursive-lipo @@ -63,6 +63,9 @@ def merge_lipo_files(src_root_dirs, file_list, copy_verbatim_subpaths, if all([os.path.islink(item) for item in file_paths]): # It's a symlink in all found instances, copy the link. print("-- Creating symlink %s" % dest_path) + # Remove symlink if it already exists + if os.path.islink(dest_path): + os.remove(dest_path) os.symlink(os.readlink(file_paths[0]), dest_path) elif all([os.path.isdir(item) for item in file_paths]): # It's a subdir in all found instances. diff --git a/utils/sil-mode.el b/utils/sil-mode.el index fe29c99d9b58b..59cc44ba0c4c7 100644 --- a/utils/sil-mode.el +++ b/utils/sil-mode.el @@ -259,6 +259,7 @@ ;; *NOTE* viewcfg must be in the $PATH and .dot files should be associated with ;; the graphviz app. (defvar sil-mode-viewcfg-program-name "viewcfg") +(defvar sil-mode-viewcfg-renderer "dot") (defvar sil-mode-viewcfg-buffer-name "*viewcfg*") (defcustom sil-mode-viewcfg-command-default "viewcfg" @@ -281,7 +282,8 @@ (process-connection-type nil)) (let ((p (start-process sil-mode-viewcfg-program-name sil-mode-viewcfg-buffer-name - sil-mode-viewcfg-command))) + sil-mode-viewcfg-command + (concat "--renderer=" sil-mode-viewcfg-renderer)))) (process-send-region p brace-start brace-end) (process-send-eof p))))) diff --git a/utils/swift-api-dump.py b/utils/swift-api-dump.py index 9022e9c89d5b2..d44b33ae19839 100755 --- a/utils/swift-api-dump.py +++ b/utils/swift-api-dump.py @@ -102,6 +102,8 @@ def create_parser(): parser.add_argument('--enable-infer-import-as-member', action='store_true', help='Infer when a global could be imported as a ' + 'member.') + parser.add_argument('--enable-experimental-concurrency', action='store_true', + help='Enable experimental concurrency model.') parser.add_argument('-swift-version', metavar='N', help='the Swift version to use') parser.add_argument('-show-overlay', action='store_true', @@ -328,6 +330,8 @@ def main(): extra_args = ['-skip-imports'] if args.enable_infer_import_as_member: extra_args = extra_args + ['-enable-infer-import-as-member'] + if args.enable_experimental_concurrency: + extra_args = extra_args + ['-enable-experimental-concurrency'] if args.swift_version: extra_args = extra_args + ['-swift-version', '%s' % args.swift_version] diff --git a/utils/swift_build_sdk_interfaces.py b/utils/swift_build_sdk_interfaces.py index 900bae30064e0..140afabdb9d3d 100755 --- a/utils/swift_build_sdk_interfaces.py +++ b/utils/swift_build_sdk_interfaces.py @@ -12,6 +12,7 @@ import subprocess import sys import traceback +from shutil import copyfile BARE_INTERFACE_SEARCH_PATHS = [ "usr/lib/swift", @@ -354,6 +355,24 @@ def process_module_files(pool, module_files): return overall_exit_status +def getSDKVersion(sdkroot): + settingPath = os.path.join(sdkroot, 'SDKSettings.json') + with open(settingPath) as json_file: + data = json.load(json_file) + return data['Version'] + fatal("Failed to get SDK version from: " + settingPath) + + +def copySystemVersionFile(sdkroot, output): + sysInfoPath = os.path.join(sdkroot, + 'System/Library/CoreServices/SystemVersion.plist') + destInfoPath = os.path.join(output, 'SystemVersion.plist') + try: + copyfile(sysInfoPath, destInfoPath) + except BaseException as e: + print("cannot copy from " + sysInfoPath + " to " + destInfoPath + ": " + str(e)) + + def main(): global args, shared_output_lock parser = create_parser() @@ -373,6 +392,12 @@ def main(): if not os.path.isdir(args.sdk): fatal("invalid SDK: " + args.sdk) + # if the given output dir ends with 'prebuilt-modules', we should + # append the SDK version number so all modules will built into + # the SDK-versioned sub-directory. + if os.path.basename(args.output_dir) == 'prebuilt-modules': + args.output_dir = os.path.join(args.output_dir, getSDKVersion(args.sdk)) + xfails = () if args.ignore_non_stdlib_failures: if args.xfails: @@ -384,6 +409,10 @@ def main(): xfails = json.load(xfails_file) make_dirs_if_needed(args.output_dir, args.dry_run) + + # Copy a file containing SDK build version into the prebuilt module dir, + # so we can keep track of the SDK version we built from. + copySystemVersionFile(args.sdk, args.output_dir) if 'ANDROID_DATA' not in os.environ: shared_output_lock = multiprocessing.Lock() pool = multiprocessing.Pool(args.jobs, set_up_child, diff --git a/utils/swift_build_support/swift_build_support/products/benchmarks.py b/utils/swift_build_support/swift_build_support/products/benchmarks.py index cac1e241e4451..b7a14ecc658fa 100644 --- a/utils/swift_build_support/swift_build_support/products/benchmarks.py +++ b/utils/swift_build_support/swift_build_support/products/benchmarks.py @@ -82,7 +82,9 @@ def get_dependencies(cls): def run_build_script_helper(host_target, product, args): - toolchain_path = args.install_destdir + toolchain_path = swiftpm.SwiftPM.get_install_destdir(args, + host_target, + product.build_dir) if platform.system() == 'Darwin': # The prefix is an absolute path, so concatenate without os.path. toolchain_path += \ diff --git a/utils/swift_build_support/swift_build_support/products/indexstoredb.py b/utils/swift_build_support/swift_build_support/products/indexstoredb.py index 65d720c4889fa..83b4ac91811c4 100644 --- a/utils/swift_build_support/swift_build_support/products/indexstoredb.py +++ b/utils/swift_build_support/swift_build_support/products/indexstoredb.py @@ -76,7 +76,12 @@ def run_build_script_helper(action, host_target, product, args, script_path = os.path.join( product.source_dir, 'Utilities', 'build-script-helper.py') - toolchain_path = targets.toolchain_path(args.install_destdir, + install_destdir = args.install_destdir + if swiftpm.SwiftPM.has_cross_compile_hosts(args): + install_destdir = swiftpm.SwiftPM.get_install_destdir(args, + host_target, + product.build_dir) + toolchain_path = targets.toolchain_path(install_destdir, args.install_prefix) is_release = product.is_release() configuration = 'release' if is_release else 'debug' diff --git a/utils/swift_build_support/swift_build_support/products/ninja.py b/utils/swift_build_support/swift_build_support/products/ninja.py index 53ebb15c6e32e..d133c22fa9ded 100644 --- a/utils/swift_build_support/swift_build_support/products/ninja.py +++ b/utils/swift_build_support/swift_build_support/products/ninja.py @@ -63,8 +63,8 @@ def build(self): "-isysroot {sysroot} -mmacosx-version-min={osx_version}" ).format(sysroot=sysroot, osx_version=osx_version_min), "LDFLAGS": ( - "-mmacosx-version-min={osx_version}" - ).format(osx_version=osx_version_min), + "-isysroot {sysroot} -mmacosx-version-min={osx_version}" + ).format(sysroot=sysroot, osx_version=osx_version_min), } elif self.toolchain.cxx: env = { diff --git a/utils/swift_build_support/swift_build_support/products/product.py b/utils/swift_build_support/swift_build_support/products/product.py index ed4c944bc008e..ba6f673bb6c99 100644 --- a/utils/swift_build_support/swift_build_support/products/product.py +++ b/utils/swift_build_support/swift_build_support/products/product.py @@ -11,6 +11,7 @@ # ---------------------------------------------------------------------------- import abc +import os from .. import cmake from .. import targets @@ -78,6 +79,20 @@ def get_dependencies(cls): """Return a list of products that this product depends upon""" raise NotImplementedError + def should_clean(self, host_target): + """should_clean() -> Bool + + Whether or not this product should be cleaned before being built + """ + return False + + def clean(self, host_target): + """clean() -> void + + Perform the clean, for a non-build-script-impl product. + """ + raise NotImplementedError + def should_build(self, host_target): """should_build() -> Bool @@ -148,13 +163,17 @@ def is_release(self): """ return is_release_variant(self.args.build_variant) - def install_toolchain_path(self): + def install_toolchain_path(self, host_target): """toolchain_path() -> string Returns the path to the toolchain that is being created as part of this build. """ - return targets.toolchain_path(self.args.install_destdir, + install_destdir = self.args.install_destdir + if self.args.cross_compile_hosts: + build_root = os.path.dirname(self.build_dir) + install_destdir = '%s/intermediate-install/%s' % (build_root, host_target) + return targets.toolchain_path(install_destdir, self.args.install_prefix) diff --git a/utils/swift_build_support/swift_build_support/products/skstresstester.py b/utils/swift_build_support/swift_build_support/products/skstresstester.py index ae79373d99c7c..0656a2bfd7d3a 100644 --- a/utils/swift_build_support/swift_build_support/products/skstresstester.py +++ b/utils/swift_build_support/swift_build_support/products/skstresstester.py @@ -50,7 +50,7 @@ def is_swiftpm_unified_build_product(cls): def package_name(self): return 'SourceKitStressTester' - def run_build_script_helper(self, action, additional_params=[]): + def run_build_script_helper(self, action, host_target, additional_params=[]): script_path = os.path.join( self.source_dir, 'build-script-helper.py') @@ -60,7 +60,7 @@ def run_build_script_helper(self, action, additional_params=[]): script_path, action, '--package-dir', self.package_name(), - '--toolchain', self.install_toolchain_path(), + '--toolchain', self.install_toolchain_path(host_target), '--config', configuration, '--build-dir', self.build_dir, '--multiroot-data-file', MULTIROOT_DATA_FILE_PATH, @@ -84,20 +84,23 @@ def build(self, host_target): "than Darwin".format( product=self.package_name())) - self.run_build_script_helper('build') + self.run_build_script_helper('build', host_target) def should_test(self, host_target): return self.args.test_skstresstester def test(self, host_target): - self.run_build_script_helper('test') + self.run_build_script_helper('test', host_target) def should_install(self, host_target): return self.args.install_skstresstester def install(self, host_target): - install_prefix = self.args.install_destdir + self.args.install_prefix - self.run_build_script_helper('install', [ + install_destdir = swiftpm.SwiftPM.get_install_destdir(self.args, + host_target, + self.build_dir) + install_prefix = install_destdir + self.args.install_prefix + self.run_build_script_helper('install', host_target, [ '--prefix', install_prefix ]) diff --git a/utils/swift_build_support/swift_build_support/products/swiftdriver.py b/utils/swift_build_support/swift_build_support/products/swiftdriver.py index 52ca78d4c00a9..5eca23c888086 100644 --- a/utils/swift_build_support/swift_build_support/products/swiftdriver.py +++ b/utils/swift_build_support/swift_build_support/products/swiftdriver.py @@ -47,6 +47,13 @@ def get_dependencies(cls): xctest.XCTest, llbuild.LLBuild] + def should_clean(self, host_target): + return self.args.clean_swift_driver + + def clean(self, host_target): + indexstoredb.run_build_script_helper( + 'clean', host_target, self, self.args) + def build(self, host_target): indexstoredb.run_build_script_helper( 'build', host_target, self, self.args) diff --git a/utils/swift_build_support/swift_build_support/products/swiftformat.py b/utils/swift_build_support/swift_build_support/products/swiftformat.py index ae6323cddadf8..940ccd1043e6c 100644 --- a/utils/swift_build_support/swift_build_support/products/swiftformat.py +++ b/utils/swift_build_support/swift_build_support/products/swiftformat.py @@ -46,7 +46,7 @@ def is_build_script_impl_product(cls): def is_swiftpm_unified_build_product(cls): return True - def run_build_script_helper(self, action, additional_params=[]): + def run_build_script_helper(self, action, host_target, additional_params=[]): script_path = os.path.join( self.source_dir, 'build-script-helper.py') @@ -55,7 +55,7 @@ def run_build_script_helper(self, action, additional_params=[]): helper_cmd = [ script_path, action, - '--toolchain', self.install_toolchain_path(), + '--toolchain', self.install_toolchain_path(host_target), '--configuration', configuration, '--build-path', self.build_dir, '--multiroot-data-file', MULTIROOT_DATA_FILE_PATH, @@ -74,13 +74,13 @@ def should_build(self, host_target): return True def build(self, host_target): - self.run_build_script_helper('build') + self.run_build_script_helper('build', host_target) def should_test(self, host_target): return self.args.test_swiftformat def test(self, host_target): - self.run_build_script_helper('test') + self.run_build_script_helper('test', host_target) def should_install(self, host_target): return False diff --git a/utils/swift_build_support/swift_build_support/products/swiftpm.py b/utils/swift_build_support/swift_build_support/products/swiftpm.py index 48c18256629b5..25e982e23f173 100644 --- a/utils/swift_build_support/swift_build_support/products/swiftpm.py +++ b/utils/swift_build_support/swift_build_support/products/swiftpm.py @@ -40,7 +40,7 @@ def should_build(self, host_target): def run_bootstrap_script(self, action, host_target, additional_params=[]): script_path = os.path.join( self.source_dir, 'Utilities', 'bootstrap') - toolchain_path = self.install_toolchain_path() + toolchain_path = self.install_toolchain_path(host_target) swiftc = os.path.join(toolchain_path, "bin", "swiftc") # FIXME: We require llbuild build directory in order to build. Is @@ -51,6 +51,11 @@ def run_bootstrap_script(self, action, host_target, additional_params=[]): helper_cmd = [script_path, action] + if action == 'clean': + helper_cmd += ["--build-dir", self.build_dir] + shell.call(helper_cmd) + return + if self.is_release(): helper_cmd.append("--release") @@ -81,6 +86,12 @@ def run_bootstrap_script(self, action, host_target, additional_params=[]): "--foundation-build-dir", foundation_build_dir ] + # Pass Cross compile host info + if self.has_cross_compile_hosts(self.args): + helper_cmd += ['--cross-compile-hosts'] + for cross_compile_host in self.args.cross_compile_hosts: + helper_cmd += [cross_compile_host] + helper_cmd.extend(additional_params) shell.call(helper_cmd) @@ -94,11 +105,33 @@ def should_test(self, host_target): def test(self, host_target): self.run_bootstrap_script('test', host_target) + def should_clean(self, host_target): + return self.args.clean_swiftpm + + def clean(self, host_target): + self.run_bootstrap_script('clean', host_target) + def should_install(self, host_target): return self.args.install_swiftpm + @classmethod + def has_cross_compile_hosts(self, args): + return args.cross_compile_hosts + + @classmethod + def get_install_destdir(self, args, host_target, build_dir): + install_destdir = args.install_destdir + if self.has_cross_compile_hosts(args): + build_root = os.path.dirname(build_dir) + install_destdir = '%s/intermediate-install/%s' % (build_root, host_target) + return install_destdir + def install(self, host_target): - install_prefix = self.args.install_destdir + self.args.install_prefix + install_destdir = self.get_install_destdir(self.args, + host_target, + self.build_dir) + install_prefix = install_destdir + self.args.install_prefix + self.run_bootstrap_script('install', host_target, [ '--prefix', install_prefix ]) diff --git a/utils/swift_build_support/swift_build_support/products/swiftsyntax.py b/utils/swift_build_support/swift_build_support/products/swiftsyntax.py index 9dd6a8436b30f..00cdef0dd0c5c 100644 --- a/utils/swift_build_support/swift_build_support/products/swiftsyntax.py +++ b/utils/swift_build_support/swift_build_support/products/swiftsyntax.py @@ -55,7 +55,7 @@ def run_swiftsyntax_build_script(self, target, additional_params=[]): script_path, '--build-dir', self.build_dir, '--multiroot-data-file', MULTIROOT_DATA_FILE_PATH, - '--toolchain', self.install_toolchain_path(), + '--toolchain', self.install_toolchain_path(target), '--filecheck-exec', os.path.join(llvm_build_dir, 'bin', 'FileCheck'), ] diff --git a/utils/swift_build_support/swift_build_support/targets.py b/utils/swift_build_support/swift_build_support/targets.py index 64ed0485edabb..4438b83157389 100644 --- a/utils/swift_build_support/swift_build_support/targets.py +++ b/utils/swift_build_support/swift_build_support/targets.py @@ -179,6 +179,12 @@ class StdlibDeploymentTarget(object): sdk_name="WATCHOS_SIMULATOR", is_simulator=True) + # A platform that's not tied to any particular OS, and it meant to be used + # to build the stdlib as standalone and/or statically linked. + Freestanding = Platform("freestanding", + archs=["i386", "x86_64", "armv7", "armv7s", "armv7k", + "arm64", "arm64e"]) + Linux = Platform("linux", archs=[ "x86_64", "i686", @@ -209,6 +215,7 @@ class StdlibDeploymentTarget(object): iOS, iOSSimulator, AppleTV, AppleTVSimulator, AppleWatch, AppleWatchSimulator, + Freestanding, Linux, FreeBSD, OpenBSD, diff --git a/utils/swift_build_support/tests/products/test_ninja.py b/utils/swift_build_support/tests/products/test_ninja.py index 5a3c919732d11..3eb26c4a838a0 100644 --- a/utils/swift_build_support/tests/products/test_ninja.py +++ b/utils/swift_build_support/tests/products/test_ninja.py @@ -101,7 +101,7 @@ def test_build(self): "env " "'CFLAGS=-isysroot {sysroot} -mmacosx-version-min=10.9' " "CXX={cxx} " - "LDFLAGS=-mmacosx-version-min=10.9 " + "'LDFLAGS=-isysroot {sysroot} -mmacosx-version-min=10.9' " ).format( cxx=self.toolchain.cxx, sysroot=xcrun.sdk_path('macosx') diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 58f6c32b881c9..b3ddc61e64916 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -62,7 +62,7 @@ "llbuild": "master", "swift-tools-support-core": "master", "swiftpm": "swiftwasm", - "swift-argument-parser": "0.0.6", + "swift-argument-parser": "0.3.0", "swift-driver": "master", "swift-syntax": "master", "swift-stress-tester": "master", @@ -113,7 +113,7 @@ "llbuild": "master", "swift-tools-support-core": "master", "swiftpm": "master", - "swift-argument-parser": "0.0.6", + "swift-argument-parser": "0.3.0", "swift-driver": "master", "swift-syntax": "master", "swift-stress-tester": "master", @@ -143,7 +143,7 @@ "llbuild": "master", "swift-tools-support-core": "master", "swiftpm": "master", - "swift-argument-parser": "0.0.6", + "swift-argument-parser": "0.3.0", "swift-driver": "master", "swift-syntax": "master", "swift-stress-tester": "master", @@ -366,6 +366,8 @@ "llbuild": "master", "swift-tools-support-core": "master", "swiftpm": "master", + "swift-argument-parser": "0.3.0", + "swift-driver": "master", "swift-syntax": "master", "swift-stress-tester": "master", "swift-corelibs-xctest": "master", @@ -375,6 +377,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-65-1", + "yams": "3.0.1", "cmake": "v3.16.5", "indexstore-db": "master", "sourcekit-lsp": "master", diff --git a/utils/webassembly/build-foundation.sh b/utils/webassembly/build-foundation.sh index 6d15e0ba5b216..9550c975780bc 100755 --- a/utils/webassembly/build-foundation.sh +++ b/utils/webassembly/build-foundation.sh @@ -3,11 +3,7 @@ set -ex DESTINATION_TOOLCHAIN=$1 SOURCE_PATH="$(cd "$(dirname $0)/../../.." && pwd)" -# Remove host CoreFoundation (which can be different from the target) headers -# to avoid shadowing the wasm32 target CoreFoundation -rm -rf $DESTINATION_TOOLCHAIN/usr/lib/swift/CoreFoundation - -FOUNDATION_BUILD="$SOURCE_PATH/build/Ninja-ReleaseAssert/foundation-wasi-wasm32" +FOUNDATION_BUILD="$SOURCE_PATH/target-build/Ninja-ReleaseAssert/foundation-wasi-wasm32" mkdir -p $FOUNDATION_BUILD cd $FOUNDATION_BUILD @@ -19,15 +15,12 @@ cmake -G Ninja \ -DWASI_SDK_PATH="$SOURCE_PATH/wasi-sdk" \ -DICU_ROOT="$SOURCE_PATH/icu_out" \ -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_Swift_COMPILER_FORCED=ON \ "${SOURCE_PATH}/swift-corelibs-foundation" ninja -v ninja -v install -# On macOS the target CoreFoundation shadows the CoreFoundation suppplied by Xcode. -# On Linux though there's no system CoreFoundation, its headers have to be shipped -# in the installable archive and serve for both host and target. -if [[ "$(uname)" == "Darwin" ]]; then - mv $DESTINATION_TOOLCHAIN/usr/lib/swift/CoreFoundation \ - $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32/CoreFoundation -fi \ No newline at end of file +# .swiftdoc and .swiftmodule files should live in `swift`, not in `swift_static` +mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/wasi/wasm32/Foundation.swift* \ + $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32 diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index 72f246b487201..527556c0d87b2 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -11,11 +11,13 @@ case $(uname -s) in OS_SUFFIX=osx HOST_PRESET=webassembly-host TARGET_PRESET=webassembly-macos-target + HOST_SUFFIX=macosx-x86_64 ;; Linux) OS_SUFFIX=linux HOST_PRESET=webassembly-linux-host TARGET_PRESET=webassembly-linux-target + HOST_SUFFIX=linux-x86_64 ;; *) echo "Unrecognised platform $(uname -s)" @@ -29,7 +31,6 @@ DAY=$(date +"%d") TOOLCHAIN_VERSION="${YEAR}${MONTH}${DAY}" TOOLCHAIN_NAME="swift-wasm-DEVELOPMENT-SNAPSHOT-${YEAR}-${MONTH}-${DAY}-a" ARCHIVE="${TOOLCHAIN_NAME}-${OS_SUFFIX}.tar.gz" -INSTALLABLE_PACKAGE=$SOURCE_PATH/$ARCHIVE PACKAGE_ARTIFACT="$SOURCE_PATH/swift-wasm-DEVELOPMENT-SNAPSHOT-${OS_SUFFIX}.tar.gz" @@ -37,52 +38,85 @@ BUNDLE_IDENTIFIER="swiftwasm.${YEAR}${MONTH}${DAY}" DISPLAY_NAME_SHORT="Swift for WebAssembly Development Snapshot" DISPLAY_NAME="${DISPLAY_NAME_SHORT} ${YEAR}-${MONTH}-${DAY}" +DIST_TOOLCHAIN_DESTDIR=$SOURCE_PATH/dist-toolchain-sdk HOST_TOOLCHAIN_DESTDIR=$SOURCE_PATH/host-toolchain-sdk +TARGET_TOOLCHAIN_DESTDIR=$SOURCE_PATH/target-toolchain-sdk + +DIST_TOOLCHAIN_SDK=$DIST_TOOLCHAIN_DESTDIR/$TOOLCHAIN_NAME HOST_TOOLCHAIN_SDK=$HOST_TOOLCHAIN_DESTDIR/$TOOLCHAIN_NAME +TARGET_TOOLCHAIN_SDK=$TARGET_TOOLCHAIN_DESTDIR/$TOOLCHAIN_NAME + + +HOST_BUILD_ROOT=$SOURCE_PATH/host-build +TARGET_BUILD_ROOT=$SOURCE_PATH/target-build +HOST_BUILD_DIR=$HOST_BUILD_ROOT/Ninja-ReleaseAssert +TARGET_BUILD_DIR=$TARGET_BUILD_ROOT/Ninja-ReleaseAssert # Avoid clang headers symlink issues mkdir -p $HOST_TOOLCHAIN_SDK/usr/lib/clang/10.0.0 -# Build the host toolchain and SDK first. -$SOURCE_PATH/swift/utils/build-script \ - --preset=$HOST_PRESET \ - INSTALL_DESTDIR="$HOST_TOOLCHAIN_DESTDIR" \ - TOOLCHAIN_NAME="$TOOLCHAIN_NAME" \ - C_CXX_LAUNCHER="$(which sccache)" - -# Clean up the host toolchain build directory so that the next -# `build-script` invocation doesn't pick up wrong CMake config files. -# For some reason passing `--reconfigure` to `build-script` won't do this. -rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/swift-* - -# build the cross-compilled toolchain -$SOURCE_PATH/swift/utils/build-script \ - --preset=$TARGET_PRESET \ - INSTALL_DESTDIR="$SOURCE_PATH/install" \ - SOURCE_PATH="$SOURCE_PATH" \ - BUNDLE_IDENTIFIER="${BUNDLE_IDENTIFIER}" \ - DISPLAY_NAME="${DISPLAY_NAME}" \ - DISPLAY_NAME_SHORT="${DISPLAY_NAME_SHORT}" \ - TOOLCHAIN_NAME="${TOOLCHAIN_NAME}" \ - TOOLCHAIN_VERSION="${TOOLCHAIN_VERSION}" \ - C_CXX_LAUNCHER="$(which sccache)" - -# Merge wasi-sdk and the toolchain -cp -a $WASI_SDK_PATH/lib/clang $HOST_TOOLCHAIN_SDK/usr/lib -cp -a $WASI_SDK_PATH/bin/{*ld,llvm-ar} $HOST_TOOLCHAIN_SDK/usr/bin -cp -r $WASI_SDK_PATH/share/wasi-sysroot $HOST_TOOLCHAIN_SDK/usr/share - -# Replace absolute sysroot path with relative path -sed -i -e "s@\".*/include@\"../../../../share/wasi-sysroot/include@g" $SOURCE_PATH/install/$TOOLCHAIN_NAME/usr/lib/swift/wasi/wasm32/glibc.modulemap - -# Copy the target environment stdlib into the toolchain - -# Avoid copying usr/lib/swift/clang because our toolchain's one is a directory -# but nightly's one is symbolic link. A simple copy fails to merge them. -rsync -v -a $SOURCE_PATH/install/$TOOLCHAIN_NAME/usr/lib/ $HOST_TOOLCHAIN_SDK/usr/lib/ --exclude 'swift/clang' - -$UTILS_PATH/build-foundation.sh $HOST_TOOLCHAIN_SDK -$UTILS_PATH/build-xctest.sh $HOST_TOOLCHAIN_SDK - -cd $HOST_TOOLCHAIN_DESTDIR +build_host_toolchain() { + # Build the host toolchain and SDK first. + env SWIFT_BUILD_ROOT="$HOST_BUILD_ROOT" \ + $SOURCE_PATH/swift/utils/build-script \ + --preset=$HOST_PRESET \ + --build-dir="$HOST_BUILD_DIR" \ + INSTALL_DESTDIR="$HOST_TOOLCHAIN_DESTDIR" \ + TOOLCHAIN_NAME="$TOOLCHAIN_NAME" \ + C_CXX_LAUNCHER="$(which sccache)" +} + +build_target_toolchain() { + mkdir -p $HOST_BUILD_DIR/ + # Copy the host build dir to reuse it. + if [[ ! -e "$HOST_BUILD_DIR/llvm-$HOST_SUFFIX" ]]; then + cp -r "$HOST_BUILD_DIR/llvm-$HOST_SUFFIX" "$TARGET_BUILD_DIR/llvm-$HOST_SUFFIX" + # Clean up compiler-rt dir to cross compile it for host and wasm32 + (cd "$TARGET_BUILD_DIR/llvm-$HOST_SUFFIX" && ninja compiler-rt-clear) + fi + + # build the cross-compilled toolchain + env SWIFT_BUILD_ROOT="$TARGET_BUILD_ROOT" \ + $SOURCE_PATH/swift/utils/build-script \ + --preset=$TARGET_PRESET --reconfigure \ + --build-dir="$TARGET_BUILD_DIR" \ + INSTALL_DESTDIR="$TARGET_TOOLCHAIN_DESTDIR" \ + SOURCE_PATH="$SOURCE_PATH" \ + BUNDLE_IDENTIFIER="${BUNDLE_IDENTIFIER}" \ + DISPLAY_NAME="${DISPLAY_NAME}" \ + DISPLAY_NAME_SHORT="${DISPLAY_NAME_SHORT}" \ + TOOLCHAIN_NAME="${TOOLCHAIN_NAME}" \ + TOOLCHAIN_VERSION="${TOOLCHAIN_VERSION}" \ + TOOLS_BIN_DIR="${HOST_TOOLCHAIN_SDK}/usr/bin" \ + C_CXX_LAUNCHER="$(which sccache)" + + $UTILS_PATH/build-foundation.sh $TARGET_TOOLCHAIN_SDK + $UTILS_PATH/build-xctest.sh $TARGET_TOOLCHAIN_SDK + +} + +merge_toolchains() { + rm -rf "$DIST_TOOLCHAIN_DESTDIR" + # Copy the base host toolchain + cp -r "$HOST_TOOLCHAIN_DESTDIR" "$DIST_TOOLCHAIN_DESTDIR" + + # Merge wasi-sdk and the toolchain + cp -r $WASI_SDK_PATH/share/wasi-sysroot $DIST_TOOLCHAIN_SDK/usr/share + + # Copy the target environment stdlib into the toolchain + # Avoid copying usr/lib/swift/clang because our toolchain's one is a directory + # but nightly's one is symbolic link. A simple copy fails to merge them. + rsync -v -a $TARGET_TOOLCHAIN_SDK/usr/lib/ $DIST_TOOLCHAIN_SDK/usr/lib/ --exclude 'swift/clang' + rsync -v -a $TARGET_TOOLCHAIN_SDK/usr/bin/ $DIST_TOOLCHAIN_SDK/usr/bin/ + + # Replace absolute sysroot path with relative path + sed -i -e "s@\".*/include@\"../../../../share/wasi-sysroot/include@g" $DIST_TOOLCHAIN_SDK/usr/lib/swift/wasi/wasm32/glibc.modulemap +} + +build_host_toolchain +build_target_toolchain + +merge_toolchains + +cd $DIST_TOOLCHAIN_DESTDIR tar cfz $PACKAGE_ARTIFACT $TOOLCHAIN_NAME diff --git a/utils/webassembly/build-xctest.sh b/utils/webassembly/build-xctest.sh index e08e0cef33db1..fe93f244ce0b3 100755 --- a/utils/webassembly/build-xctest.sh +++ b/utils/webassembly/build-xctest.sh @@ -3,7 +3,7 @@ set -ex DESTINATION_TOOLCHAIN=$1 SOURCE_PATH="$(cd "$(dirname $0)/../../.." && pwd)" -BUILD_DIR="$SOURCE_PATH/build/Ninja-ReleaseAssert/xctest-wasi-wasm32" +BUILD_DIR="$SOURCE_PATH/target-build/Ninja-ReleaseAssert/xctest-wasi-wasm32" mkdir -p $BUILD_DIR cd $BUILD_DIR @@ -14,6 +14,7 @@ cmake -G Ninja \ -DCMAKE_TOOLCHAIN_FILE="$SOURCE_PATH/swift/utils/webassembly/toolchain-wasi.cmake" \ -DWASI_SDK_PATH="$SOURCE_PATH/wasi-sdk" \ -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_Swift_COMPILER_FORCED=ON \ -DSWIFT_FOUNDATION_PATH=$DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32 \ "${SOURCE_PATH}/swift-corelibs-xctest" diff --git a/utils/webassembly/ci.sh b/utils/webassembly/ci.sh index c3ffb2877bbdc..6da8cf9f4b86a 100755 --- a/utils/webassembly/ci.sh +++ b/utils/webassembly/ci.sh @@ -13,7 +13,7 @@ fi BUILD_SCRIPT=$UTILS_PATH/build-toolchain.sh RUN_TEST_BIN=$SWIFT_PATH/utils/run-test -BUILD_DIR=$SOURCE_PATH/build/Ninja-ReleaseAssert +TARGET_BUILD_DIR=$SOURCE_PATH/target-build/Ninja-ReleaseAssert $DEPENDENCIES_SCRIPT @@ -26,14 +26,16 @@ $BUILD_SCRIPT if [[ "$(uname)" == "Darwin" ]]; then # workaround: host target test directory is necessary to use run-test - mkdir -p $BUILD_DIR/swift-macosx-x86_64/test-macosx-x86_64 + mkdir -p $TARGET_BUILD_DIR/swift-macosx-x86_64/test-macosx-x86_64 fi -$RUN_TEST_BIN --build-dir $BUILD_DIR --target wasi-wasm32 test/stdlib/ - if [[ "$(uname)" == "Linux" ]]; then + $RUN_TEST_BIN --build-dir $TARGET_BUILD_DIR --target wasi-wasm32 test/stdlib/ || true echo "Skip running test suites for Linux" else + + $RUN_TEST_BIN --build-dir $TARGET_BUILD_DIR --target wasi-wasm32 test/stdlib/ + # Run test but ignore failure temporarily $BUILD_SCRIPT -t || true fi diff --git a/utils/webassembly/compiler-rt-cache.cmake b/utils/webassembly/compiler-rt-cache.cmake new file mode 100644 index 0000000000000..ef35520e839c6 --- /dev/null +++ b/utils/webassembly/compiler-rt-cache.cmake @@ -0,0 +1,14 @@ +set(COMPILER_RT_DEFAULT_TARGET_ARCH wasm32 CACHE STRING "" FORCE) +set(COMPILER_RT_DEFAULT_TARGET_ONLY TRUE CACHE BOOL "" FORCE) +set(CMAKE_C_COMPILER_TARGET wasm32-wasi CACHE STRING "" FORCE) +set(CMAKE_C_COMPILER_FORCED TRUE CACHE BOOL "") +set(CMAKE_CXX_COMPILER_FORCED TRUE CACHE BOOL "") +set(CMAKE_SYSTEM_NAME Wasm) +set(CMAKE_SYSROOT ${COMPILER_RT_SWIFT_WASI_SDK_PATH}/share/wasi-sysroot CACHE STRING "") +set(CMAKE_SIZEOF_VOID_P 4 CACHE STRING "") +set(COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "") +set(COMPILER_RT_BUILD_XRAY OFF CACHE BOOL "") +set(COMPILER_RT_INCLUDE_TESTS OFF CACHE BOOL "") +set(COMPILER_RT_HAS_FPIC_FLAG OFF CACHE BOOL "") +set(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN OFF CACHE BOOL "") +set(COMPILER_RT_OS_DIR wasi CACHE STRING "") diff --git a/utils/webassembly/macos/install-dependencies.sh b/utils/webassembly/macos/install-dependencies.sh index 8e715d101d874..59394716e1b5a 100755 --- a/utils/webassembly/macos/install-dependencies.sh +++ b/utils/webassembly/macos/install-dependencies.sh @@ -2,7 +2,7 @@ set -ex -brew uninstall python@2 || true +brew uninstall $(brew list | grep python@2) brew install cmake ninja llvm sccache wasmer SOURCE_PATH="$( cd "$(dirname $0)/../../../../" && pwd )" diff --git a/utils/webassembly/static-executable-args.lnk b/utils/webassembly/static-executable-args.lnk index 2d8c872154c5f..ec481f273908c 100644 --- a/utils/webassembly/static-executable-args.lnk +++ b/utils/webassembly/static-executable-args.lnk @@ -11,5 +11,5 @@ -lwasi-emulated-mman -Xlinker --error-limit=0 -Xlinker --no-gc-sections --Xlinker --no-threads +-Xlinker --threads=1 -D_WASI_EMULATED_MMAN diff --git a/validation-test/Casting/BoxingCasts.swift.gyb b/validation-test/Casting/BoxingCasts.swift.gyb new file mode 100644 index 0000000000000..7ee19e67a85fb --- /dev/null +++ b/validation-test/Casting/BoxingCasts.swift.gyb @@ -0,0 +1,264 @@ +// BoxingCasts.swift - Tests for boxing/unboxing casts +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +// ----------------------------------------------------------------------------- +/// +/// Contains tests for existential, optional, and other casts that box/unbox values. +/// +// ----------------------------------------------------------------------------- +// RUN: %empty-directory(%t) +// +// RUN: %gyb %s -o %t/BoxingCasts.swift +// RUN: %line-directive %t/BoxingCasts.swift -- %target-build-swift -g -module-name a -swift-version 5 -Onone %t/BoxingCasts.swift -o %t/a.swift5.Onone.out +// RUN: %target-codesign %t/a.swift5.Onone.out +// RUN: %line-directive %t/BoxingCasts.swift -- %target-run %t/a.swift5.Onone.out +// +// Note: The RUN directives above override the default test optimizations. +// This test is deliberately run non-optimized in order to verify the +// behavior of runtime methods that may not be called for optimized casts. +// +// XXX FIXME XXX TODO XXX _Also_ build this with optimizations in order to +// verify compiler behaviors. +// +// REQUIRES: executable_test + +import StdlibUnittest +#if _runtime(_ObjC) +import Foundation +#endif + +fileprivate func runtimeCast (_ x: From, to: To.Type) -> To? { + return x as? To +} + +fileprivate func optional(_ x: T) -> Optional { + return runtimeCast(x, to: Optional.self)! +} + +fileprivate protocol FilePrivateProtocol {} +internal protocol InternalProtocol {} +public protocol PublicProtocol {} +protocol UnimplementedProtocol {} + +fileprivate enum EmptyEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { } + +fileprivate enum SingleCaseEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { +case case0 + init() {self = .case0} +} + +fileprivate enum TrivialPayloadEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { +case payloadCase(Int) + init() {self = .payloadCase(42)} +} + +extension TrivialPayloadEnum: Hashable {} + +fileprivate enum MultiPayloadEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { +case case0(String) +case case1(Int) + init() {self = .case1(42)} +} + +extension MultiPayloadEnum: Hashable {} + +fileprivate class ClassInt: FilePrivateProtocol, InternalProtocol, PublicProtocol { + public var value: Int + private var tracker = LifetimeTracked(77) + init(_ v: Int = 42) {value = v} +} + +extension ClassInt: Equatable, Hashable { + static func ==(left: ClassInt, right: ClassInt) -> Bool {left.value == right.value} + func hash(into hasher: inout Hasher) { value.hash(into: &hasher) } +} + +fileprivate struct StructInt: FilePrivateProtocol, InternalProtocol, PublicProtocol { + public var value: Int + private var tracker = LifetimeTracked(77) + init(_ v: Int = 42) { value = v} +} + +extension StructInt: Hashable, Equatable { } + +#if _runtime(_ObjC) +fileprivate class OCClassInt: NSObject, FilePrivateProtocol, InternalProtocol, PublicProtocol { + public var value: Int + private var tracker = LifetimeTracked(77) + init(_ v: Int = 42) { value = v} +} +#endif + +let BoxingCasts = TestSuite("BoxingCasts") + +%{ +import random +# The test body goes into a named function and the test case just invokes that +# function by name. This makes debugging easier, since it's easier to set break +# points on named functions than on arbitrary closures. +# The function names are included in the test name +# for ease of reference. +testNumber = 0 +def testFunctionName(): + return "test{number}".format(number=testNumber) +def nextTestNumber(): + global testNumber + testNumber += 1 + +# Type used for intermediate casts. The base object gets +# cast to one or more of these before the final test. +class Box: + def __init__(self, name, typeName=None, cast=None): + self.name = name + self.typeName = typeName or name + self.cast_template = cast or "runtimeCast({expr}, to: {typeName}.self)!" + def cast_oper(self, expr): + return self.cast_template.format(expr=expr, typeName=self.typeName) + +anyHashableBox = Box(name="AnyHashable") +all_boxes = [ + Box(name="Any", typeName="Any"), + Box(name="AnyStatic", cast="({expr} as Any)"), + Box(name="AnyObject"), + Box(name="SwiftValueBox", cast="_bridgeAnythingToObjectiveC({expr})"), + Box(name="Optional", cast="optional({expr})") +] +protocol_boxes = [ + Box(name="PublicProtocol"), +# Box(name="FilePrivateProtocol"), # Blocked by SR-2620 aka rdar://28281488 + Box(name="InternalProtocol"), +] + +# Describes a base object that will be subject to a variety of casts +default_protocols = [ + "PublicProtocol", + "InternalProtocol", + # "FilePrivateProtocol" # Blocked by SR-2620 aka rdar://28281488 +] + +class Contents: + def __init__(self, name, constructor=None, extra_targets=[], hashable=True, roundtrips=True, protocols=default_protocols, objc_only=False): + self.name = name + self.constructor = constructor or "{name}()".format(name=name) + self.objc_only = objc_only + + self.targets = ["Any"] + self.targets.extend(protocols) + self.targets.extend(extra_targets) + if roundtrips: + self.targets.append(self.name) + + self.boxes = [] + self.boxes.extend(all_boxes) + self.boxes.extend([Box(name=n) for n in protocols]) + if hashable: + self.boxes.append(anyHashableBox) + +contents = [ + Contents(name="StructInt", + # extra_targets=["StructInt?"], + ), + Contents(name="StructInt?", + constructor="Optional.some(StructInt())", + extra_targets=["StructInt"], + roundtrips=False, # Compiler bug rejects roundtrip cast T? => Any => T? + ), + Contents(name="ClassInt"), + Contents(name="OCClassInt", objc_only=True), + Contents(name="SingleCaseEnum"), + Contents(name="TrivialPayloadEnum"), + Contents(name="TrivialPayloadEnum"), + Contents(name="MultiPayloadEnum"), + Contents(name="StructInt.Type", + constructor="StructInt.self", + hashable=False, + protocols=[], + ), + Contents(name="StructInt.Type?", + constructor="Optional.some(StructInt.self)", + hashable=False, + protocols=[], + extra_targets=["StructInt.Type"], + roundtrips=False, # Compiler bug rejects roundtrip cast T? => Any => T? + ), + Contents(name="PublicProtocol.Protocol", + constructor="PublicProtocol.self", + hashable=False, + protocols=[], + ), +] + +# Code below generates a separate test case for each combination of content, +# target type, and one or more box/intermediate types. +}% + +% for content in contents: +% if content.objc_only: +#if _runtime(_ObjC) +% end +% for target in content.targets: +% for box in content.boxes: +% nextTestNumber() +BoxingCasts.test("${testFunctionName()}(): Casting ${box.name}(${content.name}) to ${target}") { + // TODO: Selectively enable/disable cases that work with earlier stdlib + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + ${testFunctionName()}() + } +} +func ${testFunctionName()}() { + let a = ${content.constructor} + let b = ${box.cast_oper("a")} +% # // Skip trivial cast from T? to T +% if not (content.name == target and box.name == "Optional"): +% # // Skip trivial cast from protocol box to protocol +% if box.name != target: +% # // Skip trivial cast from T? => P +% if not (target.endswith("Protocol") and box.name == "Optional"): + let c = /* ${box.name}(${content.name})) */ b as? ${target} + expectNotNil(c) +% end +% end +% end + let d = runtimeCast(/* ${box.name}(${content.name}) */ b, to: ${target}.self) + expectNotNil(d) +} + +% for innerBox in [random.choice(content.boxes)]: +% nextTestNumber() +BoxingCasts.test("${testFunctionName()}(): Casting ${box.name}(${innerBox.name}(${content.name})) to ${target}") { + // TODO: Selectively enable/disable cases that work with earlier stdlib + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + ${testFunctionName()}() + } +} +func ${testFunctionName()}() { + let a = ${content.constructor} + let b = ${innerBox.cast_oper("a")} + let c = ${box.cast_oper("b")} +% # // Skip trivial cast from T? to T +% if not (innerBox.name == target and box.name == "Optional"): +% # // Skip trivial cast from protocol box to protocol +% if box.name != target: + let d = /* ${box.name}(${innerBox.name}(${content.name})) */ c as? ${target} + expectNotNil(d) +% end +% end + let e = runtimeCast(/* ${box.name}(${innerBox.name}(${content.name})) */ c, to: ${target}.self) + expectNotNil(e) +} +% end +% end +% end +% if content.objc_only: +#endif +% end +% end + +runAllTests() diff --git a/validation-test/IDE/crashers_2_fixed/rdar67102611.swift b/validation-test/IDE/crashers_2_fixed/rdar67102611.swift new file mode 100644 index 0000000000000..c5069e7550cbb --- /dev/null +++ b/validation-test/IDE/crashers_2_fixed/rdar67102611.swift @@ -0,0 +1,6 @@ +// RUN: %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s > /dev/null + +for x in "foo" { + if x.#^A^# { + } +} diff --git a/validation-test/ParseableInterface/verify_all_overlays.py b/validation-test/ParseableInterface/verify_all_overlays.py index 631ddd0666a92..e1ce62e248f54 100755 --- a/validation-test/ParseableInterface/verify_all_overlays.py +++ b/validation-test/ParseableInterface/verify_all_overlays.py @@ -12,7 +12,7 @@ # RUN: test ! -e %t/failures.txt || \ # RUN: diff %t/filter.txt %t/failures.txt -# REQUIRES: nonexecutable_test +# REQUIRES: nonexecutable_test, no_asan # Expected failures by platform # ----------------------------- diff --git a/validation-test/Reflection/existentials.swift b/validation-test/Reflection/existentials.swift index ce17f8f4916d2..ea8b44587b350 100644 --- a/validation-test/Reflection/existentials.swift +++ b/validation-test/Reflection/existentials.swift @@ -281,17 +281,17 @@ protocol Composition : P, Q {} struct S : Composition {} func getComposition() -> P & Q { return S() } reflect(any: getComposition()) -// CHECK-64: Mangled name: $s12existentials1PP_AA1QPp +// CHECK-64: Mangled name: $s12existentials1P_AA1Qp // CHECK-64: Demangled name: existentials.P & existentials.Q -// CHECK-32: Mangled name: $s12existentials1PP_AA1QPp +// CHECK-32: Mangled name: $s12existentials1P_AA1Qp // CHECK-32: Demangled name: existentials.P & existentials.Q // Metatype: reflect(any: Int.self) -// CHECK-64: Mangled name: $sSim -// CHECK-64: Demangled name: Swift.Int.Type -// CHECK-32: Mangled name: $sSim -// CHECK-32: Demangled name: Swift.Int.Type +// CHECK-64: Mangled name: $sSiXMt +// CHECK-64: Demangled name: @thin Swift.Int.Type +// CHECK-32: Mangled name: $sSiXMt +// CHECK-32: Demangled name: @thin Swift.Int.Type protocol WithType { associatedtype T diff --git a/validation-test/Runtime/weak-reference-racetests.swift b/validation-test/Runtime/weak-reference-racetests.swift index 1d759c12c60ff..23fc108b6f9f0 100644 --- a/validation-test/Runtime/weak-reference-racetests.swift +++ b/validation-test/Runtime/weak-reference-racetests.swift @@ -1,7 +1,7 @@ // RUN: %target-run-simple-swift // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest diff --git a/validation-test/SILOptimizer/large_string_array.swift.gyb b/validation-test/SILOptimizer/large_string_array.swift.gyb index 91280bd424040..6b6093f78552b 100644 --- a/validation-test/SILOptimizer/large_string_array.swift.gyb +++ b/validation-test/SILOptimizer/large_string_array.swift.gyb @@ -12,12 +12,10 @@ // REQUIRES: long_test // REQUIRES: CPU=arm64 || CPU=x86_64 -// REQUIRES: rdar66807959 - // Check if the optimizer can optimize the whole array into a statically // initialized global -// CHECK: sil_global private @globalinit_{{.*}} : $_ContiguousArrayStorage = { +// CHECK: sil_global private @{{.*9str_array.*}}WZTv_ : $_ContiguousArrayStorage = { // CHECK: %initval = object $_ContiguousArrayStorage public let str_array: [String] = [ diff --git a/validation-test/SILOptimizer/string_switch.swift b/validation-test/SILOptimizer/string_switch.swift index b30c80b7cc48e..555c1d972847c 100644 --- a/validation-test/SILOptimizer/string_switch.swift +++ b/validation-test/SILOptimizer/string_switch.swift @@ -4,7 +4,7 @@ // REQUIRES: swift_stdlib_no_asserts,optimized_stdlib // REQUIRES: stress_test // REQUIRES: executable_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest diff --git a/validation-test/StdlibUnittest/AtomicInt.swift b/validation-test/StdlibUnittest/AtomicInt.swift index 00bf5d1c0f8c2..9bc3e8b3f1f8a 100644 --- a/validation-test/StdlibUnittest/AtomicInt.swift +++ b/validation-test/StdlibUnittest/AtomicInt.swift @@ -4,7 +4,7 @@ // RUN: %target-run %t.out // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import SwiftPrivate import StdlibUnittest diff --git a/validation-test/StdlibUnittest/RaceTest.swift b/validation-test/StdlibUnittest/RaceTest.swift index b3c296036f371..d0f1efc0ef750 100644 --- a/validation-test/StdlibUnittest/RaceTest.swift +++ b/validation-test/StdlibUnittest/RaceTest.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -disable-access-control -module-name a %s -o %t.out // RUN: %target-run %t.out | %FileCheck %s // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import SwiftPrivate import StdlibUnittest diff --git a/validation-test/compiler_crashers_2_fixed/rdar62268062.swift b/validation-test/compiler_crashers_2_fixed/rdar62268062.swift new file mode 100644 index 0000000000000..21b59a843ff98 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar62268062.swift @@ -0,0 +1,41 @@ +// RUN: %target-swift-frontend -emit-ir %s + +public protocol HorseSaddle {} +public enum EnglishSaddle : HorseSaddle {} + +public enum WesternSaddle : HorseSaddle {} + +public protocol Horse { + associatedtype Body : Horse + + associatedtype Saddle: HorseSaddle + + var body: Body { get } +} + +extension Horse { + typealias Saddle = Body.Saddle +} + +public struct DraftHorse : Pony { + public typealias Saddle = EnglishSaddle + public typealias Body = Never + var contents: T +} + +// MARK: - Implementation detail + +extension Never : Horse { + public typealias Saddle = EnglishSaddle + public typealias Body = Never + + public var body: Never { + switch self {} + } +} + +protocol Pony : Horse where Body == Never {} +extension Pony { + public var body: Never { fatalError() } +} + diff --git a/validation-test/compiler_crashers_2_fixed/rdar65272763.swift b/validation-test/compiler_crashers_2_fixed/rdar65272763.swift new file mode 100644 index 0000000000000..f3233a7afd131 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar65272763.swift @@ -0,0 +1,21 @@ +// RUN: %target-swift-frontend -emit-ir %s + +public struct S1 {} +public extension S1 where T1 == Int { + public struct S2 { + let value: T2 + + public init(value: T2) { + self.value = value + } + } + + public init(s: [S2]) { + self.init() + + s.forEach { _ in + + } + } +} + diff --git a/validation-test/compiler_crashers_2_fixed/rdar67239650.swift b/validation-test/compiler_crashers_2_fixed/rdar67239650.swift new file mode 100644 index 0000000000000..5ec036b8b61cf --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar67239650.swift @@ -0,0 +1,24 @@ +// RUN: %target-swift-frontend -typecheck %s + +@_functionBuilder +struct SillyBuilder { + static func buildBlock() -> () {} +} + +struct SillyStruct { + init(@SillyBuilder _: () -> ()) {} +} + +struct UsesSillyStruct { + var x: Int = 0 + + func foo() { + SillyStruct { + let fn = { + if true { + _ = x + } + } + } + } +} diff --git a/validation-test/compiler_crashers_2_fixed/rdar67259506.swift b/validation-test/compiler_crashers_2_fixed/rdar67259506.swift new file mode 100644 index 0000000000000..4f3360980adc4 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar67259506.swift @@ -0,0 +1,29 @@ +// RUN: %target-swift-frontend -emit-ir %s + +public func foo(_: T, _: S.A) {} + +public protocol P { + associatedtype A + + func foo() -> A +} + +public protocol Q { + associatedtype A + + func bar() -> A +} + +public struct S {} + +extension S : P where T : P { + public func foo() -> Int { + return 0 + } +} + +extension S : Q where T : Q { + public func bar() -> Int { + return 0 + } +} diff --git a/validation-test/compiler_crashers_2_fixed/sr12327.swift b/validation-test/compiler_crashers_2_fixed/sr12327.swift new file mode 100644 index 0000000000000..33a5140a92d27 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr12327.swift @@ -0,0 +1,42 @@ +// RUN: %target-swift-frontend -emit-ir -O %s + +protocol A { + associatedtype Foo // Does not crash if renamed +} + +protocol B { + associatedtype Foo // Does not crash if renamed + var aFoo: Foo { get } +} + +public struct Wrapper { + let wrapped: T +} + +// Removing this extension or combining it with the next one prevents the crash +extension Wrapper: A where T: A { + typealias Foo = Wrapper +} + +extension Wrapper: B where T: B { + var aFoo: Wrapper { + return .init(wrapped: wrapped.aFoo) + } +} + +public struct Model: B { + public struct Foo {} + + public var aFoo: Foo { + return Foo() + } +} + +// Attempting to specialize this method for Wrapper crashes the compiler +func fooString(body: Body) -> String { + return "\(body.aFoo)" +} + +public func foo(_ command: Wrapper) -> String { + return fooString(body: command) +} diff --git a/validation-test/compiler_crashers_2_fixed/sr12691.swift b/validation-test/compiler_crashers_2_fixed/sr12691.swift new file mode 100644 index 0000000000000..33c98979944fd --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr12691.swift @@ -0,0 +1,23 @@ +// RUN: not %target-swift-frontend -typecheck %s + +struct CountSteps1 : Collection { + init(count: Int) { self.count = count } + var count: Int + + var startIndex: Int { 0 } + var endIndex: Int { count } + func index(after i: Int) -> Int { + totalSteps += 1 + return i + 1 + } + subscript(i: Int) -> Int { return i } +} + +extension CountSteps1 + : RandomAccessCollection, BidirectionalCollection + where T : Equatable +{ + func index(_ i: Index, offsetBy d: Int) -> Index { + return i + d + } +} diff --git a/validation-test/compiler_crashers_2_fixed/sr13141.swift b/validation-test/compiler_crashers_2_fixed/sr13141.swift new file mode 100644 index 0000000000000..fe403d1ce6c1c --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr13141.swift @@ -0,0 +1,12 @@ +// RUN: %target-swift-frontend -emit-ir %s + +public protocol Book { + associatedtype Name +} +public protocol BookDecorator: Book where Name == DecoratedBook.Name { + associatedtype DecoratedBook: Book + associatedtype Name = DecoratedBook.Name +} +public class ConcreteBookDecorator: BookDecorator { + public typealias DecoratedBook = T +} diff --git a/validation-test/compiler_crashers_2_fixed/sr13461.swift b/validation-test/compiler_crashers_2_fixed/sr13461.swift new file mode 100644 index 0000000000000..b6bda64bdce53 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr13461.swift @@ -0,0 +1,17 @@ +// RUN: %target-swift-frontend -disable-availability-checking -emit-ir -o /dev/null %s +// REQUIRES: asserts + +final class Klass { + static var current: Klass { + fatalError() + } +} +private struct Build { + let val: T + unowned let unownedBinding = Klass.current + unowned(unsafe) let unownedUnsafeBinding = Klass.current + weak var weakBinding = Klass.current +} +private func phase(_ val: T) -> Build { + return Build(val: val) +} diff --git a/validation-test/compiler_crashers_2_fixed/sr9199.swift b/validation-test/compiler_crashers_2_fixed/sr9199.swift index 422f46b5579ba..609bb9e4ad46c 100644 --- a/validation-test/compiler_crashers_2_fixed/sr9199.swift +++ b/validation-test/compiler_crashers_2_fixed/sr9199.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-ir -o %t.ll %s +// RUN: not %target-swift-frontend -emit-ir %s // Just make sure we don't crash. @@ -54,4 +54,4 @@ extension Controller: WithReturnType { let controller = Controller() -controller.returnTheThing() \ No newline at end of file +controller.returnTheThing() diff --git a/validation-test/lit.site.cfg.in b/validation-test/lit.site.cfg.in index 12aaec7150e00..649281bef0df2 100644 --- a/validation-test/lit.site.cfg.in +++ b/validation-test/lit.site.cfg.in @@ -87,8 +87,8 @@ if "@SWIFT_OPTIMIZED@" == "TRUE": if "@SWIFT_ENABLE_SOURCEKIT_TESTS@" == "TRUE": config.available_features.add('sourcekit') -if "@SWIFT_STDLIB_USE_NONATOMIC_RC@" == "TRUE": - config.available_features.add("nonatomic_rc") +if "@SWIFT_STDLIB_SINGLE_THREADED_RUNTIME@" == "TRUE": + config.available_features.add("single_threaded_runtime") if "@SWIFT_BUILT_STANDALONE@" == "TRUE": config.available_features.add('standalone_build') diff --git a/validation-test/stdlib/ArrayBridging.swift b/validation-test/stdlib/ArrayBridging.swift index 3fd92fa951dda..6c24bfe8dd0cf 100644 --- a/validation-test/stdlib/ArrayBridging.swift +++ b/validation-test/stdlib/ArrayBridging.swift @@ -9,7 +9,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest import Foundation diff --git a/validation-test/stdlib/CommandLine.swift b/validation-test/stdlib/CommandLine.swift index 610ec08eee400..a43defe135d37 100644 --- a/validation-test/stdlib/CommandLine.swift +++ b/validation-test/stdlib/CommandLine.swift @@ -8,7 +8,7 @@ // RUN: %target-run %t/CommandLineStressTest foo bar baz qux quux corge grault garply waldo fred plugh xyzzy and thud // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime // This file is an empty stub to call into the command line stress test which // houses `main`. diff --git a/validation-test/stdlib/DictionaryBridging.swift b/validation-test/stdlib/DictionaryBridging.swift index 4a2d203e2ca79..eed83d32a67ec 100644 --- a/validation-test/stdlib/DictionaryBridging.swift +++ b/validation-test/stdlib/DictionaryBridging.swift @@ -8,7 +8,7 @@ // REQUIRES: stress_test // REQUIRES: objc_interop -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest import Foundation diff --git a/validation-test/stdlib/ErrorProtocol.swift b/validation-test/stdlib/ErrorProtocol.swift index 5e8a8b7862d38..6b2cf70ef7838 100644 --- a/validation-test/stdlib/ErrorProtocol.swift +++ b/validation-test/stdlib/ErrorProtocol.swift @@ -2,7 +2,7 @@ // REQUIRES: executable_test // REQUIRES: stress_test // REQUIRES: objc_interop -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import SwiftPrivate import StdlibUnittest