diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bb2e0a4cb5b5..4476bbe894498 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -893,7 +893,13 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") endif() find_package(Python2 COMPONENTS Interpreter REQUIRED) -find_package(Python3 COMPONENTS Interpreter REQUIRED) +find_package(Python3 COMPONENTS Interpreter) +if(NOT Python3_Interpreter_FOUND) + message(WARNING "Python3 not found, using python2 as a fallback") + add_executable(Python3::Interpreter IMPORTED) + set_target_properties(Python3::Interpreter PROPERTIES + IMPORTED_LOCATION ${Python2_EXECUTABLE}) +endif() # # Find optional dependencies. diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index b62a7b2937bf1..10ed368512fe3 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -96,8 +96,7 @@ set(SWIFT_BENCH_MODULES single-source/Hanoi single-source/Hash single-source/Histogram - single-source/InsertCharacter - single-source/IntegerParsing + single-source/HTTP2StateMachine single-source/Integrate single-source/IterateData single-source/Join diff --git a/benchmark/Package.swift b/benchmark/Package.swift index cb6c0ecdf4f14..4e31fdd2ef3fb 100644 --- a/benchmark/Package.swift +++ b/benchmark/Package.swift @@ -22,19 +22,19 @@ func getSingleSourceLibraries(subDirectory: String) -> [String] { let fileURLs = try! f.contentsOfDirectory(at: dirURL, includingPropertiesForKeys: nil) return fileURLs.compactMap { (path: URL) -> String? in - let c = path.lastPathComponent.split(separator: ".") - // Too many components. Must be a gyb file. - if c.count > 2 { - return nil - } - if c[1] != "swift" { + guard let lastDot = path.lastPathComponent.lastIndex(of: ".") else { return nil } + let ext = String(path.lastPathComponent.suffix(from: lastDot)) + guard ext == ".swift" else { return nil } + + let name = String(path.lastPathComponent.prefix(upTo: lastDot)) - let name = String(c[0]) + // Test names must have a single component. + if name.contains(".") { return nil } - // We do not support this test. if unsupportedTests.contains(name) { + // We do not support this test. return nil } diff --git a/benchmark/single-source/HTTP2StateMachine.swift b/benchmark/single-source/HTTP2StateMachine.swift new file mode 100644 index 0000000000000..6106957b2f8ce --- /dev/null +++ b/benchmark/single-source/HTTP2StateMachine.swift @@ -0,0 +1,390 @@ +//===--- HTTP2StateMachine.swift ------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +import TestsUtils + +// +// A trimmed-down version of SwiftNIO's HTTP/2 stream state machine. This version removes all code +// comments and removes any custom data types that are used by SwiftNIO. Its purpose is to benchmark +// Swift's performance switching over enums with substantial amounts of associated data. +// + +public let HTTP2StateMachine = [ + BenchmarkInfo( + name: "HTTP2StateMachine", + runFunction: run_HTTP2StateMachine, + tags: [.miniapplication]) +] + +typealias HTTP2FlowControlWindow = Int + + +struct HTTP2StreamStateMachine { + enum State { + case idle(localRole: StreamRole, localWindow: HTTP2FlowControlWindow, remoteWindow: HTTP2FlowControlWindow) + case reservedRemote(remoteWindow: HTTP2FlowControlWindow) + case reservedLocal(localWindow: HTTP2FlowControlWindow) + case halfOpenLocalPeerIdle(localWindow: HTTP2FlowControlWindow, remoteWindow: HTTP2FlowControlWindow) + case halfOpenRemoteLocalIdle(localWindow: HTTP2FlowControlWindow, remoteWindow: HTTP2FlowControlWindow) + case fullyOpen(localRole: StreamRole, localWindow: HTTP2FlowControlWindow, remoteWindow: HTTP2FlowControlWindow) + case halfClosedLocalPeerIdle(remoteWindow: HTTP2FlowControlWindow) + case halfClosedLocalPeerActive(localRole: StreamRole, initiatedBy: StreamRole, remoteWindow: HTTP2FlowControlWindow) + case halfClosedRemoteLocalIdle(localWindow: HTTP2FlowControlWindow) + case halfClosedRemoteLocalActive(localRole: StreamRole, initiatedBy: StreamRole, localWindow: HTTP2FlowControlWindow) + case closed + } + + enum StreamRole { + case server + case client + } + + private var state: State + + init(localRole: StreamRole, localWindow: HTTP2FlowControlWindow, remoteWindow: HTTP2FlowControlWindow) { + self.state = .idle(localRole: localRole, localWindow: localWindow, remoteWindow: remoteWindow) + } + + init(receivedPushPromiseWithRemoteInitialWindowSize remoteWindow: HTTP2FlowControlWindow) { + self.state = .reservedRemote(remoteWindow: remoteWindow) + } + + init(sentPushPromiseWithLocalInitialWindowSize localWindow: HTTP2FlowControlWindow) { + self.state = .reservedLocal(localWindow: localWindow) + } + + @inline(never) + mutating func sendHeaders(isEndStreamSet endStream: Bool) -> Bool { + switch self.state { + case .idle(.client, localWindow: let localWindow, remoteWindow: let remoteWindow): + self.state = endStream ? .halfClosedLocalPeerIdle(remoteWindow: remoteWindow) : .halfOpenLocalPeerIdle(localWindow: localWindow, remoteWindow: remoteWindow) + return true + + case .halfOpenRemoteLocalIdle(localWindow: let localWindow, remoteWindow: let remoteWindow): + self.state = endStream ? .halfClosedLocalPeerActive(localRole: .server, initiatedBy: .client, remoteWindow: remoteWindow) : .fullyOpen(localRole: .server, localWindow: localWindow, remoteWindow: remoteWindow) + return true + + case .halfOpenLocalPeerIdle(localWindow: _, remoteWindow: let remoteWindow): + self.state = .halfClosedLocalPeerIdle(remoteWindow: remoteWindow) + return true + + case .reservedLocal(let localWindow): + self.state = endStream ? .closed : .halfClosedRemoteLocalActive(localRole: .server, initiatedBy: .server, localWindow: localWindow) + return true + + case .fullyOpen(let localRole, localWindow: _, remoteWindow: let remoteWindow): + self.state = .halfClosedLocalPeerActive(localRole: localRole, initiatedBy: .client, remoteWindow: remoteWindow) + return true + + case .halfClosedRemoteLocalIdle(let localWindow): + self.state = endStream ? .closed : . halfClosedRemoteLocalActive(localRole: .server, initiatedBy: .client, localWindow: localWindow) + return true + + case .halfClosedRemoteLocalActive: + self.state = .closed + return true + + + case .idle(.server, _, _), .closed: + return false + + case .reservedRemote, .halfClosedLocalPeerIdle, .halfClosedLocalPeerActive: + return false + } + } + + @inline(never) + mutating func receiveHeaders(isEndStreamSet endStream: Bool) -> Bool { + switch self.state { + case .idle(.server, localWindow: let localWindow, remoteWindow: let remoteWindow): + self.state = endStream ? .halfClosedRemoteLocalIdle(localWindow: localWindow) : .halfOpenRemoteLocalIdle(localWindow: localWindow, remoteWindow: remoteWindow) + return true + + case .halfOpenLocalPeerIdle(localWindow: let localWindow, remoteWindow: let remoteWindow): + self.state = endStream ? .halfClosedRemoteLocalActive(localRole: .client,initiatedBy: .client, localWindow: localWindow) : .fullyOpen(localRole: .client, localWindow: localWindow, remoteWindow: remoteWindow) + return true + + case .halfOpenRemoteLocalIdle(localWindow: let localWindow, remoteWindow: _): + self.state = .halfClosedRemoteLocalIdle(localWindow: localWindow) + return true + + case .reservedRemote(let remoteWindow): + self.state = endStream ? .closed : .halfClosedLocalPeerActive(localRole: .client, initiatedBy: .server, remoteWindow: remoteWindow) + return true + + case .fullyOpen(let localRole, localWindow: let localWindow, remoteWindow: _): + self.state = .halfClosedRemoteLocalActive(localRole: localRole, initiatedBy: .client, localWindow: localWindow) + return true + + case .halfClosedLocalPeerIdle(let remoteWindow): + self.state = endStream ? .closed : . halfClosedLocalPeerActive(localRole: .client, initiatedBy: .client, remoteWindow: remoteWindow) + return true + + case .halfClosedLocalPeerActive: + self.state = .closed + return true + + case .idle(.client, _, _), .closed: + return false + + case .reservedLocal, .halfClosedRemoteLocalIdle, .halfClosedRemoteLocalActive: + return false + } + } + + @inline(never) + mutating func sendData(flowControlledBytes: Int, isEndStreamSet endStream: Bool) -> Bool { + switch self.state { + case .halfOpenLocalPeerIdle(localWindow: var localWindow, remoteWindow: let remoteWindow): + localWindow -= flowControlledBytes + self.state = endStream ? .halfClosedLocalPeerIdle(remoteWindow: remoteWindow) : .halfOpenLocalPeerIdle(localWindow: localWindow, remoteWindow: remoteWindow) + return true + + case .fullyOpen(let localRole, localWindow: var localWindow, remoteWindow: let remoteWindow): + localWindow -= flowControlledBytes + self.state = endStream ? .halfClosedLocalPeerActive(localRole: localRole, initiatedBy: .client, remoteWindow: remoteWindow) : .fullyOpen(localRole: localRole, localWindow: localWindow, remoteWindow: remoteWindow) + return true + + case .halfClosedRemoteLocalActive(let localRole, let initiatedBy, var localWindow): + localWindow -= flowControlledBytes + self.state = endStream ? .closed : .halfClosedRemoteLocalActive(localRole: localRole, initiatedBy: initiatedBy, localWindow: localWindow) + return true + + case .idle, .halfOpenRemoteLocalIdle, .reservedLocal, .reservedRemote, .halfClosedLocalPeerIdle, + .halfClosedLocalPeerActive, .halfClosedRemoteLocalIdle, .closed: + return false + } + } + + @inline(never) + mutating func receiveData(flowControlledBytes: Int, isEndStreamSet endStream: Bool) -> Bool { + switch self.state { + case .halfOpenRemoteLocalIdle(localWindow: let localWindow, remoteWindow: var remoteWindow): + remoteWindow -= flowControlledBytes + self.state = endStream ? .halfClosedRemoteLocalIdle(localWindow: localWindow) : .halfOpenRemoteLocalIdle(localWindow: localWindow, remoteWindow: remoteWindow) + return true + + case .fullyOpen(let localRole, localWindow: let localWindow, remoteWindow: var remoteWindow): + remoteWindow -= flowControlledBytes + self.state = endStream ? .halfClosedRemoteLocalActive(localRole: localRole, initiatedBy: .client, localWindow: localWindow) : .fullyOpen(localRole: localRole, localWindow: localWindow, remoteWindow: remoteWindow) + return true + + case .halfClosedLocalPeerActive(let localRole, let initiatedBy, var remoteWindow): + remoteWindow -= flowControlledBytes + self.state = endStream ? .closed : .halfClosedLocalPeerActive(localRole: localRole, initiatedBy: initiatedBy, remoteWindow: remoteWindow) + return true + + case .idle, .halfOpenLocalPeerIdle, .reservedLocal, .reservedRemote, .halfClosedLocalPeerIdle, + .halfClosedRemoteLocalActive, .halfClosedRemoteLocalIdle, .closed: + return false + } + } + + @inline(never) + mutating func sendPushPromise() -> Bool { + switch self.state { + case .fullyOpen(localRole: .server, localWindow: _, remoteWindow: _), + .halfClosedRemoteLocalActive(localRole: .server, initiatedBy: .client, localWindow: _): + return true + + case .idle, .reservedLocal, .reservedRemote, .halfClosedLocalPeerIdle, .halfClosedLocalPeerActive, + .halfClosedRemoteLocalIdle, .halfOpenLocalPeerIdle, .halfOpenRemoteLocalIdle, .closed, + .fullyOpen(localRole: .client, localWindow: _, remoteWindow: _), + .halfClosedRemoteLocalActive(localRole: .client, initiatedBy: _, localWindow: _), + .halfClosedRemoteLocalActive(localRole: .server, initiatedBy: .server, localWindow: _): + return false + } + } + + @inline(never) + mutating func receivePushPromise() -> Bool { + switch self.state { + case .fullyOpen(localRole: .client, localWindow: _, remoteWindow: _), + .halfClosedLocalPeerActive(localRole: .client, initiatedBy: .client, remoteWindow: _): + return true + + case .idle, .reservedLocal, .reservedRemote, .halfClosedLocalPeerIdle, .halfClosedRemoteLocalIdle, + .halfClosedRemoteLocalActive, .halfOpenLocalPeerIdle, .halfOpenRemoteLocalIdle, .closed, + .fullyOpen(localRole: .server, localWindow: _, remoteWindow: _), + .halfClosedLocalPeerActive(localRole: .server, initiatedBy: _, remoteWindow: _), + .halfClosedLocalPeerActive(localRole: .client, initiatedBy: .server, remoteWindow: _): + return false + } + } + + @inline(never) + mutating func sendWindowUpdate(windowIncrement: Int) -> Bool { + switch self.state { + case .reservedRemote(remoteWindow: var remoteWindow): + remoteWindow += windowIncrement + self.state = .reservedRemote(remoteWindow: remoteWindow) + + case .halfOpenLocalPeerIdle(localWindow: let localWindow, remoteWindow: var remoteWindow): + remoteWindow += windowIncrement + self.state = .halfOpenLocalPeerIdle(localWindow: localWindow, remoteWindow: remoteWindow) + + case .halfOpenRemoteLocalIdle(localWindow: let localWindow, remoteWindow: var remoteWindow): + remoteWindow += windowIncrement + self.state = .halfOpenRemoteLocalIdle(localWindow: localWindow, remoteWindow: remoteWindow) + + case .fullyOpen(localRole: let localRole, localWindow: let localWindow, remoteWindow: var remoteWindow): + remoteWindow += windowIncrement + self.state = .fullyOpen(localRole: localRole, localWindow: localWindow, remoteWindow: remoteWindow) + + case .halfClosedLocalPeerIdle(remoteWindow: var remoteWindow): + remoteWindow += windowIncrement + self.state = .halfClosedLocalPeerIdle(remoteWindow: remoteWindow) + + case .halfClosedLocalPeerActive(localRole: let localRole, initiatedBy: let initiatedBy, remoteWindow: var remoteWindow): + remoteWindow += windowIncrement + self.state = .halfClosedLocalPeerActive(localRole: localRole, initiatedBy: initiatedBy, remoteWindow: remoteWindow) + + case .idle, .reservedLocal, .halfClosedRemoteLocalIdle, .halfClosedRemoteLocalActive, .closed: + return false + } + + return true + } + + @inline(never) + mutating func receiveWindowUpdate(windowIncrement: Int) -> Bool { + switch self.state { + case .reservedLocal(localWindow: var localWindow): + localWindow += windowIncrement + self.state = .reservedLocal(localWindow: localWindow) + + case .halfOpenLocalPeerIdle(localWindow: var localWindow, remoteWindow: let remoteWindow): + localWindow += windowIncrement + self.state = .halfOpenLocalPeerIdle(localWindow: localWindow, remoteWindow: remoteWindow) + + case .halfOpenRemoteLocalIdle(localWindow: var localWindow, remoteWindow: let remoteWindow): + localWindow += windowIncrement + self.state = .halfOpenRemoteLocalIdle(localWindow: localWindow, remoteWindow: remoteWindow) + + case .fullyOpen(localRole: let localRole, localWindow: var localWindow, remoteWindow: let remoteWindow): + localWindow += windowIncrement + self.state = .fullyOpen(localRole: localRole, localWindow: localWindow, remoteWindow: remoteWindow) + + case .halfClosedRemoteLocalIdle(localWindow: var localWindow): + localWindow += windowIncrement + self.state = .halfClosedRemoteLocalIdle(localWindow: localWindow) + + case .halfClosedRemoteLocalActive(localRole: let localRole, initiatedBy: let initiatedBy, localWindow: var localWindow): + localWindow += windowIncrement + self.state = .halfClosedRemoteLocalActive(localRole: localRole, initiatedBy: initiatedBy, localWindow: localWindow) + + case .halfClosedLocalPeerIdle, .halfClosedLocalPeerActive: + break + + case .idle, .reservedRemote, .closed: + return false + } + + return true + } +} + +@inline(never) +func testSimpleRequestResponse() -> Bool { + var successful = true + + var server = HTTP2StreamStateMachine(localRole: .server, localWindow: 1<<16, remoteWindow: 1<<16) + var client = HTTP2StreamStateMachine(localRole: .client, localWindow: 1<<16, remoteWindow: 1<<16) + + successful = successful && client.sendHeaders(isEndStreamSet: false) + successful = successful && server.receiveHeaders(isEndStreamSet: false) + + successful = successful && client.sendData(flowControlledBytes: 128, isEndStreamSet: false) + successful = successful && client.sendData(flowControlledBytes: 128, isEndStreamSet: false) + successful = successful && server.receiveData(flowControlledBytes: 128, isEndStreamSet: false) + successful = successful && server.receiveData(flowControlledBytes: 128, isEndStreamSet: false) + + successful = successful && server.sendWindowUpdate(windowIncrement: 256) + successful = successful && client.receiveWindowUpdate(windowIncrement: 256) + + successful = successful && client.sendData(flowControlledBytes: 128, isEndStreamSet: true) + successful = successful && server.receiveData(flowControlledBytes: 128, isEndStreamSet: true) + + successful = successful && server.sendHeaders(isEndStreamSet: false) + successful = successful && client.receiveHeaders(isEndStreamSet: false) + + successful = successful && server.sendData(flowControlledBytes: 1024, isEndStreamSet: false) + successful = successful && client.receiveData(flowControlledBytes: 1024, isEndStreamSet: false) + successful = successful && client.sendWindowUpdate(windowIncrement: 1024) + successful = successful && server.receiveWindowUpdate(windowIncrement: 1024) + + successful = successful && server.sendData(flowControlledBytes: 1024, isEndStreamSet: true) + successful = successful && client.receiveData(flowControlledBytes: 1024, isEndStreamSet: true) + + return successful +} + +@inline(never) +func testPushedRequests() -> Bool { + var successful = true + + var server = HTTP2StreamStateMachine(sentPushPromiseWithLocalInitialWindowSize: 1<<16) + var client = HTTP2StreamStateMachine(receivedPushPromiseWithRemoteInitialWindowSize: 1<<16) + + successful = successful && client.sendWindowUpdate(windowIncrement: 1024) + + successful = successful && server.sendHeaders(isEndStreamSet: false) + successful = successful && client.receiveHeaders(isEndStreamSet: false) + + successful = successful && server.sendData(flowControlledBytes: 1024, isEndStreamSet: false) + successful = successful && server.sendData(flowControlledBytes: 1024, isEndStreamSet: false) + successful = successful && client.receiveData(flowControlledBytes: 1024, isEndStreamSet: false) + successful = successful && client.receiveData(flowControlledBytes: 1024, isEndStreamSet: false) + + successful = successful && client.sendWindowUpdate(windowIncrement: 1024) + successful = successful && server.receiveWindowUpdate(windowIncrement: 1024) + + successful = successful && server.sendData(flowControlledBytes: 1024, isEndStreamSet: false) + successful = successful && client.receiveData(flowControlledBytes: 1024, isEndStreamSet: false) + + successful = successful && server.sendHeaders(isEndStreamSet: true) + successful = successful && client.receiveHeaders(isEndStreamSet: true) + + return successful +} + +@inline(never) +func testPushingRequests() -> Bool { + var successful = true + + var server = HTTP2StreamStateMachine(localRole: .server, localWindow: 1<<16, remoteWindow: 1<<16) + var client = HTTP2StreamStateMachine(localRole: .client, localWindow: 1<<16, remoteWindow: 1<<16) + + successful = successful && client.sendHeaders(isEndStreamSet: true) + successful = successful && server.receiveHeaders(isEndStreamSet: true) + + successful = successful && server.sendHeaders(isEndStreamSet: false) + successful = successful && client.receiveHeaders(isEndStreamSet: false) + + successful = successful && server.sendPushPromise() + successful = successful && client.receivePushPromise() + + successful = successful && server.sendData(flowControlledBytes: 1024, isEndStreamSet: true) + successful = successful && client.receiveData(flowControlledBytes: 1024, isEndStreamSet: true) + + return successful +} + +@inline(never) +func run_HTTP2StateMachine(_ N: Int) { + for _ in 0 ..< 1000000 * N { + CheckResults(testSimpleRequestResponse()) + CheckResults(testPushedRequests()) + CheckResults(testPushingRequests()) + } +} + diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift index f31ccdec9d04c..7e49bfbbfec7b 100644 --- a/benchmark/utils/main.swift +++ b/benchmark/utils/main.swift @@ -84,8 +84,7 @@ import FloatingPointPrinting import Hanoi import Hash import Histogram -import InsertCharacter -import IntegerParsing +import HTTP2StateMachine import Integrate import IterateData import Join @@ -268,8 +267,7 @@ registerBenchmark(FloatingPointPrinting) registerBenchmark(Hanoi) registerBenchmark(HashTest) registerBenchmark(Histogram) -registerBenchmark(InsertCharacter) -registerBenchmark(IntegerParsing) +registerBenchmark(HTTP2StateMachine) registerBenchmark(IntegrateTest) registerBenchmark(IterateData) registerBenchmark(Join) diff --git a/docs/ContinuousIntegration.md b/docs/ContinuousIntegration.md index 263698516b23f..ba96e2e3906e2 100644 --- a/docs/ContinuousIntegration.md +++ b/docs/ContinuousIntegration.md @@ -12,6 +12,7 @@ - [Source Compatibility Testing](#source-compatibility-testing) - [Sourcekit Stress Testing](#sourcekit-stress-testing) - [Specific Preset Testing](#specific-preset-testing) + - [Running Non-Executable Device Tests](#running-non-executable-device-tests) - [Build Swift Toolchain](#build-swift-toolchain) - [Testing Compiler Performance](#testing-compiler-performance) - [Swift Community Hosted CI Pull Request Testing](#swift-community-hosted-ci-pull-request-testing) @@ -161,8 +162,18 @@ For example: ``` preset=buildbot_incremental,tools=RA,stdlib=RD,smoketest=macosx,single-thread @swift-ci Please test with preset macOS +``` + +### Running Non-Executable Device Tests + +Using the specific preset testing, one can run non-executable device tests by +telling swift-ci: ``` +preset=buildbot,tools=RA,stdlib=RD,test=non_executable +@swift-ci Please test with preset macOS +``` + ### Build Swift Toolchain Platform | Comment | Check Status diff --git a/docs/DebuggingTheCompiler.rst b/docs/DebuggingTheCompiler.rst index 5e36945976fe7..503b1b5c6bcea 100644 --- a/docs/DebuggingTheCompiler.rst +++ b/docs/DebuggingTheCompiler.rst @@ -80,8 +80,8 @@ where to stop in the debugger. Rather than trying to guess/check if one has an asserts swift compiler, one can use the following options to cause the diagnostic engine to assert on the first error/warning: -* -Xllvm -swift-diagnostics-assert-on-error=1 -* -Xllvm -swift-diagnostics-assert-on-warning=1 +* ``-Xllvm -swift-diagnostics-assert-on-error=1`` +* ``-Xllvm -swift-diagnostics-assert-on-warning=1`` These allow one to dump a stack trace of where the diagnostic is being emitted (if run without a debugger) or drop into the debugger if a debugger is attached. @@ -548,10 +548,17 @@ it's quite easy to do this manually: a. Add the compiler option ``-Xllvm -sil-opt-pass-count=``, where ```` is the number of optimizations to run. - b. Bisect: find n where the executable crashes, but does not crash with n-1. - Note that n can be quite large, e.g. > 100000 (just try - n = 10, 100, 1000, 10000, etc. to find an upper bound). - c. Add another option ``-Xllvm -sil-print-pass-name``. The output can be + + b. Bisect: find n where the executable crashes, but does not crash + with n-1. First just try n = 10, 100, 1000, 10000, etc. to find + an upper bound). Then can either bisect the invocation by hand or + place the invocation into a script and use + ``./llvm-project/llvm/utils/bisect`` to automatically bisect + based on the scripts error code. Example invocation:: + + bisect --start=0 --end=10000 ./invoke_swift_passing_N.sh "%(count)s" + + c. Once one finds ``n``, Add another option ``-Xllvm -sil-print-pass-name``. The output can be large, so it's best to redirect stderr to a file (``2> output``). In the output search for the last pass before ``stage Address Lowering``. It should be the ``Run #``. This line tells you the name of the bad @@ -687,3 +694,65 @@ Multiple Logs at a Time Note, you can also turn on more than one log at a time as well, e.x.:: (lldb) log enable -f /tmp/lldb-types-log.txt lldb types expression + +Using git-bisect in the presence of branch forwarding/feature branches +====================================================================== + +``git-bisect`` is a useful tool for finding where a regression was +introduced. Sadly ``git-bisect`` does not handle long lived branches +and will in fact choose commits from upstream branches that may be +missing important content from the downstream branch. As an example, +consider a situation where one has the following straw man commit flow +graph:: + + github/master -> github/tensorflow + +In this case if one attempts to use ``git-bisect`` on +github/tensorflow, ``git-bisect`` will sometimes choose commits from +github/master resulting in one being unable to compile/test specific +tensorflow code that has not been upstreamed yet. Even worse, what if +we are trying to bisect in between two that were branched from +github/tensorflow and have had subsequent commits cherry-picked on +top. Without any loss of generality, lets call those two tags +``tag-tensorflow-bad`` and ``tag-tensorflow-good``. Since both of +these tags have had commits cherry-picked on top, they are technically +not even on the github/tensorflow branch, but rather in a certain +sense are a tag of a feature branch from master/tensorflow. So, +``git-bisect`` doesn't even have a clear history to bisect on in +multiple ways. + +With those constraints in mind, we can bisect! We just need to be +careful how we do it. Lets assume that we have a test script called +``test.sh`` that indicates error by the error code. With that in hand, +we need to compute the least common ancestor of the good/bad +commits. This is traditionally called the "merge base" of the +commits. We can compute this as so:: + + TAG_MERGE_BASE=$(git merge-base tags/tag-tensorflow-bad tags/tag-tensorflow-good) + +Given that both tags were taken from the feature branch, the reader +can prove to themselves that this commit is guaranteed to be on +``github/tensorflow`` and not ``github/master`` since all commits from +``github/master`` are forwarded using git merges. + +Then lets assume that we checked out ``$TAG_MERGE_BASE`` and then ran +``test.sh`` and did not hit any error. Ok, we can not bisect. Sadly, +as mentioned above if we run git-bisect in between ``$TAG_MERGE_BASE`` +and ``tags/tag-tensorflow-bad``, ``git-bisect`` will sometimes choose +commits from ``github/master`` which would cause ``test.sh`` to fail +if we are testing tensorflow specific code! To work around this +problem, we need to start our bisect and then tell ``git-bisect`` to +ignore those commits by using the skip sub command:: + + git bisect start tags/tag-tensorflow-bad $TAG_MERGE_BASE + for rev in $(git rev-list $TAG_MERGE_BASE..tags/tag-tensorflow-bad --merges --first-parent); do + git rev-list $rev^2 --not $rev^ + done | xargs git bisect skip + +Once this has been done, one uses ``git-bisect`` normally. One thing +to be aware of is that ``git-bisect`` will return a good/bad commits +on the feature branch and if one of those commits is a merge from the +upstream branch, one will need to analyze the range of commits from +upstream for the bad commit afterwards. The commit range in the merge +should be relatively small though compared with the large git history +one just bisected. diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index e3c0850899709..456b386ea9e62 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5243,7 +5243,7 @@ class VarDecl : public AbstractStorageDecl { /// /// \code /// @Lazy var i = 17 - /// \end + /// \endcode /// /// Or when there is no initializer but each composed property wrapper has /// a suitable `init(wrappedValue:)`. diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 6428c23eb17eb..c1bc125b16e84 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -902,8 +902,8 @@ ERROR(nonstatic_operator_in_nominal,none, "operator %0 declared in type %1 must be 'static'", (Identifier, DeclName)) ERROR(nonstatic_operator_in_extension,none, - "operator %0 declared in extension of %1 must be 'static'", - (Identifier, TypeRepr*)) + "operator %0 declared in extension%select{| of %2}1 must be 'static'", + (Identifier, bool, TypeRepr*)) ERROR(nonfinal_operator_in_class,none, "operator %0 declared in non-final class %1 must be 'final'", (Identifier, Type)) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index befac567f83e5..90a11c96eff43 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -4041,7 +4041,61 @@ class OpaqueValueExpr : public Expr { SourceRange getSourceRange() const { return Range; } static bool classof(const Expr *E) { - return E->getKind() == ExprKind::OpaqueValue; + return E->getKind() == ExprKind::OpaqueValue; + } +}; + +/// A placeholder to substitute with a \c wrappedValue initialization expression +/// for a property with an attached property wrapper. +/// +/// Wrapped value placeholder expressions are injected around the +/// \c wrappedValue argument in a synthesized \c init(wrappedValue:) +/// call. This injection happens for properties with attached property wrappers +/// that can be initialized out-of-line with a wrapped value expression, rather +/// than calling \c init(wrappedValue:) explicitly. +/// +/// Wrapped value placeholders store the original initialization expression +/// if one exists, along with an opaque value placeholder that can be bound +/// to a different wrapped value expression. +class PropertyWrapperValuePlaceholderExpr : public Expr { + SourceRange Range; + OpaqueValueExpr *Placeholder; + Expr *WrappedValue; + + PropertyWrapperValuePlaceholderExpr(SourceRange Range, Type Ty, + OpaqueValueExpr *placeholder, + Expr *wrappedValue) + : Expr(ExprKind::PropertyWrapperValuePlaceholder, /*Implicit=*/true, Ty), + Range(Range), Placeholder(placeholder), WrappedValue(wrappedValue) {} + +public: + static PropertyWrapperValuePlaceholderExpr * + create(ASTContext &ctx, SourceRange range, Type ty, Expr *wrappedValue); + + /// The original wrappedValue initialization expression provided via + /// \c = on a proprety with attached property wrappers. + Expr *getOriginalWrappedValue() const { + return WrappedValue; + } + + void setOriginalWrappedValue(Expr *value) { + WrappedValue = value; + } + + /// An opaque value placeholder that will be used to substitute in a + /// different wrapped value expression for out-of-line initialization. + OpaqueValueExpr *getOpaqueValuePlaceholder() const { + return Placeholder; + } + + void setOpaqueValuePlaceholder(OpaqueValueExpr *placeholder) { + Placeholder = placeholder; + } + + SourceRange getSourceRange() const { return Range; } + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::PropertyWrapperValuePlaceholder; } }; diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index fb28680bbd9a1..afd5e4f17235b 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -126,6 +126,7 @@ EXPR(VarargExpansion, Expr) EXPR(DynamicType, Expr) EXPR(RebindSelfInConstructor, Expr) EXPR(OpaqueValue, Expr) +EXPR(PropertyWrapperValuePlaceholder, Expr) EXPR(DefaultArgument, Expr) EXPR(BindOptional, Expr) EXPR(OptionalEvaluation, Expr) diff --git a/include/swift/AST/PropertyWrappers.h b/include/swift/AST/PropertyWrappers.h index 1fa0ea8873419..9a16a4fc708e5 100644 --- a/include/swift/AST/PropertyWrappers.h +++ b/include/swift/AST/PropertyWrappers.h @@ -141,7 +141,7 @@ struct PropertyWrapperBackingPropertyInfo { /// /// \code /// @Lazy var i = 17 - /// \end + /// \endcode /// /// This is the specified initial value (\c 17), which is suitable for /// embedding in the expression \c initializeFromOriginal. @@ -190,12 +190,13 @@ void simple_display( llvm::raw_ostream &out, const PropertyWrapperBackingPropertyInfo &backingInfo); -/// Given the initializer for the given property with an attached property -/// wrapper, dig out the original initialization expression. +/// Given the initializer for a property with an attached property wrapper, +/// dig out the wrapped value placeholder for the original initialization +/// expression. /// -/// Cannot just dig out the getOriginalInit() value because this function checks -/// types, etc. Erroneous code won't return a result from here. -Expr *findOriginalPropertyWrapperInitialValue(VarDecl *var, Expr *init); +/// \note The wrapped value placeholder is injected for properties that can +/// be initialized out-of-line using an expression of the wrapped property type. +PropertyWrapperValuePlaceholderExpr *findWrappedValuePlaceholder(Expr *init); } // end namespace swift diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 4a6cadbb84b86..dbd73c8776156 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2511,6 +2511,18 @@ class PrintExpr : public ExprVisitor { PrintWithColorRAII(OS, ParenthesisColor) << ')'; } + void visitPropertyWrapperValuePlaceholderExpr( + PropertyWrapperValuePlaceholderExpr *E) { + printCommon(E, "property_wrapper_value_placeholder_expr"); + OS << '\n'; + printRec(E->getOpaqueValuePlaceholder()); + if (auto *value = E->getOriginalWrappedValue()) { + OS << '\n'; + printRec(value); + } + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitDefaultArgumentExpr(DefaultArgumentExpr *E) { printCommon(E, "default_argument_expr"); OS << " default_args_owner="; diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 5b7d0dd2bd680..2e6a946b498e9 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -508,6 +508,23 @@ class Traversal : public ASTVisitorgetOpaqueValuePlaceholder())) + E->setOpaqueValuePlaceholder(dyn_cast(placeholder)); + else + return nullptr; + + if (E->getOriginalWrappedValue()) { + if (auto *newValue = doIt(E->getOriginalWrappedValue())) + E->setOriginalWrappedValue(newValue); + else + return nullptr; + } + + return E; + } + Expr *visitDefaultArgumentExpr(DefaultArgumentExpr *E) { return E; } Expr *visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E) { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index a96df5da0af6b..0a319f7b0146f 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -6356,105 +6356,27 @@ void ParamDecl::setDefaultArgumentCaptureInfo(CaptureInfo captures) { DefaultValueAndFlags.getPointer()->Captures = captures; } -/// Return nullptr if there is no property wrapper -Expr *swift::findOriginalPropertyWrapperInitialValue(VarDecl *var, - Expr *init) { - auto *PBD = var->getParentPatternBinding(); - if (!PBD) - return nullptr; - - // If there is no '=' on the pattern, there was no initial value. - if (PBD->getEqualLoc(0).isInvalid() && !PBD->isDefaultInitializable()) - return nullptr; - - ASTContext &ctx = var->getASTContext(); - auto dc = var->getInnermostDeclContext(); - const auto wrapperAttrs = var->getAttachedPropertyWrappers(); - if (wrapperAttrs.empty()) - return nullptr; - auto innermostAttr = wrapperAttrs.back(); - auto innermostNominal = evaluateOrDefault( - ctx.evaluator, CustomAttrNominalRequest{innermostAttr, dc}, nullptr); - if (!innermostNominal) - return nullptr; - - // Walker +PropertyWrapperValuePlaceholderExpr * +swift::findWrappedValuePlaceholder(Expr *init) { class Walker : public ASTWalker { public: - NominalTypeDecl *innermostNominal; - Expr *initArg = nullptr; - - Walker(NominalTypeDecl *innermostNominal) - : innermostNominal(innermostNominal) { } + PropertyWrapperValuePlaceholderExpr *placeholder = nullptr; virtual std::pair walkToExprPre(Expr *E) override { - if (initArg) + if (placeholder) return { false, E }; - if (auto call = dyn_cast(E)) { - ASTContext &ctx = innermostNominal->getASTContext(); - - // We're looking for an implicit call. - if (!call->isImplicit()) - return { true, E }; - - // ... which may call the constructor of another property - // wrapper if there are multiple wrappers attached to the - // property. - if (auto tuple = dyn_cast(call->getArg())) { - if (tuple->getNumElements() > 0) { - for (unsigned i : range(tuple->getNumElements())) { - if (tuple->getElementName(i) == ctx.Id_wrappedValue || - tuple->getElementName(i) == ctx.Id_initialValue) { - auto elem = tuple->getElement(i)->getSemanticsProvidingExpr(); - - // Look through autoclosures. - if (auto autoclosure = dyn_cast(elem)) - elem = autoclosure->getSingleExpressionBody(); - - if (elem->isImplicit() && isa(elem)) { - return { true, E }; - } - } - } - } - } - - // ... producing a value of the same nominal type as the - // innermost property wrapper. - if (!call->getType() || - call->getType()->getAnyNominal() != innermostNominal) - return { false, E }; - - // Find the implicit initialValue/wrappedValue argument. - if (auto tuple = dyn_cast(call->getArg())) { - for (unsigned i : range(tuple->getNumElements())) { - if (tuple->getElementName(i) == ctx.Id_wrappedValue || - tuple->getElementName(i) == ctx.Id_initialValue) { - initArg = tuple->getElement(i); - return { false, E }; - } - } - } + if (auto *value = dyn_cast(E)) { + placeholder = value; + return { false, value }; } return { true, E }; } - } walker(innermostNominal); + } walker; init->walk(walker); - Expr *initArg = walker.initArg; - if (initArg) { - initArg = initArg->getSemanticsProvidingExpr(); - if (auto autoclosure = dyn_cast(initArg)) { - if (!var->isInnermostPropertyWrapperInitUsesEscapingAutoClosure()) { - // Remove the autoclosure part only for non-escaping autoclosures - initArg = - autoclosure->getSingleExpressionBody()->getSemanticsProvidingExpr(); - } - } - } - return initArg; + return walker.placeholder; } /// Writes a tuple expression where each element is either `nil` or another such @@ -6553,7 +6475,7 @@ ParamDecl::getDefaultValueStringRepresentation( } auto init = - findOriginalPropertyWrapperInitialValue(original, parentInit); + findWrappedValuePlaceholder(parentInit)->getOriginalWrappedValue(); return extractInlinableText(getASTContext().SourceMgr, init, scratch); } } diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 01edba7079ee9..fc80808f00a61 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -583,11 +583,14 @@ static void formatDiagnosticArgument(StringRef Modifier, } break; } + case DiagnosticArgumentKind::TypeRepr: assert(Modifier.empty() && "Improper modifier for TypeRepr argument"); + assert(Arg.getAsTypeRepr() && "TypeRepr argument is null"); Out << FormatOpts.OpeningQuotationMark << Arg.getAsTypeRepr() << FormatOpts.ClosingQuotationMark; break; + case DiagnosticArgumentKind::PatternKind: assert(Modifier.empty() && "Improper modifier for PatternKind argument"); Out << Arg.getAsPatternKind(); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index c28001799baa0..aaadd90e62cae 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -311,6 +311,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const { PASS_THROUGH_REFERENCE(RebindSelfInConstructor, getSubExpr); NO_REFERENCE(OpaqueValue); + NO_REFERENCE(PropertyWrapperValuePlaceholder); NO_REFERENCE(DefaultArgument); PASS_THROUGH_REFERENCE(BindOptional, getSubExpr); @@ -624,6 +625,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const { case ExprKind::RebindSelfInConstructor: case ExprKind::OpaqueValue: + case ExprKind::PropertyWrapperValuePlaceholder: case ExprKind::DefaultArgument: case ExprKind::BindOptional: case ExprKind::OptionalEvaluation: @@ -1403,6 +1405,17 @@ static ValueDecl *getCalledValue(Expr *E) { return nullptr; } +PropertyWrapperValuePlaceholderExpr * +PropertyWrapperValuePlaceholderExpr::create(ASTContext &ctx, SourceRange range, + Type ty, Expr *wrappedValue) { + auto *placeholder = + new (ctx) OpaqueValueExpr(range, ty, /*isPlaceholder=*/true); + + return new (ctx) PropertyWrapperValuePlaceholderExpr(range, ty, + placeholder, + wrappedValue); +} + const ParamDecl *DefaultArgumentExpr::getParamDecl() const { return getParameterAt(DefaultArgsOwner.getDecl(), ParamIndex); } diff --git a/lib/LLVMPasses/LLVMMergeFunctions.cpp b/lib/LLVMPasses/LLVMMergeFunctions.cpp index 80b59e5df23a2..7df78383c12c9 100644 --- a/lib/LLVMPasses/LLVMMergeFunctions.cpp +++ b/lib/LLVMPasses/LLVMMergeFunctions.cpp @@ -1126,7 +1126,7 @@ bool SwiftMergeFunctions::replaceDirectCallers(Function *Old, Function *New, cast(New->getType())->getAddressSpace()); Value *Callee = ConstantExpr::getBitCast(New, FPtrType); - CallInst *NewCI = Builder.CreateCall(Callee, NewArgs); + CallInst *NewCI = Builder.CreateCall(FType, Callee, NewArgs); NewCI->setCallingConv(CI->getCallingConv()); // Don't transfer attributes from the function to the callee. Function // attributes typically aren't relevant to the calling convention or ABI. diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 738fca46259e6..dd6a0f8d842c9 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -220,6 +220,21 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, // Cleanup after this initialization. FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); + + // If this is a property wrapper backing storage var that isn't + // memberwise initialized and has an original wrapped value, apply + // the property wrapper backing initializer. + if (auto *wrappedVar = field->getOriginalWrappedProperty()) { + auto wrappedInfo = wrappedVar->getPropertyWrapperBackingPropertyInfo(); + if (wrappedInfo.originalInitialValue) { + auto arg = SGF.emitRValue(wrappedInfo.originalInitialValue); + maybeEmitPropertyWrapperInitFromValue(SGF, Loc, field, subs, + std::move(arg)) + .forwardInto(SGF, Loc, init.get()); + continue; + } + } + SGF.emitExprInto(field->getParentInitializer(), init.get()); } } @@ -235,27 +250,37 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, for (VarDecl *field : decl->getStoredProperties()) { auto fieldTy = selfTy.getFieldType(field, SGF.SGM.M, SGF.getTypeExpansionContext()); - SILValue v; + RValue value; // If it's memberwise initialized, do so now. if (field->isMemberwiseInitialized(/*preferDeclaredProperties=*/false)) { - FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); assert(elti != eltEnd && "number of args does not match number of fields"); (void)eltEnd; - v = maybeEmitPropertyWrapperInitFromValue( - SGF, Loc, field, subs, std::move(*elti)) - .forwardAsSingleStorageValue(SGF, fieldTy, Loc); + value = std::move(*elti); ++elti; } else { // Otherwise, use its initializer. assert(field->isParentInitialized()); + Expr *init = field->getParentInitializer(); + + // If this is a property wrapper backing storage var that isn't + // memberwise initialized, use the original wrapped value if it exists. + if (auto *wrappedVar = field->getOriginalWrappedProperty()) { + auto wrappedInfo = wrappedVar->getPropertyWrapperBackingPropertyInfo(); + if (wrappedInfo.originalInitialValue) { + init = wrappedInfo.originalInitialValue; + } + } - // Cleanup after this initialization. - FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); - v = SGF.emitRValue(field->getParentInitializer()) - .forwardAsSingleStorageValue(SGF, fieldTy, Loc); + value = SGF.emitRValue(init); } + // Cleanup after this initialization. + FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); + SILValue v = maybeEmitPropertyWrapperInitFromValue(SGF, Loc, field, subs, + std::move(value)) + .forwardAsSingleStorageValue(SGF, fieldTy, Loc); + eltValues.push_back(v); } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 86fc91af463d9..981ac6aa6d992 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -519,6 +519,8 @@ namespace { MakeTemporarilyEscapableExpr *E, SGFContext C); RValue visitOpaqueValueExpr(OpaqueValueExpr *E, SGFContext C); + RValue visitPropertyWrapperValuePlaceholderExpr( + PropertyWrapperValuePlaceholderExpr *E, SGFContext C); RValue visitInOutToPointerExpr(InOutToPointerExpr *E, SGFContext C); RValue visitArrayToPointerExpr(ArrayToPointerExpr *E, SGFContext C); @@ -2407,22 +2409,15 @@ RValue RValueEmitter::visitCaptureListExpr(CaptureListExpr *E, SGFContext C) { return visit(E->getClosureBody(), C); } -static OpaqueValueExpr *opaqueValueExprToSubstituteForAutoClosure( - const AbstractClosureExpr *e) { - // When we find an autoclosure that just calls an opaque closure, - // this is a case where we've created the opaque closure as a - // stand-in for the autoclosure itself. Such an opaque closure is - // created when we have a property wrapper's 'init(wrappedValue:)' - // taking an autoclosure argument. +/// Returns the wrapped value placeholder that is meant to be substituted +/// in for the given autoclosure. This autoclosure placeholder is created +/// when \c init(wrappedValue:) takes an autoclosure for the \c wrappedValue +/// parameter. +static PropertyWrapperValuePlaceholderExpr * +wrappedValueAutoclosurePlaceholder(const AbstractClosureExpr *e) { if (auto ace = dyn_cast(e)) { if (auto ce = dyn_cast(ace->getSingleExpressionBody())) { - if (auto ove = dyn_cast(ce->getFn())) { - if (!ace->isImplicit() || !ove->isImplicit() || !ove->isPlaceholder()) - return nullptr; - - if (ace->getType()->isEqual(ove->getType())) - return ove; - } + return dyn_cast(ce->getFn()); } } return nullptr; @@ -2430,8 +2425,8 @@ static OpaqueValueExpr *opaqueValueExprToSubstituteForAutoClosure( RValue RValueEmitter::visitAbstractClosureExpr(AbstractClosureExpr *e, SGFContext C) { - if (auto ove = opaqueValueExprToSubstituteForAutoClosure(e)) - return visitOpaqueValueExpr(ove, C); + if (auto *placeholder = wrappedValueAutoclosurePlaceholder(e)) + return visitPropertyWrapperValuePlaceholderExpr(placeholder, C); // Emit the closure body. SGF.SGM.emitClosure(e); @@ -5141,6 +5136,11 @@ RValue RValueEmitter::visitOpaqueValueExpr(OpaqueValueExpr *E, SGFContext C) { return RValue(SGF, E, SGF.manageOpaqueValue(value, E, C)); } +RValue RValueEmitter::visitPropertyWrapperValuePlaceholderExpr( + PropertyWrapperValuePlaceholderExpr *E, SGFContext C) { + return visitOpaqueValueExpr(E->getOpaqueValuePlaceholder(), C); +} + ProtocolDecl *SILGenFunction::getPointerProtocol() { if (SGM.PointerProtocol) return *SGM.PointerProtocol; diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 752d30169893e..9d13caa396e1f 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -298,6 +298,7 @@ namespace { ConstraintSystem &cs; DeclContext *dc; Solution &solution; + Optional target; bool SuppressDiagnostics; /// Coerce the given tuple to another tuple type. @@ -2207,8 +2208,9 @@ namespace { public: ExprRewriter(ConstraintSystem &cs, Solution &solution, + Optional target, bool suppressDiagnostics) - : cs(cs), dc(cs.DC), solution(solution), + : cs(cs), dc(cs.DC), solution(solution), target(target), SuppressDiagnostics(suppressDiagnostics) {} ConstraintSystem &getConstraintSystem() const { return cs; } @@ -3483,6 +3485,11 @@ namespace { return expr; } + Expr *visitPropertyWrapperValuePlaceholderExpr( + PropertyWrapperValuePlaceholderExpr *expr) { + return expr; + } + Expr *visitDefaultArgumentExpr(DefaultArgumentExpr *expr) { llvm_unreachable("Already type-checked"); } @@ -5551,8 +5558,24 @@ Expr *ExprRewriter::coerceCallArguments(Expr *arg, AnyFunctionType *funcType, SmallVector args; AnyFunctionType::decomposeInput(cs.getType(arg), args); + // If this application is an init(wrappedValue:) call that needs an injected + // wrapped value placeholder, the first non-defaulted argument must be + // wrapped in an OpaqueValueExpr. + bool shouldInjectWrappedValuePlaceholder = + target->shouldInjectWrappedValuePlaceholder(apply); + + auto injectWrappedValuePlaceholder = [&](Expr *arg) -> Expr * { + auto *placeholder = PropertyWrapperValuePlaceholderExpr::create(ctx, + arg->getSourceRange(), cs.getType(arg), arg); + cs.cacheType(placeholder); + cs.cacheType(placeholder->getOpaqueValuePlaceholder()); + shouldInjectWrappedValuePlaceholder = false; + return placeholder; + }; + // Quickly test if any further fix-ups for the argument types are necessary. - if (AnyFunctionType::equalParams(args, params)) + if (AnyFunctionType::equalParams(args, params) && + !shouldInjectWrappedValuePlaceholder) return arg; // Apply labels to arguments. @@ -5703,7 +5726,7 @@ Expr *ExprRewriter::coerceCallArguments(Expr *arg, AnyFunctionType *funcType, // If the types exactly match, this is easy. auto paramType = param.getOldType(); - if (argType->isEqual(paramType)) { + if (argType->isEqual(paramType) && !shouldInjectWrappedValuePlaceholder) { newArgs.push_back(arg); newParams.push_back(param); continue; @@ -5742,6 +5765,22 @@ Expr *ExprRewriter::coerceCallArguments(Expr *arg, AnyFunctionType *funcType, arg, closureType->getResult(), locator.withPathElement(ConstraintLocator::AutoclosureResult)); + if (shouldInjectWrappedValuePlaceholder) { + // If init(wrappedValue:) takes an escaping autoclosure, then we want + // the effect of autoclosure forwarding of the placeholder + // autoclosure. The only way to do this is to call the placeholder + // autoclosure when passing it to the init. + if (!closureType->isNoEscape()) { + auto *placeholder = injectWrappedValuePlaceholder( + cs.buildAutoClosureExpr(arg, closureType)); + arg = CallExpr::createImplicit(ctx, placeholder, {}, {}); + arg->setType(closureType->getResult()); + cs.cacheType(arg); + } else { + arg = injectWrappedValuePlaceholder(arg); + } + } + convertedArg = cs.buildAutoClosureExpr(arg, closureType); } else { convertedArg = coerceToType( @@ -5749,6 +5788,10 @@ Expr *ExprRewriter::coerceCallArguments(Expr *arg, AnyFunctionType *funcType, getArgLocator(argIdx, paramIdx, param.getParameterFlags())); } + // Perform the wrapped value placeholder injection + if (shouldInjectWrappedValuePlaceholder) + convertedArg = injectWrappedValuePlaceholder(convertedArg); + if (!convertedArg) return nullptr; @@ -8355,7 +8398,7 @@ Optional ConstraintSystem::applySolution( } } - ExprRewriter rewriter(*this, solution, shouldSuppressDiagnostics()); + ExprRewriter rewriter(*this, solution, target, shouldSuppressDiagnostics()); ExprWalker walker(rewriter); auto resultTarget = walker.rewriteTarget(target); if (!resultTarget) @@ -8387,7 +8430,7 @@ Expr *Solution::coerceToType(Expr *expr, Type toType, ConstraintLocator *locator, Optional typeFromPattern) { auto &cs = getConstraintSystem(); - ExprRewriter rewriter(cs, *this, /*suppressDiagnostics=*/false); + ExprRewriter rewriter(cs, *this, None, /*suppressDiagnostics=*/false); Expr *result = rewriter.coerceToType(expr, toType, locator, typeFromPattern); if (!result) return nullptr; diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 8e81d585e970f..afdefb654c000 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -82,8 +82,14 @@ Type FailureDiagnostic::getType(const TypeLoc &loc, bool wantRValue) const { template InFlightDiagnostic FailureDiagnostic::emitDiagnostic(ArgTypes &&... Args) const { - auto &cs = getConstraintSystem(); - return cs.getASTContext().Diags.diagnose(std::forward(Args)...); + return emitDiagnosticAt(getLoc(), std::forward(Args)...); +} + +template +InFlightDiagnostic +FailureDiagnostic::emitDiagnosticAt(ArgTypes &&... Args) const { + auto &DE = getASTContext().Diags; + return DE.diagnose(std::forward(Args)...); } Expr *FailureDiagnostic::findParentExpr(Expr *subExpr) const { @@ -308,7 +314,6 @@ bool RequirementFailure::isStaticOrInstanceMember(const ValueDecl *decl) { } bool RequirementFailure::diagnoseAsError() { - auto *anchor = getRawAnchor(); const auto *reqDC = getRequirementDC(); auto *genericCtx = getGenericContext(); @@ -317,13 +322,12 @@ bool RequirementFailure::diagnoseAsError() { if (auto *OTD = dyn_cast(AffectedDecl)) { auto *namingDecl = OTD->getNamingDecl(); - emitDiagnostic( - anchor->getLoc(), diag::type_does_not_conform_in_opaque_return, - namingDecl->getDescriptiveKind(), namingDecl->getFullName(), lhs, rhs, - rhs->isAnyObject()); + emitDiagnostic(diag::type_does_not_conform_in_opaque_return, + namingDecl->getDescriptiveKind(), namingDecl->getFullName(), + lhs, rhs, rhs->isAnyObject()); if (auto *repr = namingDecl->getOpaqueResultTypeRepr()) { - emitDiagnostic(repr->getLoc(), diag::opaque_return_type_declared_here) + emitDiagnosticAt(repr->getLoc(), diag::opaque_return_type_declared_here) .highlight(repr->getSourceRange()); } return true; @@ -333,13 +337,11 @@ bool RequirementFailure::diagnoseAsError() { (genericCtx->isChildContextOf(reqDC) || isStaticOrInstanceMember(AffectedDecl))) { auto *NTD = reqDC->getSelfNominalTypeDecl(); - emitDiagnostic(anchor->getLoc(), getDiagnosticInRereference(), - AffectedDecl->getDescriptiveKind(), - AffectedDecl->getFullName(), NTD->getDeclaredType(), lhs, - rhs); + emitDiagnostic( + getDiagnosticInRereference(), AffectedDecl->getDescriptiveKind(), + AffectedDecl->getFullName(), NTD->getDeclaredType(), lhs, rhs); } else { - emitDiagnostic(anchor->getLoc(), getDiagnosticOnDecl(), - AffectedDecl->getDescriptiveKind(), + emitDiagnostic(getDiagnosticOnDecl(), AffectedDecl->getDescriptiveKind(), AffectedDecl->getFullName(), lhs, rhs); } @@ -351,8 +353,8 @@ bool RequirementFailure::diagnoseAsNote() { const auto &req = getRequirement(); const auto *reqDC = getRequirementDC(); - emitDiagnostic(reqDC->getAsDecl(), getDiagnosticAsNote(), getLHS(), getRHS(), - req.getFirstType(), req.getSecondType(), ""); + emitDiagnosticAt(reqDC->getAsDecl(), getDiagnosticAsNote(), getLHS(), + getRHS(), req.getFirstType(), req.getSecondType(), ""); return true; } @@ -367,33 +369,33 @@ void RequirementFailure::emitRequirementNote(const Decl *anchor, Type lhs, if (TypeChecker::typesSatisfyConstraint(wrappedType, rhs, /*openArchetypes=*/false, kind, getDC())) - emitDiagnostic(getAnchor()->getLoc(), - diag::wrapped_type_satisfies_requirement, wrappedType); + emitDiagnostic(diag::wrapped_type_satisfies_requirement, wrappedType); } } if (isConditional()) { - emitDiagnostic(anchor, diag::requirement_implied_by_conditional_conformance, - resolveType(Conformance->getType()), - Conformance->getProtocol()->getDeclaredInterfaceType()); + emitDiagnosticAt(anchor, + diag::requirement_implied_by_conditional_conformance, + resolveType(Conformance->getType()), + Conformance->getProtocol()->getDeclaredInterfaceType()); return; } if (req.getKind() == RequirementKind::Layout || rhs->isEqual(req.getSecondType())) { - emitDiagnostic(anchor, diag::where_requirement_failure_one_subst, - req.getFirstType(), lhs); + emitDiagnosticAt(anchor, diag::where_requirement_failure_one_subst, + req.getFirstType(), lhs); return; } if (lhs->isEqual(req.getFirstType())) { - emitDiagnostic(anchor, diag::where_requirement_failure_one_subst, - req.getSecondType(), rhs); + emitDiagnosticAt(anchor, diag::where_requirement_failure_one_subst, + req.getSecondType(), rhs); return; } - emitDiagnostic(anchor, diag::where_requirement_failure_both_subst, - req.getFirstType(), lhs, req.getSecondType(), rhs); + emitDiagnosticAt(anchor, diag::where_requirement_failure_both_subst, + req.getFirstType(), lhs, req.getSecondType(), rhs); } bool MissingConformanceFailure::diagnoseAsError() { @@ -430,12 +432,12 @@ bool MissingConformanceFailure::diagnoseAsError() { return true; if (nonConformingType->isObjCExistentialType()) { - emitDiagnostic(anchor->getLoc(), diag::protocol_does_not_conform_static, - nonConformingType, protocolType); + emitDiagnostic(diag::protocol_does_not_conform_static, nonConformingType, + protocolType); return true; } - if (diagnoseTypeCannotConform(anchor, nonConformingType, protocolType)) + if (diagnoseTypeCannotConform(nonConformingType, protocolType)) return true; // If none of the special cases could be diagnosed, @@ -443,7 +445,7 @@ bool MissingConformanceFailure::diagnoseAsError() { return RequirementFailure::diagnoseAsError(); } -bool MissingConformanceFailure::diagnoseTypeCannotConform(Expr *anchor, +bool MissingConformanceFailure::diagnoseTypeCannotConform( Type nonConformingType, Type protocolType) const { if (getRequirement().getKind() == RequirementKind::Layout || !(nonConformingType->is() || @@ -453,15 +455,16 @@ bool MissingConformanceFailure::diagnoseTypeCannotConform(Expr *anchor, return false; } - emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform, + emitDiagnostic(diag::type_cannot_conform, nonConformingType->isExistentialType(), nonConformingType, protocolType); if (auto *OTD = dyn_cast(AffectedDecl)) { auto *namingDecl = OTD->getNamingDecl(); if (auto *repr = namingDecl->getOpaqueResultTypeRepr()) { - emitDiagnostic(repr->getLoc(), diag::required_by_opaque_return, - namingDecl->getDescriptiveKind(), namingDecl->getFullName()) + emitDiagnosticAt(repr->getLoc(), diag::required_by_opaque_return, + namingDecl->getDescriptiveKind(), + namingDecl->getFullName()) .highlight(repr->getSourceRange()); } return true; @@ -473,24 +476,25 @@ bool MissingConformanceFailure::diagnoseTypeCannotConform(Expr *anchor, auto noteLocation = reqDC->getAsDecl()->getLoc(); if (!noteLocation.isValid()) - noteLocation = anchor->getLoc(); + noteLocation = getLoc(); if (isConditional()) { - emitDiagnostic(noteLocation, diag::requirement_implied_by_conditional_conformance, - resolveType(Conformance->getType()), - Conformance->getProtocol()->getDeclaredInterfaceType()); + emitDiagnosticAt(noteLocation, + diag::requirement_implied_by_conditional_conformance, + resolveType(Conformance->getType()), + Conformance->getProtocol()->getDeclaredInterfaceType()); } else if (genericCtx != reqDC && (genericCtx->isChildContextOf(reqDC) || isStaticOrInstanceMember(AffectedDecl))) { - emitDiagnostic(noteLocation, diag::required_by_decl_ref, - AffectedDecl->getDescriptiveKind(), - AffectedDecl->getFullName(), - reqDC->getSelfNominalTypeDecl()->getDeclaredType(), - req.getFirstType(), nonConformingType); + emitDiagnosticAt(noteLocation, diag::required_by_decl_ref, + AffectedDecl->getDescriptiveKind(), + AffectedDecl->getFullName(), + reqDC->getSelfNominalTypeDecl()->getDeclaredType(), + req.getFirstType(), nonConformingType); } else { - emitDiagnostic(noteLocation, diag::required_by_decl, - AffectedDecl->getDescriptiveKind(), - AffectedDecl->getFullName(), req.getFirstType(), - nonConformingType); + emitDiagnosticAt(noteLocation, diag::required_by_decl, + AffectedDecl->getDescriptiveKind(), + AffectedDecl->getFullName(), req.getFirstType(), + nonConformingType); } return true; @@ -518,15 +522,15 @@ bool MissingConformanceFailure::diagnoseAsAmbiguousOperatorRef() { auto rhsType = params[1].getPlainType(); if (lhsType->isEqual(rhsType)) { - emitDiagnostic(anchor->getLoc(), diag::cannot_apply_binop_to_same_args, - operatorID.str(), lhsType); + emitDiagnostic(diag::cannot_apply_binop_to_same_args, operatorID.str(), + lhsType); } else { - emitDiagnostic(anchor->getLoc(), diag::cannot_apply_binop_to_args, - operatorID.str(), lhsType, rhsType); + emitDiagnostic(diag::cannot_apply_binop_to_args, operatorID.str(), + lhsType, rhsType); } } else { - emitDiagnostic(anchor->getLoc(), diag::cannot_apply_unop_to_arg, - operatorID.str(), params[0].getPlainType()); + emitDiagnostic(diag::cannot_apply_unop_to_arg, operatorID.str(), + params[0].getPlainType()); } diagnoseAsNote(); @@ -593,12 +597,11 @@ void GenericArgumentsMismatchFailure::emitNoteForMismatch(int position) { auto noteLocation = param->getLoc(); - if (!noteLocation.isValid()) { - noteLocation = getAnchor()->getLoc(); - } + if (!noteLocation.isValid()) + noteLocation = getLoc(); - emitDiagnostic(noteLocation, diag::generic_argument_mismatch, - param->getName(), lhs, rhs); + emitDiagnosticAt(noteLocation, diag::generic_argument_mismatch, + param->getName(), lhs, rhs); } bool GenericArgumentsMismatchFailure::diagnoseAsError() { @@ -712,7 +715,7 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() { if (!diagnostic) return false; - emitDiagnostic(anchor->getLoc(), *diagnostic, fromType, toType); + emitDiagnosticAt(anchor->getLoc(), *diagnostic, fromType, toType); emitNotesForMismatches(); return true; } @@ -758,8 +761,9 @@ bool LabelingFailure::diagnoseAsNote() { const auto &choice = selectedOverload->choice; if (auto *decl = choice.getDeclOrNull()) { - emitDiagnostic(decl, diag::candidate_expected_different_labels, - stringifyLabels(argLabels), stringifyLabels(CorrectLabels)); + emitDiagnosticAt(decl, diag::candidate_expected_different_labels, + stringifyLabels(argLabels), + stringifyLabels(CorrectLabels)); return true; } @@ -767,20 +771,17 @@ bool LabelingFailure::diagnoseAsNote() { } bool NoEscapeFuncToTypeConversionFailure::diagnoseAsError() { - auto *anchor = getAnchor(); - if (diagnoseParameterUse()) return true; if (auto *typeVar = getRawFromType()->getAs()) { if (auto *GP = typeVar->getImpl().getGenericParameter()) { - emitDiagnostic(anchor->getLoc(), diag::converting_noescape_to_type, GP); + emitDiagnostic(diag::converting_noescape_to_type, GP); return true; } } - emitDiagnostic(anchor->getLoc(), diag::converting_noescape_to_type, - getToType()); + emitDiagnostic(diag::converting_noescape_to_type, getToType()); return true; } @@ -810,13 +811,12 @@ bool NoEscapeFuncToTypeConversionFailure::diagnoseParameterUse() const { auto paramInterfaceTy = argApplyInfo->getParamInterfaceType(); if (paramInterfaceTy->isTypeParameter()) { auto diagnoseGenericParamFailure = [&](GenericTypeParamDecl *decl) { - emitDiagnostic(anchor->getLoc(), - diag::converting_noespace_param_to_generic_type, + emitDiagnostic(diag::converting_noespace_param_to_generic_type, PD->getName(), paramInterfaceTy); auto declLoc = decl->getLoc(); if (declLoc.isValid()) - emitDiagnostic(decl, diag::generic_parameters_always_escaping); + emitDiagnosticAt(decl, diag::generic_parameters_always_escaping); }; // If this is a situation when non-escaping parameter is passed @@ -848,11 +848,10 @@ bool NoEscapeFuncToTypeConversionFailure::diagnoseParameterUse() const { if (!PD) return false; - emitDiagnostic(anchor->getLoc(), diagnostic, PD->getName()); + emitDiagnostic(diagnostic, PD->getName()); // Give a note and fix-it - auto note = - emitDiagnostic(PD->getLoc(), diag::noescape_parameter, PD->getName()); + auto note = emitDiagnosticAt(PD, diag::noescape_parameter, PD->getName()); if (!PD->isAutoClosure()) { SourceLoc reprLoc; @@ -864,46 +863,54 @@ bool NoEscapeFuncToTypeConversionFailure::diagnoseParameterUse() const { return true; } -bool MissingForcedDowncastFailure::diagnoseAsError() { - auto *expr = getAnchor(); +Expr *MissingForcedDowncastFailure::getAnchor() const { + auto *expr = FailureDiagnostic::getAnchor(); + if (auto *assignExpr = dyn_cast(expr)) - expr = assignExpr->getSrc(); + return assignExpr->getSrc(); - auto *coerceExpr = cast(expr); + return expr; +} +bool MissingForcedDowncastFailure::diagnoseAsError() { auto fromType = getFromType(); auto toType = getToType(); - emitDiagnostic(coerceExpr->getLoc(), diag::missing_forced_downcast, fromType, - toType) - .highlight(coerceExpr->getSourceRange()) - .fixItReplace(coerceExpr->getLoc(), "as!"); + emitDiagnostic(diag::missing_forced_downcast, fromType, toType) + .highlight(getSourceRange()) + .fixItReplace(getLoc(), "as!"); return true; } bool MissingAddressOfFailure::diagnoseAsError() { - auto *anchor = getAnchor(); auto argTy = getFromType(); auto paramTy = getToType(); if (paramTy->getAnyPointerElementType()) { - emitDiagnostic(anchor->getLoc(), diag::cannot_convert_argument_value, argTy, - paramTy) - .fixItInsert(anchor->getStartLoc(), "&"); + emitDiagnostic(diag::cannot_convert_argument_value, argTy, paramTy) + .fixItInsert(getSourceRange().Start, "&"); } else { - emitDiagnostic(anchor->getLoc(), diag::missing_address_of, argTy) - .fixItInsert(anchor->getStartLoc(), "&"); + emitDiagnostic(diag::missing_address_of, argTy) + .fixItInsert(getSourceRange().Start, "&"); } return true; } +Expr *MissingExplicitConversionFailure::getAnchor() const { + auto *anchor = FailureDiagnostic::getAnchor(); + + if (auto *assign = dyn_cast(anchor)) + return assign->getSrc(); + + if (auto *paren = dyn_cast(anchor)) + return paren->getSubExpr(); + + return anchor; +} + bool MissingExplicitConversionFailure::diagnoseAsError() { auto *DC = getDC(); auto *anchor = getAnchor(); - if (auto *assign = dyn_cast(anchor)) - anchor = assign->getSrc(); - if (auto *paren = dyn_cast(anchor)) - anchor = paren->getSubExpr(); auto fromType = getFromType(); auto toType = getToType(); @@ -915,9 +922,9 @@ bool MissingExplicitConversionFailure::diagnoseAsError() { if (!useAs && !TypeChecker::checkedCastMaySucceed(fromType, toType, DC)) return false; - auto *expr = findParentExpr(getAnchor()); + auto *expr = findParentExpr(anchor); if (!expr) - expr = getAnchor(); + expr = anchor; // If we're performing pattern matching, // "as" means something completely different... @@ -949,11 +956,12 @@ bool MissingExplicitConversionFailure::diagnoseAsError() { auto diagID = useAs ? diag::missing_explicit_conversion : diag::missing_forced_downcast; - auto diag = emitDiagnostic(anchor->getLoc(), diagID, fromType, toType); + auto diag = emitDiagnostic(diagID, fromType, toType); + if (!insertBefore.empty()) { - diag.fixItInsert(anchor->getStartLoc(), insertBefore); + diag.fixItInsert(getSourceRange().Start, insertBefore); } - diag.fixItInsertAfter(anchor->getEndLoc(), insertAfter); + diag.fixItInsertAfter(getSourceRange().End, insertAfter); return true; } @@ -974,20 +982,20 @@ bool MemberAccessOnOptionalBaseFailure::diagnoseAsError() { if (!unwrappedBaseType) return false; - emitDiagnostic(anchor->getLoc(), diag::optional_base_not_unwrapped, - baseType, Member, unwrappedBaseType); + 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 // in MissingOptionalUnwrapFailure:diagnose() to offer a default value during // the next compile. - emitDiagnostic(anchor->getLoc(), diag::optional_base_chain, Member) - .fixItInsertAfter(anchor->getEndLoc(), "?"); + emitDiagnostic(diag::optional_base_chain, Member) + .fixItInsertAfter(getSourceRange().End, "?"); if (!resultIsOptional) { - emitDiagnostic(anchor->getLoc(), diag::unwrap_with_force_value) - .fixItInsertAfter(anchor->getEndLoc(), "!"); + emitDiagnostic(diag::unwrap_with_force_value) + .fixItInsertAfter(getSourceRange().End, "!"); } return true; @@ -1008,7 +1016,7 @@ void MissingOptionalUnwrapFailure::offerDefaultValueUnwrapFixIt( if (argApplyInfo->getParameterFlags().isInOut()) return; - auto diag = emitDiagnostic(expr->getLoc(), diag::unwrap_with_default_value); + auto diag = emitDiagnosticAt(expr->getLoc(), diag::unwrap_with_default_value); // Figure out what we need to parenthesize. bool needsParensInside = @@ -1038,7 +1046,7 @@ void MissingOptionalUnwrapFailure::offerDefaultValueUnwrapFixIt( // Suggest a force-unwrap. void MissingOptionalUnwrapFailure::offerForceUnwrapFixIt(Expr *expr) const { - auto diag = emitDiagnostic(expr->getLoc(), diag::unwrap_with_force_value); + auto diag = emitDiagnosticAt(expr->getLoc(), diag::unwrap_with_force_value); // If expr is optional as the result of an optional chain and this last // dot isn't a member returning optional, then offer to force the last @@ -1112,8 +1120,8 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() { return false; } - emitDiagnostic(tryExpr->getTryLoc(), diag::missing_unwrap_optional_try, - getType(anchor)) + emitDiagnosticAt(tryExpr->getTryLoc(), diag::missing_unwrap_optional_try, + getType(anchor)) .fixItReplace({tryExpr->getTryLoc(), tryExpr->getQuestionLoc()}, "try!"); return true; @@ -1130,8 +1138,8 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() { if (!baseType->getOptionalObjectType()) return false; - emitDiagnostic(unwrappedExpr->getLoc(), diag::optional_not_unwrapped, - baseType, unwrappedType); + emitDiagnosticAt(unwrappedExpr->getLoc(), diag::optional_not_unwrapped, + baseType, unwrappedType); // If the expression we're unwrapping is the only reference to a // local variable whose type isn't explicit in the source, then @@ -1158,8 +1166,8 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() { if (auto declRefExpr = dyn_cast(initializer)) { if (declRefExpr->getDecl()->isImplicitlyUnwrappedOptional()) { - emitDiagnostic(declRefExpr->getLoc(), diag::unwrap_iuo_initializer, - baseType); + emitDiagnosticAt(declRefExpr->getLoc(), + diag::unwrap_iuo_initializer, baseType); } } @@ -1167,7 +1175,8 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() { bool voidReturn = fnTy->getResult()->isEqual(TupleType::getEmpty(getASTContext())); - auto diag = emitDiagnostic(varDecl->getLoc(), diag::unwrap_with_guard); + auto diag = + emitDiagnosticAt(varDecl->getLoc(), diag::unwrap_with_guard); diag.fixItInsert(binding->getStartLoc(), "guard "); if (voidReturn) { diag.fixItInsertAfter(binding->getEndLoc(), " else { return }"); @@ -1265,8 +1274,8 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { if (cs.isArrayType(argType) && paramType->getAnyPointerElementType(ptr) && (ptr == PTK_UnsafePointer || ptr == PTK_UnsafeRawPointer)) { - emitDiagnostic(inoutExpr->getLoc(), - diag::extra_address_of_unsafepointer, paramType) + emitDiagnosticAt(inoutExpr->getLoc(), + diag::extra_address_of_unsafepointer, paramType) .highlight(inoutExpr->getSourceRange()) .fixItRemove(inoutExpr->getStartLoc()); return true; @@ -1292,12 +1301,13 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { if (baseRef->getDecl() == ctor->getImplicitSelfDecl() && ctor->getDelegatingOrChainedInitKind(nullptr) == ConstructorDecl::BodyInitKind::Delegating) { - emitDiagnostic(loc, diag::assignment_let_property_delegating_init, - member->getName()); + emitDiagnosticAt(loc, diag::assignment_let_property_delegating_init, + member->getName()); if (auto overload = getOverloadChoiceIfAvailable( getConstraintLocator(member, ConstraintLocator::Member))) { if (auto *ref = overload->choice.getDeclOrNull()) - emitDiagnostic(ref, diag::decl_declared_here, ref->getFullName()); + emitDiagnosticAt(ref, diag::decl_declared_here, + ref->getFullName()); } return true; } @@ -1333,8 +1343,8 @@ bool RValueTreatedAsLValueFailure::diagnoseAsNote() { return false; auto *decl = overload->choice.getDecl(); - emitDiagnostic(decl, diag::candidate_is_not_assignable, - decl->getDescriptiveKind(), decl->getFullName()); + emitDiagnosticAt(decl, diag::candidate_is_not_assignable, + decl->getDescriptiveKind(), decl->getFullName()); return true; } @@ -1434,7 +1444,7 @@ bool TrailingClosureAmbiguityFailure::diagnoseAsNote() { // If we got here, then all of the choices have unique labels. Offer them in // order. for (const auto &choicePair : choicesByLabel) { - auto diag = emitDiagnostic( + auto diag = emitDiagnosticAt( expr->getLoc(), diag::ambiguous_because_of_trailing_closure, choicePair.first.empty(), choicePair.second->getFullName()); swift::fixItEncloseTrailingClosure(getASTContext(), diag, callExpr, @@ -1481,7 +1491,7 @@ bool AssignmentFailure::diagnoseAsError() { "'" + identifier.str().str() + "' is a read-only key path"; } } - emitDiagnostic(Loc, DeclDiagnostic, message) + emitDiagnosticAt(Loc, DeclDiagnostic, message) .highlight(immutableExpr->getSourceRange()); return true; } @@ -1514,7 +1524,7 @@ bool AssignmentFailure::diagnoseAsError() { message += " is immutable"; } - emitDiagnostic(Loc, DeclDiagnostic, message) + emitDiagnosticAt(Loc, DeclDiagnostic, message) .highlight(immutableExpr->getSourceRange()); // If there is a masked property of the same type, emit a @@ -1559,8 +1569,8 @@ bool AssignmentFailure::diagnoseAsError() { } else { fixItText = selfTy->getString() + "."; } - emitDiagnostic(startLoc, diag::masked_mutable_property, - fixItText, property->getDescriptiveKind(), selfTy) + emitDiagnosticAt(startLoc, diag::masked_mutable_property, fixItText, + property->getDescriptiveKind(), selfTy) .fixItInsert(startLoc, fixItText); } } @@ -1581,7 +1591,7 @@ bool AssignmentFailure::diagnoseAsError() { else message = "subscript is immutable"; - emitDiagnostic(Loc, DeclDiagnostic, message) + emitDiagnosticAt(Loc, DeclDiagnostic, message) .highlight(immutableExpr->getSourceRange()); return true; } @@ -1603,7 +1613,7 @@ bool AssignmentFailure::diagnoseAsError() { } else message += " is not settable"; - emitDiagnostic(Loc, diagID, message) + emitDiagnosticAt(Loc, diagID, message) .highlight(immutableExpr->getSourceRange()); return true; } @@ -1615,13 +1625,13 @@ bool AssignmentFailure::diagnoseAsError() { // If a keypath was the problem but wasn't resolved into a vardecl // it is ambiguous or unable to be used for setting. if (auto *KPE = dyn_cast_or_null(immutableExpr)) { - emitDiagnostic(Loc, DeclDiagnostic, "immutable key path") + emitDiagnosticAt(Loc, DeclDiagnostic, "immutable key path") .highlight(KPE->getSourceRange()); return true; } if (auto LE = dyn_cast(immutableExpr)) { - emitDiagnostic(Loc, DeclDiagnostic, "literals are not mutable") + emitDiagnosticAt(Loc, DeclDiagnostic, "literals are not mutable") .highlight(LE->getSourceRange()); return true; } @@ -1636,7 +1646,7 @@ bool AssignmentFailure::diagnoseAsError() { argsTuple->getNumElements() == 1) { if (auto LE = dyn_cast( argsTuple->getElement(0)->getSemanticsProvidingExpr())) { - emitDiagnostic(Loc, DeclDiagnostic, "literals are not mutable") + emitDiagnosticAt(Loc, DeclDiagnostic, "literals are not mutable") .highlight(LE->getSourceRange()); return true; } @@ -1656,7 +1666,7 @@ bool AssignmentFailure::diagnoseAsError() { name = std::string("'") + DRE->getDecl()->getBaseIdentifier().str().str() + "'"; - emitDiagnostic(Loc, DeclDiagnostic, name + " returns immutable value") + emitDiagnosticAt(Loc, DeclDiagnostic, name + " returns immutable value") .highlight(AE->getSourceRange()); return true; } @@ -1666,10 +1676,10 @@ bool AssignmentFailure::diagnoseAsError() { Type actualType = getType(immutableExpr)->getInOutObjectType(); if (!neededType->isEqual(actualType)) { if (DeclDiagnostic.ID != diag::cannot_pass_rvalue_inout_subelement.ID) { - emitDiagnostic(Loc, DeclDiagnostic, - "implicit conversion from '" + actualType->getString() + - "' to '" + neededType->getString() + - "' requires a temporary") + emitDiagnosticAt(Loc, DeclDiagnostic, + "implicit conversion from '" + + actualType->getString() + "' to '" + + neededType->getString() + "' requires a temporary") .highlight(immutableExpr->getSourceRange()); } return true; @@ -1677,14 +1687,14 @@ bool AssignmentFailure::diagnoseAsError() { } if (auto IE = dyn_cast(immutableExpr)) { - emitDiagnostic(Loc, DeclDiagnostic, - "result of conditional operator '? :' is never mutable") + emitDiagnosticAt(Loc, DeclDiagnostic, + "result of conditional operator '? :' is never mutable") .highlight(IE->getQuestionLoc()) .highlight(IE->getColonLoc()); return true; } - emitDiagnostic(Loc, TypeDiagnostic, getType(DestExpr)) + emitDiagnosticAt(Loc, TypeDiagnostic, getType(DestExpr)) .highlight(immutableExpr->getSourceRange()); return true; } @@ -1875,8 +1885,8 @@ bool ContextualFailure::diagnoseAsError() { if (CTP == CTP_ReturnSingleExpr || CTP == CTP_ReturnStmt) { // Special case the "conversion to void". if (getToType()->isVoid()) { - emitDiagnostic(anchor->getLoc(), diag::cannot_return_value_from_void_func) - .highlight(anchor->getSourceRange()); + emitDiagnostic(diag::cannot_return_value_from_void_func) + .highlight(getSourceRange()); return true; } } @@ -1886,9 +1896,9 @@ bool ContextualFailure::diagnoseAsError() { if (path.empty()) { if (auto *KPE = dyn_cast(anchor)) { - emitDiagnostic(KPE->getLoc(), - diag::expr_smart_keypath_value_covert_to_contextual_type, - getFromType(), getToType()); + emitDiagnosticAt(KPE->getLoc(), + diag::expr_smart_keypath_value_covert_to_contextual_type, + getFromType(), getToType()); return true; } @@ -1896,14 +1906,13 @@ bool ContextualFailure::diagnoseAsError() { return true; if (isa(anchor)) { - emitDiagnostic(anchor->getLoc(), diag::cannot_convert_initializer_value, - getFromType(), getToType()); + emitDiagnostic(diag::cannot_convert_initializer_value, getFromType(), + getToType()); return true; } if (isa(anchor)) { - emitDiagnostic(anchor->getLoc(), diag::cannot_convert_assign, - getFromType(), getToType()); + emitDiagnostic(diag::cannot_convert_assign, getFromType(), getToType()); return true; } @@ -1916,10 +1925,9 @@ bool ContextualFailure::diagnoseAsError() { // Special case of some common conversions involving Swift.String // indexes, catching cases where people attempt to index them with an integer. if (isIntegerToStringIndexConversion()) { - emitDiagnostic(anchor->getLoc(), diag::string_index_not_integer, - getFromType()) - .highlight(anchor->getSourceRange()); - emitDiagnostic(anchor->getLoc(), diag::string_index_not_integer_note); + emitDiagnostic(diag::string_index_not_integer, getFromType()) + .highlight(getSourceRange()); + emitDiagnostic(diag::string_index_not_integer_note); return true; } @@ -1934,8 +1942,9 @@ bool ContextualFailure::diagnoseAsError() { if (closure->hasExplicitResultType() && closure->getExplicitResultTypeLoc().getTypeRepr()) { auto resultRepr = closure->getExplicitResultTypeLoc().getTypeRepr(); - emitDiagnostic(resultRepr->getStartLoc(), - diag::incorrect_explicit_closure_result, fromType, toType) + emitDiagnosticAt(resultRepr->getStartLoc(), + diag::incorrect_explicit_closure_result, fromType, + toType) .fixItReplace(resultRepr->getSourceRange(), toType.getString()); return true; } @@ -1992,16 +2001,15 @@ bool ContextualFailure::diagnoseAsError() { if (CTP == CTP_ForEachStmt) { if (fromType->isAnyExistentialType()) { - emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform, + emitDiagnostic(diag::type_cannot_conform, /*isExistentialType=*/true, fromType, toType); return true; } emitDiagnostic( - anchor->getLoc(), diag::foreach_sequence_does_not_conform_to_expected_protocol, fromType, toType, bool(fromType->getOptionalObjectType())) - .highlight(anchor->getSourceRange()); + .highlight(getSourceRange()); return true; } @@ -2028,8 +2036,7 @@ bool ContextualFailure::diagnoseAsError() { auto *choice = overload->choice.getDecl(); auto fnType = fromType->getAs(); if (!fnType) { - emitDiagnostic(anchor->getLoc(), - diag::expected_result_in_contextual_member, + emitDiagnostic(diag::expected_result_in_contextual_member, choice->getFullName(), fromType, toType); return true; } @@ -2055,16 +2062,14 @@ bool ContextualFailure::diagnoseAsError() { if (numMissingArgs == 0 || numMissingArgs > 1) { auto diagnostic = emitDiagnostic( - anchor->getLoc(), diag::expected_parens_in_contextual_member, - choice->getFullName()); + diag::expected_parens_in_contextual_member, choice->getFullName()); // If there are no parameters we can suggest a fix-it // to form an explicit call. if (numMissingArgs == 0) - diagnostic.fixItInsertAfter(anchor->getEndLoc(), "()"); + diagnostic.fixItInsertAfter(getSourceRange().End, "()"); } else { - emitDiagnostic(anchor->getLoc(), - diag::expected_argument_in_contextual_member, + emitDiagnostic(diag::expected_argument_in_contextual_member, choice->getFullName(), params.front().getPlainType()); } @@ -2075,9 +2080,8 @@ bool ContextualFailure::diagnoseAsError() { return false; } - auto diag = - emitDiagnostic(anchor->getLoc(), diagnostic, fromType, toType); - diag.highlight(anchor->getSourceRange()); + auto diag = emitDiagnostic(diagnostic, fromType, toType); + diag.highlight(getSourceRange()); (void)tryFixIts(diag); return true; @@ -2089,7 +2093,7 @@ bool ContextualFailure::diagnoseAsNote() { return false; auto *decl = overload->choice.getDecl(); - emitDiagnostic(decl, diag::found_candidate_type, getFromType()); + emitDiagnosticAt(decl, diag::found_candidate_type, getFromType()); return true; } @@ -2165,7 +2169,7 @@ bool ContextualFailure::diagnoseConversionToNil() const { // Looks like it's something similar to `let _ = nil`. if (!parentExpr) { - emitDiagnostic(anchor->getLoc(), diag::unresolved_nil_literal); + emitDiagnostic(diag::unresolved_nil_literal); return true; } @@ -2185,7 +2189,7 @@ bool ContextualFailure::diagnoseConversionToNil() const { // If there is no enclosing expression it's something like // `(nil)` or `(a: nil)` which can't be inferred without a // contextual type. - emitDiagnostic(anchor->getLoc(), diag::unresolved_nil_literal); + emitDiagnostic(diag::unresolved_nil_literal); return true; } @@ -2214,8 +2218,7 @@ bool ContextualFailure::diagnoseConversionToNil() const { CTP = CTP_CoerceOperand; } else { // Otherwise let's produce a generic `nil` conversion diagnostic. - emitDiagnostic(anchor->getLoc(), diag::cannot_use_nil_with_this_type, - getToType()); + emitDiagnostic(diag::cannot_use_nil_with_this_type, getToType()); return true; } } @@ -2224,7 +2227,7 @@ bool ContextualFailure::diagnoseConversionToNil() const { return false; if (CTP == CTP_ThrowStmt) { - emitDiagnostic(anchor->getLoc(), diag::cannot_throw_nil); + emitDiagnostic(diag::cannot_throw_nil); return true; } @@ -2232,15 +2235,15 @@ bool ContextualFailure::diagnoseConversionToNil() const { if (!diagnostic) return false; - emitDiagnostic(anchor->getLoc(), *diagnostic, getToType()); + emitDiagnostic(*diagnostic, getToType()); if (CTP == CTP_Initialization) { - auto *patternTR = getContextualTypeLoc(locator->getAnchor()).getTypeRepr(); + auto *patternTR = getContextualTypeLoc(getRawAnchor()).getTypeRepr(); if (!patternTR) return true; - auto diag = emitDiagnostic(patternTR->getLoc(), diag::note_make_optional, - OptionalType::get(getToType())); + auto diag = emitDiagnosticAt(patternTR->getLoc(), diag::note_make_optional, + OptionalType::get(getToType())); if (patternTR->isSimple()) { diag.fixItInsertAfter(patternTR->getEndLoc(), "?"); } else { @@ -2299,24 +2302,21 @@ bool ContextualFailure::diagnoseMissingFunctionCall() const { getLocator()->getLastElementAs()) { if (auto enumElementPattern = dyn_cast(match->getPattern())) { - emitDiagnostic(enumElementPattern->getNameLoc(), - diag::enum_element_pattern_assoc_values_mismatch, - enumElementPattern->getName()); - emitDiagnostic(enumElementPattern->getNameLoc(), - diag::enum_element_pattern_assoc_values_remove) - .fixItRemove(enumElementPattern->getSubPattern()->getSourceRange()); + emitDiagnosticAt(enumElementPattern->getNameLoc(), + diag::enum_element_pattern_assoc_values_mismatch, + enumElementPattern->getName()); + emitDiagnosticAt(enumElementPattern->getNameLoc(), + diag::enum_element_pattern_assoc_values_remove) + .fixItRemove(enumElementPattern->getSubPattern()->getSourceRange()); return true; } } - auto *anchor = getAnchor(); - emitDiagnostic(anchor->getLoc(), diag::missing_nullary_call, - srcFT->getResult()) - .highlight(anchor->getSourceRange()) - .fixItInsertAfter(anchor->getEndLoc(), "()"); - - tryComputedPropertyFixIts(anchor); + emitDiagnostic(diag::missing_nullary_call, srcFT->getResult()) + .highlight(getSourceRange()) + .fixItInsertAfter(getSourceRange().End, "()"); + tryComputedPropertyFixIts(); return true; } @@ -2329,9 +2329,8 @@ bool ContextualFailure::diagnoseCoercionToUnrelatedType() const { auto diagnostic = getDiagnosticFor(CTP_CoerceOperand, toType); - auto diag = - emitDiagnostic(anchor->getLoc(), *diagnostic, fromType, toType); - diag.highlight(anchor->getSourceRange()); + auto diag = emitDiagnostic(*diagnostic, fromType, toType); + diag.highlight(getSourceRange()); (void)tryFixIts(diag); @@ -2346,10 +2345,10 @@ bool ContextualFailure::diagnoseConversionToBool() const { if (!toType->isBool()) return false; - auto *expr = getAnchor(); + const auto *expr = getAnchor(); // Check for "=" converting to Bool. The user probably meant ==. if (auto *AE = dyn_cast(expr->getValueProvidingExpr())) { - emitDiagnostic(AE->getEqualLoc(), diag::use_of_equal_instead_of_equality) + emitDiagnosticAt(AE->getEqualLoc(), diag::use_of_equal_instead_of_equality) .fixItReplace(AE->getEqualLoc(), "==") .highlight(AE->getDest()->getLoc()) .highlight(AE->getSrc()->getLoc()); @@ -2398,10 +2397,10 @@ bool ContextualFailure::diagnoseConversionToBool() const { } // FIXME: The outer parentheses may be superfluous too. - emitDiagnostic(expr->getLoc(), diag::optional_used_as_boolean, fromType, + emitDiagnostic(diag::optional_used_as_boolean, fromType, notOperatorLoc.isValid()) - .fixItInsert(expr->getStartLoc(), prefix) - .fixItInsertAfter(expr->getEndLoc(), suffix) + .fixItInsert(getSourceRange().Start, prefix) + .fixItInsertAfter(getSourceRange().End, suffix) .fixItRemove(notOperatorLoc); return true; } @@ -2429,10 +2428,10 @@ bool ContextualFailure::diagnoseConversionToBool() const { } // FIXME: The outer parentheses may be superfluous too. - emitDiagnostic(expr->getLoc(), diag::integer_used_as_boolean, fromType, + emitDiagnostic(diag::integer_used_as_boolean, fromType, notOperatorLoc.isValid()) - .fixItInsert(expr->getStartLoc(), prefix) - .fixItInsertAfter(expr->getEndLoc(), suffix) + .fixItInsert(getSourceRange().Start, prefix) + .fixItInsertAfter(getSourceRange().End, suffix) .fixItRemove(notOperatorLoc); return true; } @@ -2464,9 +2463,8 @@ bool ContextualFailure::diagnoseThrowsTypeMismatch() const { .getTypeWitnessByName(errorCodeType, getASTContext().Id_ErrorType) ->getCanonicalType(); if (errorType) { - auto diagnostic = - emitDiagnostic(anchor->getLoc(), diag::cannot_throw_error_code, - errorCodeType, errorType); + auto diagnostic = emitDiagnostic(diag::cannot_throw_error_code, + errorCodeType, errorType); if (auto *UDE = dyn_cast(anchor)) { diagnostic.fixItInsert(UDE->getDotLoc(), "("); diagnostic.fixItInsertAfter(UDE->getEndLoc(), ")"); @@ -2479,9 +2477,8 @@ bool ContextualFailure::diagnoseThrowsTypeMismatch() const { // The conversion destination of throw is always ErrorType (at the moment) // if this ever expands, this should be a specific form like () is for // return. - emitDiagnostic(anchor->getLoc(), diag::cannot_convert_thrown_type, - getFromType()) - .highlight(anchor->getSourceRange()); + emitDiagnostic(diag::cannot_convert_thrown_type, getFromType()) + .highlight(getSourceRange()); return true; } @@ -2494,14 +2491,13 @@ bool ContextualFailure::diagnoseYieldByReferenceMismatch() const { auto contextualType = getToType(); if (auto exprLV = exprType->getAs()) { - emitDiagnostic(anchor->getLoc(), diag::cannot_yield_wrong_type_by_reference, + emitDiagnostic(diag::cannot_yield_wrong_type_by_reference, exprLV->getObjectType(), contextualType); } else if (exprType->isEqual(contextualType)) { - emitDiagnostic(anchor->getLoc(), - diag::cannot_yield_rvalue_by_reference_same_type, exprType); + emitDiagnostic(diag::cannot_yield_rvalue_by_reference_same_type, exprType); } else { - emitDiagnostic(anchor->getLoc(), diag::cannot_yield_rvalue_by_reference, - exprType, contextualType); + emitDiagnostic(diag::cannot_yield_rvalue_by_reference, exprType, + contextualType); } return true; } @@ -2555,8 +2551,7 @@ bool ContextualFailure::tryRawRepresentableFixIts( fixItAfter += "!" + convWrapAfter.str(); diagnostic.flush(); - emitDiagnostic(expr->getLoc(), - diag::construct_raw_representable_from_unwrapped_value, + emitDiagnostic(diag::construct_raw_representable_from_unwrapped_value, toType, fromType) .highlight(exprRange) .fixItInsert(exprRange.Start, fixItBefore) @@ -2655,8 +2650,8 @@ bool ContextualFailure::tryIntegerCastFixIts( Type innerTy = getType(innerE); if (TypeChecker::isConvertibleTo(innerTy, toType, getDC())) { // Remove the unnecessary cast. - diagnostic.fixItRemoveChars(anchor->getLoc(), innerE->getStartLoc()) - .fixItRemove(anchor->getEndLoc()); + diagnostic.fixItRemoveChars(getLoc(), innerE->getStartLoc()) + .fixItRemove(getSourceRange().End); return true; } } @@ -2665,7 +2660,7 @@ bool ContextualFailure::tryIntegerCastFixIts( std::string convWrapBefore = toType.getString(); convWrapBefore += "("; std::string convWrapAfter = ")"; - SourceRange exprRange = anchor->getSourceRange(); + SourceRange exprRange = getSourceRange(); diagnostic.fixItInsert(exprRange.Start, convWrapBefore); diagnostic.fixItInsertAfter(exprRange.End, convWrapAfter); return true; @@ -2731,14 +2726,12 @@ bool ContextualFailure::tryTypeCoercionFixIt( SourceLoc(), nullptr, SourceRange()); if (Kind != CheckedCastKind::Unresolved) { - auto *anchor = getAnchor(); - bool canUseAs = Kind == CheckedCastKind::Coercion || Kind == CheckedCastKind::BridgingCoercion; if (bothOptional && canUseAs) toType = OptionalType::get(toType); diagnostic.fixItInsert(Lexer::getLocForEndOfToken(getASTContext().SourceMgr, - anchor->getEndLoc()), + getSourceRange().End), diag::insert_type_coercion, canUseAs, toType); return true; } @@ -2813,9 +2806,9 @@ bool ContextualFailure::tryProtocolConformanceFixIt( // missing protocols. // // TODO: Maybe also insert the requirement stubs? - auto conformanceDiag = emitDiagnostic( - getAnchor()->getLoc(), diag::assign_protocol_conformance_fix_it, - unwrappedToType, nominal->getDescriptiveKind(), fromType); + auto conformanceDiag = + emitDiagnostic(diag::assign_protocol_conformance_fix_it, unwrappedToType, + nominal->getDescriptiveKind(), fromType); if (nominal->getInherited().size() > 0) { auto lastInherited = nominal->getInherited().back().getLoc(); auto lastInheritedEndLoc = @@ -2830,8 +2823,8 @@ bool ContextualFailure::tryProtocolConformanceFixIt( return true; } -void ContextualFailure::tryComputedPropertyFixIts(Expr *expr) const { - if (!isa(expr)) +void ContextualFailure::tryComputedPropertyFixIts() const { + if (!isa(getAnchor())) return; // It is possible that we're looking at a stored property being @@ -2864,8 +2857,7 @@ void ContextualFailure::tryComputedPropertyFixIts(Expr *expr) const { if (!VD->isStatic() && !VD->getAttrs().getAttribute() && initExpr && isa(initExpr)) { - auto diag = emitDiagnostic(expr->getLoc(), - diag::extension_stored_property_fixit, + auto diag = emitDiagnostic(diag::extension_stored_property_fixit, VD->getName()); diag.fixItRemove(PBD->getEqualLoc(i)); @@ -2978,7 +2970,7 @@ bool TupleContextualFailure::diagnoseAsError() { else return false; - emitDiagnostic(getAnchor()->getLoc(), diagnostic, getFromType(), getToType()); + emitDiagnostic(diagnostic, getFromType(), getToType()); return true; } @@ -2988,7 +2980,7 @@ bool FunctionTypeMismatch::diagnoseAsError() { if (!diagnostic) return false; - emitDiagnostic(getAnchor()->getLoc(), *diagnostic, getFromType(), getToType()); + emitDiagnostic(*diagnostic, getFromType(), getToType()); return true; } @@ -2999,17 +2991,16 @@ bool AutoClosureForwardingFailure::diagnoseAsError() { // We need a raw anchor here because `getAnchor()` is simplified // to the argument expression. auto *argExpr = getArgumentExpr(getRawAnchor(), last.getArgIdx()); - emitDiagnostic(argExpr->getLoc(), diag::invalid_autoclosure_forwarding) + emitDiagnosticAt(argExpr->getLoc(), diag::invalid_autoclosure_forwarding) .highlight(argExpr->getSourceRange()) .fixItInsertAfter(argExpr->getEndLoc(), "()"); return true; } bool AutoClosurePointerConversionFailure::diagnoseAsError() { - auto *anchor = getAnchor(); auto diagnostic = diag::invalid_autoclosure_pointer_conversion; - emitDiagnostic(anchor->getLoc(), diagnostic, getFromType(), getToType()) - .highlight(anchor->getSourceRange()); + emitDiagnostic(diagnostic, getFromType(), getToType()) + .highlight(getSourceRange()); return true; } @@ -3020,20 +3011,22 @@ bool NonOptionalUnwrapFailure::diagnoseAsError() { if (isa(anchor)) diagnostic = diag::invalid_force_unwrap; - emitDiagnostic(anchor->getLoc(), diagnostic, BaseType) - .highlight(anchor->getSourceRange()) - .fixItRemove(anchor->getEndLoc()); - + auto range = getSourceRange(); + emitDiagnostic(diagnostic, BaseType).highlight(range).fixItRemove(range.End); return true; } +Expr *MissingCallFailure::getAnchor() const { + auto *anchor = FailureDiagnostic::getAnchor(); + if (auto *FVE = dyn_cast(anchor)) + return FVE->getSubExpr(); + return anchor; +} + bool MissingCallFailure::diagnoseAsError() { auto *baseExpr = getAnchor(); SourceLoc insertLoc = baseExpr->getEndLoc(); - if (auto *FVE = dyn_cast(baseExpr)) - baseExpr = FVE->getSubExpr(); - // Calls are not yet supported by key path, but it // is useful to record this fix to diagnose chaining // where one of the key path components is a method @@ -3049,9 +3042,8 @@ bool MissingCallFailure::diagnoseAsError() { case ConstraintLocator::ContextualType: case ConstraintLocator::ApplyArgToParam: { auto fnType = getType(baseExpr)->castTo(); - emitDiagnostic(baseExpr->getLoc(), diag::missing_nullary_call, - fnType->getResult()) - .fixItInsertAfter(baseExpr->getEndLoc(), "()"); + emitDiagnostic(diag::missing_nullary_call, fnType->getResult()) + .fixItInsertAfter(getSourceRange().End, "()"); return true; } @@ -3074,14 +3066,14 @@ bool MissingCallFailure::diagnoseAsError() { } if (auto *DRE = dyn_cast(baseExpr)) { - emitDiagnostic(baseExpr->getLoc(), diag::did_not_call_function, + emitDiagnostic(diag::did_not_call_function, DRE->getDecl()->getBaseIdentifier()) .fixItInsertAfter(insertLoc, "()"); return true; } if (auto *UDE = dyn_cast(baseExpr)) { - emitDiagnostic(baseExpr->getLoc(), diag::did_not_call_method, + emitDiagnostic(diag::did_not_call_method, UDE->getName().getBaseIdentifier()) .fixItInsertAfter(insertLoc, "()"); return true; @@ -3089,7 +3081,7 @@ bool MissingCallFailure::diagnoseAsError() { if (auto *DSCE = dyn_cast(baseExpr)) { if (auto *DRE = dyn_cast(DSCE->getFn())) { - emitDiagnostic(baseExpr->getLoc(), diag::did_not_call_method, + emitDiagnostic(diag::did_not_call_method, DRE->getDecl()->getBaseIdentifier()) .fixItInsertAfter(insertLoc, "()"); return true; @@ -3099,52 +3091,50 @@ bool MissingCallFailure::diagnoseAsError() { if (auto *AE = dyn_cast(baseExpr)) { auto *srcExpr = AE->getSrc(); if (auto *fnType = getType(srcExpr)->getAs()) { - emitDiagnostic(srcExpr->getLoc(), diag::missing_nullary_call, - fnType->getResult()) + emitDiagnosticAt(srcExpr->getLoc(), diag::missing_nullary_call, + fnType->getResult()) .highlight(srcExpr->getSourceRange()) .fixItInsertAfter(srcExpr->getEndLoc(), "()"); return true; } } - emitDiagnostic(baseExpr->getLoc(), diag::did_not_call_function_value) + emitDiagnostic(diag::did_not_call_function_value) .fixItInsertAfter(insertLoc, "()"); return true; } bool ExtraneousPropertyWrapperUnwrapFailure::diagnoseAsError() { - auto loc = getAnchor()->getLoc(); auto newPrefix = usingStorageWrapper() ? "$" : "_"; if (auto *member = getReferencedMember()) { - emitDiagnostic(loc, diag::incorrect_property_wrapper_reference_member, + emitDiagnostic(diag::incorrect_property_wrapper_reference_member, member->getDescriptiveKind(), member->getFullName(), false, getToType()) - .fixItInsert(loc, newPrefix); + .fixItInsert(getLoc(), newPrefix); return true; } - emitDiagnostic(loc, diag::incorrect_property_wrapper_reference, - getPropertyName(), getFromType(), getToType(), false) - .fixItInsert(loc, newPrefix); + emitDiagnostic(diag::incorrect_property_wrapper_reference, getPropertyName(), + getFromType(), getToType(), false) + .fixItInsert(getLoc(), newPrefix); return true; } bool MissingPropertyWrapperUnwrapFailure::diagnoseAsError() { - auto loc = getAnchor()->getLoc(); auto endLoc = getAnchor()->getLoc().getAdvancedLoc(1); if (auto *member = getReferencedMember()) { - emitDiagnostic(loc, diag::incorrect_property_wrapper_reference_member, + emitDiagnostic(diag::incorrect_property_wrapper_reference_member, member->getDescriptiveKind(), member->getFullName(), true, getToType()) - .fixItRemoveChars(loc, endLoc); + .fixItRemoveChars(getLoc(), endLoc); return true; } - emitDiagnostic(loc, diag::incorrect_property_wrapper_reference, - getPropertyName(), getFromType(), getToType(), true) - .fixItRemoveChars(loc, endLoc); + emitDiagnostic(diag::incorrect_property_wrapper_reference, getPropertyName(), + getFromType(), getToType(), true) + .fixItRemoveChars(getLoc(), endLoc); return true; } @@ -3154,13 +3144,12 @@ bool SubscriptMisuseFailure::diagnoseAsError() { auto *memberExpr = cast(getRawAnchor()); auto *baseExpr = getAnchor(); - auto memberRange = baseExpr->getSourceRange(); + auto memberRange = getSourceRange(); (void)simplifyLocator(getConstraintSystem(), getLocator(), memberRange); auto nameLoc = DeclNameLoc(memberRange.Start); - auto diag = emitDiagnostic(baseExpr->getLoc(), - diag::could_not_find_subscript_member_did_you_mean, + auto diag = emitDiagnostic(diag::could_not_find_subscript_member_did_you_mean, getType(baseExpr)); diag.highlight(memberRange).highlight(nameLoc.getSourceRange()); @@ -3187,8 +3176,8 @@ bool SubscriptMisuseFailure::diagnoseAsError() { diag.flush(); if (auto overload = getOverloadChoiceIfAvailable(getLocator())) { - emitDiagnostic(overload->choice.getDecl(), diag::kind_declared_here, - DescriptiveDeclKind::Subscript); + emitDiagnosticAt(overload->choice.getDecl(), diag::kind_declared_here, + DescriptiveDeclKind::Subscript); } return true; @@ -3196,7 +3185,7 @@ bool SubscriptMisuseFailure::diagnoseAsError() { bool SubscriptMisuseFailure::diagnoseAsNote() { if (auto overload = getOverloadChoiceIfAvailable(getLocator())) { - emitDiagnostic(overload->choice.getDecl(), diag::found_candidate); + emitDiagnosticAt(overload->choice.getDecl(), diag::found_candidate); return true; } return false; @@ -3257,13 +3246,13 @@ bool MissingMemberFailure::diagnoseAsError() { return hasUnresolvedPattern ? nullptr : expr; }); if (hasUnresolvedPattern && !baseType->getAs()) { - emitDiagnostic(anchor->getLoc(), - diag::cannot_match_unresolved_expr_pattern_with_value, baseType); + emitDiagnostic(diag::cannot_match_unresolved_expr_pattern_with_value, + baseType); return; } - emitDiagnostic(anchor->getLoc(), diagnostic, baseType, getName()) - .highlight(baseExpr->getSourceRange()) + emitDiagnostic(diagnostic, baseType, getName()) + .highlight(getSourceRange()) .highlight(nameLoc.getSourceRange()); }; @@ -3274,37 +3263,35 @@ bool MissingMemberFailure::diagnoseAsError() { }; if (getName().getBaseName().getKind() == DeclBaseName::Kind::Subscript) { - auto loc = anchor->getLoc(); if (auto *metatype = baseType->getAs()) { - emitDiagnostic(loc, diag::could_not_find_type_member, + emitDiagnostic(diag::could_not_find_type_member, metatype->getInstanceType(), getName()) - .highlight(baseExpr->getSourceRange()); + .highlight(getSourceRange()); } else { - emitDiagnostic(loc, diag::could_not_find_value_subscript, baseType) - .highlight(baseExpr->getSourceRange()); + emitDiagnostic(diag::could_not_find_value_subscript, baseType) + .highlight(getSourceRange()); } } else if (getName().getBaseName() == "deinit") { // Specialised diagnostic if trying to access deinitialisers - emitDiagnostic(anchor->getLoc(), diag::destructor_not_accessible) - .highlight(baseExpr->getSourceRange()); + emitDiagnostic(diag::destructor_not_accessible).highlight(getSourceRange()); } else if (auto metatypeTy = baseType->getAs()) { auto instanceTy = metatypeTy->getInstanceType(); tryTypoCorrection(baseType); if (DeclName rightName = findCorrectEnumCaseName(instanceTy, corrections, getName())) { - emitDiagnostic(anchor->getLoc(), diag::could_not_find_enum_case, - instanceTy, getName(), rightName) + emitDiagnostic(diag::could_not_find_enum_case, instanceTy, getName(), + rightName) .fixItReplace(nameLoc.getBaseNameLoc(), rightName.getBaseIdentifier().str()); return true; } if (auto correction = corrections.claimUniqueCorrection()) { - auto diagnostic = emitDiagnostic( - anchor->getLoc(), diag::could_not_find_type_member_corrected, - instanceTy, getName(), correction->CorrectedName); - diagnostic.highlight(baseExpr->getSourceRange()) + auto diagnostic = + emitDiagnostic(diag::could_not_find_type_member_corrected, instanceTy, + getName(), correction->CorrectedName); + diagnostic.highlight(getSourceRange()) .highlight(nameLoc.getSourceRange()); correction->addFixits(diagnostic); } else if (instanceTy->getAnyNominal() && @@ -3321,9 +3308,8 @@ bool MissingMemberFailure::diagnoseAsError() { // "no such member" one. if (result.ViableCandidates.empty() && result.UnviableCandidates.empty()) { - emitDiagnostic(anchor->getLoc(), diag::no_accessible_initializers, - instanceTy) - .highlight(baseExpr->getSourceRange()); + emitDiagnostic(diag::no_accessible_initializers, instanceTy) + .highlight(getSourceRange()); } else { emitBasicError(baseType); } @@ -3331,9 +3317,9 @@ bool MissingMemberFailure::diagnoseAsError() { emitBasicError(baseType); } } else if (auto moduleTy = baseType->getAs()) { - emitDiagnostic(baseExpr->getLoc(), diag::no_member_of_module, - moduleTy->getModule()->getName(), getName()) - .highlight(baseExpr->getSourceRange()) + emitDiagnosticAt(baseExpr->getLoc(), diag::no_member_of_module, + moduleTy->getModule()->getName(), getName()) + .highlight(getSourceRange()) .highlight(nameLoc.getSourceRange()); return true; } else { @@ -3343,14 +3329,16 @@ bool MissingMemberFailure::diagnoseAsError() { auto loc = ED->getNameLoc(); if (loc.isValid()) { emitBasicError(baseType); - emitDiagnostic(loc, diag::did_you_mean_raw_type); + emitDiagnosticAt(loc, diag::did_you_mean_raw_type); return true; } } else if (baseType->isAny()) { emitBasicError(baseType); - emitDiagnostic(anchor->getLoc(), diag::any_as_anyobject_fixit) - .fixItInsert(baseExpr->getStartLoc(), "(") - .fixItInsertAfter(baseExpr->getEndLoc(), " as AnyObject)"); + + auto range = getSourceRange(); + emitDiagnostic(diag::any_as_anyobject_fixit) + .fixItInsert(range.Start, "(") + .fixItInsertAfter(range.End, " as AnyObject)"); return true; } @@ -3365,30 +3353,26 @@ bool MissingMemberFailure::diagnoseAsError() { if (auto correction = corrections.claimUniqueCorrection()) { auto diagnostic = emitDiagnostic( - anchor->getLoc(), - diag::could_not_find_value_dynamic_member_corrected, - baseExprType, baseType, getName(), - correction->CorrectedName); - diagnostic.highlight(baseExpr->getSourceRange()) + diag::could_not_find_value_dynamic_member_corrected, baseExprType, + baseType, getName(), correction->CorrectedName); + diagnostic.highlight(getSourceRange()) .highlight(nameLoc.getSourceRange()); correction->addFixits(diagnostic); } else { - auto diagnostic = emitDiagnostic( - anchor->getLoc(), - diag::could_not_find_value_dynamic_member, - baseExprType, baseType, getName()); - diagnostic.highlight(baseExpr->getSourceRange()) + auto diagnostic = + emitDiagnostic(diag::could_not_find_value_dynamic_member, + baseExprType, baseType, getName()); + diagnostic.highlight(getSourceRange()) .highlight(nameLoc.getSourceRange()); } } else { if (auto correction = corrections.claimUniqueCorrection()) { - auto diagnostic = emitDiagnostic( - anchor->getLoc(), - diag::could_not_find_value_member_corrected, - baseType, getName(), - correction->CorrectedName); - diagnostic.highlight(baseExpr->getSourceRange()) + auto diagnostic = + emitDiagnostic(diag::could_not_find_value_member_corrected, + baseType, getName(), correction->CorrectedName); + diagnostic.highlight(getSourceRange()) .highlight(nameLoc.getSourceRange()); + correction->addFixits(diagnostic); } else { emitBasicError(baseType); @@ -3412,9 +3396,7 @@ bool MissingMemberFailure::diagnoseForDynamicCallable() const { auto &ctx = getASTContext(); if (arguments.front() == ctx.Id_withKeywordArguments) { - auto anchor = getAnchor(); - emitDiagnostic(anchor->getLoc(), - diag::missing_dynamic_callable_kwargs_method, getBaseType()); + emitDiagnostic(diag::missing_dynamic_callable_kwargs_method, getBaseType()); return true; } @@ -3437,16 +3419,15 @@ bool InvalidMemberRefOnExistential::diagnoseAsError() { baseExpr = call->getFn(); } - emitDiagnostic(getAnchor()->getLoc(), - diag::could_not_use_member_on_existential, getBaseType(), + emitDiagnostic(diag::could_not_use_member_on_existential, getBaseType(), getName()) .highlight(nameLoc.getSourceRange()) - .highlight(baseExpr->getSourceRange()); + .highlight(getSourceRange()); return true; } bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { - auto loc = getAnchor()->getLoc(); + auto loc = getLoc(); auto &cs = getConstraintSystem(); auto *DC = getDC(); auto locator = getLocator(); @@ -3489,7 +3470,7 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { !BaseType->is()) { if (auto ctorRef = dyn_cast(getRawAnchor())) { if (isa(ctorRef->getBase())) { - emitDiagnostic(loc, diag::super_initializer_not_in_initializer); + emitDiagnostic(diag::super_initializer_not_in_initializer); return true; } @@ -3518,13 +3499,13 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { !isCallArgument(initCall) && getContextualTypePurpose(getRootExpr(ctorRef)) == CTP_Unused) { auto fixItLoc = ctorRef->getBase()->getSourceRange().End; - emitDiagnostic(loc, diag::init_not_instance_member_use_assignment) + emitDiagnostic(diag::init_not_instance_member_use_assignment) .fixItInsertAfter(fixItLoc, " = "); return true; } SourceRange fixItRng = ctorRef->getBase()->getSourceRange(); - emitDiagnostic(loc, diag::init_not_instance_member) + emitDiagnostic(diag::init_not_instance_member) .fixItInsert(fixItRng.Start, "type(of: ") .fixItInsertAfter(fixItRng.End, ")"); return true; @@ -3557,10 +3538,10 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { if (TypeDC->getSelfNominalTypeDecl() == instanceTy->getAnyNominal()) { if (propertyInitializer) { - emitDiagnostic(loc, diag::instance_member_in_initializer, Name); + emitDiagnostic(diag::instance_member_in_initializer, Name); return true; } else { - emitDiagnostic(loc, diag::instance_member_in_default_parameter, Name); + emitDiagnostic(diag::instance_member_in_default_parameter, Name); return true; } } @@ -3578,8 +3559,8 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { auto arg = callExpr->getArg(); if (fnType->is()) { - emitDiagnostic(arg->getStartLoc(), - diag::missing_init_on_metatype_initialization) + emitDiagnosticAt(arg->getStartLoc(), + diag::missing_init_on_metatype_initialization) .highlight(fnExpr->getSourceRange()); return true; } @@ -3594,7 +3575,7 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { if (memberTypeContext && currentTypeContext && memberTypeContext->getSemanticDepth() < currentTypeContext->getSemanticDepth()) { - emitDiagnostic(loc, diag::could_not_use_instance_member_on_type, + emitDiagnostic(diag::could_not_use_instance_member_on_type, currentTypeContext->getDeclaredInterfaceType(), Name, memberTypeContext->getDeclaredInterfaceType(), true) .highlight(baseRange) @@ -3605,16 +3586,16 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { if (auto *UDE = dyn_cast(getRawAnchor())) { auto *baseExpr = UDE->getBase(); if (isa(baseExpr)) { - emitDiagnostic(loc, diag::instance_member_use_on_type, instanceTy, Name) - .highlight(baseExpr->getSourceRange()); + emitDiagnostic(diag::instance_member_use_on_type, instanceTy, Name) + .highlight(getSourceRange()); return true; } } // Just emit a generic "instance member cannot be used" error - emitDiagnostic(loc, diag::could_not_use_instance_member_on_type, instanceTy, + emitDiagnostic(diag::could_not_use_instance_member_on_type, instanceTy, Name, instanceTy, false) - .highlight(getAnchor()->getSourceRange()); + .highlight(getSourceRange()); return true; } else { // If the base of the lookup is a protocol metatype, suggest @@ -3639,21 +3620,21 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { // of a protocol -- otherwise a diagnostic talking about // static members doesn't make a whole lot of sense if (isa(Member)) { - Diag.emplace(emitDiagnostic(loc, diag::typealias_outside_of_protocol, - Name)); + Diag.emplace( + emitDiagnostic(diag::typealias_outside_of_protocol, Name)); } else if (isa(Member)) { - Diag.emplace(emitDiagnostic(loc, diag::assoc_type_outside_of_protocol, - Name)); + Diag.emplace( + emitDiagnostic(diag::assoc_type_outside_of_protocol, Name)); } else if (isa(Member)) { - Diag.emplace(emitDiagnostic(loc, diag::construct_protocol_by_name, - instanceTy)); + Diag.emplace( + emitDiagnostic(diag::construct_protocol_by_name, instanceTy)); } else { Diag.emplace(emitDiagnostic( - loc, diag::could_not_use_type_member_on_protocol_metatype, baseTy, + diag::could_not_use_type_member_on_protocol_metatype, baseTy, Name)); } - Diag->highlight(baseRange).highlight(getAnchor()->getSourceRange()); + Diag->highlight(baseRange).highlight(getSourceRange()); // See through function decl context if (auto parent = cs.DC->getInnermostTypeContext()) { @@ -3661,7 +3642,7 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { // 'Proto.static', suggest 'Self.static' if (auto extensionContext = parent->getExtendedProtocolDecl()) { if (extensionContext->getDeclaredType()->isEqual(instanceTy)) { - Diag->fixItReplace(getAnchor()->getSourceRange(), "Self"); + Diag->fixItReplace(getSourceRange(), "Self"); } } } @@ -3679,11 +3660,11 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { } if (isa(Member)) { - Diag.emplace(emitDiagnostic( - loc, diag::could_not_use_enum_element_on_instance, Name)); + Diag.emplace( + emitDiagnostic(diag::could_not_use_enum_element_on_instance, Name)); } else { - Diag.emplace(emitDiagnostic( - loc, diag::could_not_use_type_member_on_instance, baseTy, Name)); + Diag.emplace(emitDiagnostic(diag::could_not_use_type_member_on_instance, + baseTy, Name)); } Diag->highlight(getAnchor()->getSourceRange()); @@ -3775,42 +3756,50 @@ bool PartialApplicationFailure::diagnoseAsError() { ? diag::partial_application_of_function_invalid_swift4 : diag::partial_application_of_function_invalid; - emitDiagnostic(anchor->getNameLoc(), diagnostic, kind); + emitDiagnosticAt(anchor->getNameLoc(), diagnostic, kind); return true; } bool InvalidDynamicInitOnMetatypeFailure::diagnoseAsError() { - auto *anchor = getRawAnchor(); - emitDiagnostic(anchor->getLoc(), diag::dynamic_construct_class, + emitDiagnostic(diag::dynamic_construct_class, BaseType->getMetatypeInstanceType()) .highlight(BaseRange); - emitDiagnostic(Init, diag::note_nonrequired_initializer, Init->isImplicit(), - Init->getFullName()); + emitDiagnosticAt(Init, diag::note_nonrequired_initializer, Init->isImplicit(), + Init->getFullName()); return true; } bool InitOnProtocolMetatypeFailure::diagnoseAsError() { - auto *anchor = getRawAnchor(); if (IsStaticallyDerived) { - emitDiagnostic(anchor->getLoc(), diag::construct_protocol_by_name, + emitDiagnostic(diag::construct_protocol_by_name, BaseType->getMetatypeInstanceType()) .highlight(BaseRange); } else { - emitDiagnostic(anchor->getLoc(), diag::construct_protocol_value, BaseType) + emitDiagnostic(diag::construct_protocol_value, BaseType) .highlight(BaseRange); } return true; } -bool ImplicitInitOnNonConstMetatypeFailure::diagnoseAsError() { +SourceLoc ImplicitInitOnNonConstMetatypeFailure::getLoc() const { auto *apply = cast(getRawAnchor()); - auto loc = apply->getArg()->getStartLoc(); - emitDiagnostic(loc, diag::missing_init_on_metatype_initialization) - .fixItInsert(loc, ".init"); + return apply->getArg()->getStartLoc(); +} + +bool ImplicitInitOnNonConstMetatypeFailure::diagnoseAsError() { + emitDiagnostic(diag::missing_init_on_metatype_initialization) + .fixItInsert(getLoc(), ".init"); return true; } +Expr *MissingArgumentsFailure::getAnchor() const { + auto *anchor = FailureDiagnostic::getAnchor(); + if (auto *captureList = dyn_cast(anchor)) + return captureList->getClosureBody(); + return anchor; +} + bool MissingArgumentsFailure::diagnoseAsError() { auto *locator = getLocator(); @@ -3827,8 +3816,6 @@ bool MissingArgumentsFailure::diagnoseAsError() { return false; auto *anchor = getAnchor(); - if (auto *captureList = dyn_cast(anchor)) - anchor = captureList->getClosureBody(); if (auto *closure = dyn_cast(anchor)) return diagnoseClosure(closure); @@ -3846,8 +3833,8 @@ bool MissingArgumentsFailure::diagnoseAsError() { auto info = *(getFunctionArgApplyInfo(locator)); auto *argExpr = info.getArgExpr(); - emitDiagnostic(argExpr->getLoc(), diag::cannot_convert_argument_value, - info.getArgType(), info.getParamType()); + emitDiagnosticAt(argExpr->getLoc(), diag::cannot_convert_argument_value, + info.getArgType(), info.getParamType()); // TODO: It would be great so somehow point out which arguments are missing. return true; } @@ -3859,8 +3846,7 @@ bool MissingArgumentsFailure::diagnoseAsError() { // let _: (Int) -> Void = foo // ``` if (locator->isLastElement()) { - emitDiagnostic(anchor->getLoc(), diag::cannot_convert_initializer_value, - getType(anchor), + emitDiagnostic(diag::cannot_convert_initializer_value, getType(anchor), resolveType(getContextualType(getAnchor()))); // TODO: It would be great so somehow point out which arguments are missing. return true; @@ -3894,8 +3880,7 @@ bool MissingArgumentsFailure::diagnoseAsError() { }, [&] { arguments << ", "; }); - auto diag = emitDiagnostic(anchor->getLoc(), diag::missing_arguments_in_call, - arguments.str()); + auto diag = emitDiagnostic(diag::missing_arguments_in_call, arguments.str()); Expr *fnExpr = nullptr; Expr *argExpr = nullptr; @@ -3925,7 +3910,7 @@ bool MissingArgumentsFailure::diagnoseAsError() { if (auto selectedOverload = getCalleeOverloadChoiceIfAvailable(locator)) { if (auto *decl = selectedOverload->choice.getDeclOrNull()) { - emitDiagnostic(decl, diag::decl_declared_here, decl->getFullName()); + emitDiagnosticAt(decl, diag::decl_declared_here, decl->getFullName()); } } @@ -3937,10 +3922,12 @@ bool MissingArgumentsFailure::diagnoseAsNote() { if (auto overload = getCalleeOverloadChoiceIfAvailable(locator)) { auto *fn = resolveType(overload->openedType)->getAs(); auto loc = overload->choice.getDecl()->getLoc(); + if (loc.isInvalid()) - loc = getAnchor()->getLoc(); - emitDiagnostic(loc, diag::candidate_partial_match, - fn->getParamListAsString(fn->getParams())); + loc = getLoc(); + + emitDiagnosticAt(loc, diag::candidate_partial_match, + fn->getParamListAsString(fn->getParams())); return true; } @@ -4044,21 +4031,21 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const { return false; if (label.empty()) { - emitDiagnostic(insertLoc, diag::missing_argument_positional, position + 1) + emitDiagnosticAt(insertLoc, diag::missing_argument_positional, position + 1) .fixItInsert(insertLoc, insertText.str()); } else if (isPropertyWrapperInitialization()) { auto *TE = cast(fnExpr); - emitDiagnostic(TE->getLoc(), diag::property_wrapper_missing_arg_init, label, - resolveType(TE->getInstanceType())->getString()); + emitDiagnosticAt(TE->getLoc(), diag::property_wrapper_missing_arg_init, + label, resolveType(TE->getInstanceType())->getString()); } else { - emitDiagnostic(insertLoc, diag::missing_argument_named, label) + emitDiagnosticAt(insertLoc, diag::missing_argument_named, label) .fixItInsert(insertLoc, insertText.str()); } if (auto selectedOverload = getCalleeOverloadChoiceIfAvailable(getLocator())) { if (auto *decl = selectedOverload->choice.getDeclOrNull()) { - emitDiagnostic(decl, diag::decl_declared_here, decl->getFullName()); + emitDiagnosticAt(decl, diag::decl_declared_here, decl->getFullName()); } } @@ -4098,8 +4085,8 @@ bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) { // needs some, produce a fixit to turn "{...}" into "{ _,_ in ...}". if (diff == 0) { auto diag = - emitDiagnostic(closure->getStartLoc(), - diag::closure_argument_list_missing, numSynthesized); + emitDiagnosticAt(closure->getStartLoc(), + diag::closure_argument_list_missing, numSynthesized); std::string fixText; // Let's provide fixits for up to 10 args. if (funcType->getNumParams() <= 10) { @@ -4131,7 +4118,7 @@ bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) { std::all_of(params->begin(), params->end(), [](ParamDecl *param) { return !param->hasName(); }); - auto diag = emitDiagnostic( + auto diag = emitDiagnosticAt( params->getStartLoc(), diag::closure_argument_list_tuple, resolveType(funcType), funcType->getNumParams(), diff, diff == 1); @@ -4186,8 +4173,7 @@ bool MissingArgumentsFailure::diagnoseInvalidTupleDestructuring() const { auto name = decl->getBaseName(); auto diagnostic = - emitDiagnostic(anchor->getLoc(), - diag::cannot_convert_single_tuple_into_multiple_arguments, + emitDiagnostic(diag::cannot_convert_single_tuple_into_multiple_arguments, decl->getDescriptiveKind(), name, name.isSpecial(), SynthesizedArgs.size(), isa(argExpr)); @@ -4199,7 +4185,7 @@ bool MissingArgumentsFailure::diagnoseInvalidTupleDestructuring() const { diagnostic.flush(); // Add a note which points to the overload choice location. - emitDiagnostic(decl, diag::decl_declared_here, decl->getFullName()); + emitDiagnosticAt(decl, diag::decl_declared_here, decl->getFullName()); return true; } @@ -4319,6 +4305,18 @@ void MissingArgumentsFailure::forFixIt( out << "<#" << resolvedType << "#>"; } +SourceLoc ClosureParamDestructuringFailure::getLoc() const { + auto *closure = cast(getAnchor()); + auto paramList = closure->getParameters(); + return paramList->getStartLoc(); +} + +SourceRange ClosureParamDestructuringFailure::getSourceRange() const { + auto *closure = cast(getAnchor()); + auto paramList = closure->getParameters(); + return paramList->getSourceRange(); +} + bool ClosureParamDestructuringFailure::diagnoseAsError() { auto *closure = cast(getAnchor()); auto params = closure->getParameters(); @@ -4328,15 +4326,13 @@ bool ClosureParamDestructuringFailure::diagnoseAsError() { // structure of parameter type itself is unclear. for (auto *param : params->getArray()) { if (param->isImplicit()) { - emitDiagnostic(params->getStartLoc(), - diag::closure_tuple_parameter_destructuring_implicit, + emitDiagnostic(diag::closure_tuple_parameter_destructuring_implicit, getParameterType()); return true; } } - auto diag = emitDiagnostic(params->getStartLoc(), - diag::closure_tuple_parameter_destructuring, + auto diag = emitDiagnostic(diag::closure_tuple_parameter_destructuring, getParameterType()); auto *closureBody = closure->getBody(); @@ -4446,7 +4442,7 @@ bool ClosureParamDestructuringFailure::diagnoseAsError() { } } - diag.fixItReplace(params->getSourceRange(), nameOS.str()) + diag.fixItReplace(getSourceRange(), nameOS.str()) .fixItInsert(bodyLoc, OS.str()); return true; } @@ -4519,20 +4515,22 @@ bool OutOfOrderArgumentFailure::diagnoseAsError() { // There are 4 diagnostic messages variations depending on // labeled/unlabeled arguments. if (first.empty() && second.empty()) { - addFixIts(emitDiagnostic(diagLoc, - isa(anchor) - ? diag::argument_out_of_order_binary_op - : diag::argument_out_of_order_unnamed_unnamed, - ArgIdx + 1, PrevArgIdx + 1)); + addFixIts(emitDiagnosticAt( + diagLoc, + isa(anchor) ? diag::argument_out_of_order_binary_op + : diag::argument_out_of_order_unnamed_unnamed, + ArgIdx + 1, PrevArgIdx + 1)); } else if (first.empty() && !second.empty()) { - addFixIts(emitDiagnostic(diagLoc, diag::argument_out_of_order_unnamed_named, - ArgIdx + 1, second)); + addFixIts(emitDiagnosticAt(diagLoc, + diag::argument_out_of_order_unnamed_named, + ArgIdx + 1, second)); } else if (!first.empty() && second.empty()) { - addFixIts(emitDiagnostic(diagLoc, diag::argument_out_of_order_named_unnamed, - first, PrevArgIdx + 1)); + addFixIts(emitDiagnosticAt(diagLoc, + diag::argument_out_of_order_named_unnamed, first, + PrevArgIdx + 1)); } else { - addFixIts(emitDiagnostic(diagLoc, diag::argument_out_of_order_named_named, - first, second)); + addFixIts(emitDiagnosticAt(diagLoc, diag::argument_out_of_order_named_named, + first, second)); } return true; } @@ -4545,7 +4543,7 @@ bool ExtraneousArgumentsFailure::diagnoseAsError() { auto fnType = ContextualType; auto params = closure->getParameters(); - auto diag = emitDiagnostic( + auto diag = emitDiagnosticAt( params->getStartLoc(), diag::closure_argument_list_tuple, fnType, fnType->getNumParams(), params->size(), (params->size() == 1)); @@ -4568,8 +4566,7 @@ bool ExtraneousArgumentsFailure::diagnoseAsError() { if (isContextualMismatch()) { auto *locator = getLocator(); - emitDiagnostic(anchor->getLoc(), - locator->isLastElement() + emitDiagnostic(locator->isLastElement() ? diag::cannot_convert_initializer_value : diag::cannot_convert_argument_value, getType(anchor), ContextualType); @@ -4582,7 +4579,7 @@ bool ExtraneousArgumentsFailure::diagnoseAsError() { if (ContextualType->getNumParams() == 0) { if (auto argExpr = getArgumentListExprFor(getLocator())) { - emitDiagnostic(anchor->getLoc(), diag::extra_argument_to_nullary_call) + emitDiagnostic(diag::extra_argument_to_nullary_call) .highlight(argExpr->getSourceRange()) .fixItRemove(argExpr->getSourceRange()); return true; @@ -4602,11 +4599,11 @@ bool ExtraneousArgumentsFailure::diagnoseAsError() { }, [&] { OS << ", "; }); - emitDiagnostic(anchor->getLoc(), diag::extra_arguments_in_call, OS.str()); + emitDiagnostic(diag::extra_arguments_in_call, OS.str()); if (auto overload = getCalleeOverloadChoiceIfAvailable(getLocator())) { if (auto *decl = overload->choice.getDeclOrNull()) { - emitDiagnostic(decl, diag::decl_declared_here, decl->getFullName()); + emitDiagnosticAt(decl, diag::decl_declared_here, decl->getFullName()); } } @@ -4621,9 +4618,9 @@ bool ExtraneousArgumentsFailure::diagnoseAsNote() { auto *decl = overload->choice.getDecl(); auto *anchor = getAnchor(); auto numArgs = getTotalNumArguments(); - emitDiagnostic(decl, diag::candidate_with_extraneous_args, ContextualType, - ContextualType->getNumParams(), numArgs, (numArgs == 1), - isa(anchor)); + emitDiagnosticAt(decl, diag::candidate_with_extraneous_args, ContextualType, + ContextualType->getNumParams(), numArgs, (numArgs == 1), + isa(anchor)); return true; } @@ -4636,7 +4633,7 @@ bool ExtraneousArgumentsFailure::diagnoseSingleExtraArgument() const { if (auto *call = dyn_cast(getRawAnchor())) { auto *TE = dyn_cast(call->getFn()); if (TE && getType(TE)->getMetatypeInstanceType()->isVoid()) { - emitDiagnostic(call->getLoc(), diag::extra_argument_to_nullary_call) + emitDiagnosticAt(call->getLoc(), diag::extra_argument_to_nullary_call) .highlight(call->getArg()->getSourceRange()); return true; } @@ -4657,7 +4654,7 @@ bool ExtraneousArgumentsFailure::diagnoseSingleExtraArgument() const { auto loc = argExpr->getLoc(); if (tuple && index == tuple->getNumElements() - 1 && tuple->hasTrailingClosure()) { - emitDiagnostic(loc, diag::extra_trailing_closure_in_call) + emitDiagnosticAt(loc, diag::extra_trailing_closure_in_call) .highlight(argExpr->getSourceRange()); } else if (ContextualType->getNumParams() == 0) { auto *PE = dyn_cast(arguments); @@ -4666,17 +4663,17 @@ bool ExtraneousArgumentsFailure::diagnoseSingleExtraArgument() const { subExpr = PE->getSubExpr(); if (subExpr && argument.getPlainType()->isVoid()) { - emitDiagnostic(loc, diag::extra_argument_to_nullary_call) + emitDiagnosticAt(loc, diag::extra_argument_to_nullary_call) .fixItRemove(subExpr->getSourceRange()); } else { - emitDiagnostic(loc, diag::extra_argument_to_nullary_call) + emitDiagnosticAt(loc, diag::extra_argument_to_nullary_call) .highlight(argExpr->getSourceRange()); } } else if (argument.hasLabel()) { - emitDiagnostic(loc, diag::extra_argument_named, argument.getLabel()) + emitDiagnosticAt(loc, diag::extra_argument_named, argument.getLabel()) .highlight(argExpr->getSourceRange()); } else { - emitDiagnostic(loc, diag::extra_argument_positional) + emitDiagnosticAt(loc, diag::extra_argument_positional) .highlight(argExpr->getSourceRange()); } return true; @@ -4721,49 +4718,58 @@ bool InaccessibleMemberFailure::diagnoseAsError() { auto loc = nameLoc.isValid() ? nameLoc.getStartLoc() : anchor->getLoc(); auto accessLevel = Member->getFormalAccessScope().accessLevelForDiagnostics(); if (auto *CD = dyn_cast(Member)) { - emitDiagnostic(loc, diag::init_candidate_inaccessible, - CD->getResultInterfaceType(), accessLevel) + emitDiagnosticAt(loc, diag::init_candidate_inaccessible, + CD->getResultInterfaceType(), accessLevel) .highlight(nameLoc.getSourceRange()); } else { - emitDiagnostic(loc, diag::candidate_inaccessible, Member->getBaseName(), - accessLevel) + emitDiagnosticAt(loc, diag::candidate_inaccessible, Member->getBaseName(), + accessLevel) .highlight(nameLoc.getSourceRange()); } - emitDiagnostic(Member, diag::decl_declared_here, Member->getFullName()); + emitDiagnosticAt(Member, diag::decl_declared_here, Member->getFullName()); return true; } -bool AnyObjectKeyPathRootFailure::diagnoseAsError() { - // Diagnose use of AnyObject as root for a keypath +SourceLoc AnyObjectKeyPathRootFailure::getLoc() const { + if (auto KPE = dyn_cast(getAnchor())) { + if (auto rootTyRepr = KPE->getRootType()) + return rootTyRepr->getLoc(); + } - auto anchor = getAnchor(); - auto loc = anchor->getLoc(); - auto range = anchor->getSourceRange(); + return FailureDiagnostic::getLoc(); +} - if (auto KPE = dyn_cast(anchor)) { - if (auto rootTyRepr = KPE->getRootType()) { - loc = rootTyRepr->getLoc(); - range = rootTyRepr->getSourceRange(); - } +SourceRange AnyObjectKeyPathRootFailure::getSourceRange() const { + if (auto KPE = dyn_cast(getAnchor())) { + if (auto rootTyRepr = KPE->getRootType()) + return rootTyRepr->getSourceRange(); } - emitDiagnostic(loc, diag::expr_swift_keypath_anyobject_root).highlight(range); + return FailureDiagnostic::getSourceRange(); +} + +bool AnyObjectKeyPathRootFailure::diagnoseAsError() { + // Diagnose use of AnyObject as root for a keypath + emitDiagnostic(diag::expr_swift_keypath_anyobject_root) + .highlight(getSourceRange()); return true; } -bool KeyPathSubscriptIndexHashableFailure::diagnoseAsError() { - auto *anchor = getRawAnchor(); +SourceLoc KeyPathSubscriptIndexHashableFailure::getLoc() const { auto *locator = getLocator(); - auto loc = anchor->getLoc(); if (locator->isKeyPathSubscriptComponent()) { - auto *KPE = cast(anchor); + auto *KPE = cast(getAnchor()); if (auto kpElt = locator->findFirst()) - loc = KPE->getComponents()[kpElt->getIndex()].getLoc(); + return KPE->getComponents()[kpElt->getIndex()].getLoc(); } - emitDiagnostic(loc, diag::expr_keypath_subscript_index_not_hashable, + return FailureDiagnostic::getLoc(); +} + +bool KeyPathSubscriptIndexHashableFailure::diagnoseAsError() { + emitDiagnostic(diag::expr_keypath_subscript_index_not_hashable, resolveType(NonConformingType)); return true; } @@ -4782,20 +4788,20 @@ SourceLoc InvalidMemberRefInKeyPath::getLoc() const { } bool InvalidStaticMemberRefInKeyPath::diagnoseAsError() { - emitDiagnostic(getLoc(), diag::expr_keypath_static_member, getName(), + emitDiagnostic(diag::expr_keypath_static_member, getName(), isForKeyPathDynamicMemberLookup()); return true; } bool InvalidMemberWithMutatingGetterInKeyPath::diagnoseAsError() { - emitDiagnostic(getLoc(), diag::expr_keypath_mutating_getter, getName(), + emitDiagnostic(diag::expr_keypath_mutating_getter, getName(), isForKeyPathDynamicMemberLookup()); return true; } bool InvalidMethodRefInKeyPath::diagnoseAsError() { - emitDiagnostic(getLoc(), diag::expr_keypath_not_property, getKind(), - getName(), isForKeyPathDynamicMemberLookup()); + emitDiagnostic(diag::expr_keypath_not_property, getKind(), getName(), + isForKeyPathDynamicMemberLookup()); return true; } @@ -4811,21 +4817,19 @@ SourceLoc InvalidUseOfAddressOf::getLoc() const { bool InvalidUseOfAddressOf::diagnoseAsError() { if (auto argApplyInfo = getFunctionArgApplyInfo(getLocator())) { if (!argApplyInfo->getParameterFlags().isInOut()) { - auto anchor = getAnchor(); - emitDiagnostic(anchor->getLoc(), diag::extra_address_of, getToType()) - .highlight(anchor->getSourceRange()) - .fixItRemove(anchor->getStartLoc()); + emitDiagnostic(diag::extra_address_of, getToType()) + .highlight(getSourceRange()) + .fixItRemove(getSourceRange().Start); return true; } } - emitDiagnostic(getLoc(), diag::extraneous_address_of); + emitDiagnostic(diag::extraneous_address_of); return true; } bool ExtraneousReturnFailure::diagnoseAsError() { - auto *anchor = getAnchor(); - emitDiagnostic(anchor->getLoc(), diag::cannot_return_value_from_void_func); + emitDiagnostic(diag::cannot_return_value_from_void_func); if (auto FD = dyn_cast(getDC())) { // We only want to emit the note + fix-it if the function does not // have an explicit return type. The reason we also need to check @@ -4838,7 +4842,7 @@ bool ExtraneousReturnFailure::diagnoseAsError() { !FD->getBaseIdentifier().empty()) { auto fixItLoc = Lexer::getLocForEndOfToken( getASTContext().SourceMgr, FD->getParameters()->getEndLoc()); - emitDiagnostic(anchor->getLoc(), diag::add_return_type_note) + emitDiagnostic(diag::add_return_type_note) .fixItInsert(fixItLoc, " -> <#Return Type#>"); } } @@ -4847,7 +4851,6 @@ bool ExtraneousReturnFailure::diagnoseAsError() { } bool CollectionElementContextualFailure::diagnoseAsError() { - auto *anchor = getAnchor(); auto *locator = getLocator(); auto eltType = getFromType(); @@ -4855,8 +4858,7 @@ bool CollectionElementContextualFailure::diagnoseAsError() { Optional diagnostic; if (isa(getRawAnchor())) { - diagnostic.emplace(emitDiagnostic(anchor->getLoc(), - diag::cannot_convert_array_element, + diagnostic.emplace(emitDiagnostic(diag::cannot_convert_array_element, eltType, contextualType)); } @@ -4864,14 +4866,12 @@ bool CollectionElementContextualFailure::diagnoseAsError() { auto eltLoc = locator->castLastElementTo(); switch (eltLoc.getIndex()) { case 0: // key - diagnostic.emplace(emitDiagnostic(anchor->getLoc(), - diag::cannot_convert_dict_key, eltType, + diagnostic.emplace(emitDiagnostic(diag::cannot_convert_dict_key, eltType, contextualType)); break; case 1: // value - diagnostic.emplace(emitDiagnostic(anchor->getLoc(), - diag::cannot_convert_dict_value, + diagnostic.emplace(emitDiagnostic(diag::cannot_convert_dict_value, eltType, contextualType)); break; @@ -4885,19 +4885,17 @@ bool CollectionElementContextualFailure::diagnoseAsError() { // If this is a conversion failure related to binding of `for-each` // statement it has to be diagnosed as pattern match if there are // holes present in the contextual type. - if (cs.getContextualTypePurpose(anchor) == + if (cs.getContextualTypePurpose(getAnchor()) == ContextualTypePurpose::CTP_ForEachStmt && contextualType->hasHole()) { diagnostic.emplace(emitDiagnostic( - anchor->getLoc(), (contextualType->is() && !eltType->is()) ? diag::cannot_match_expr_tuple_pattern_with_nontuple_value : diag::cannot_match_unresolved_expr_pattern_with_value, eltType)); } else { diagnostic.emplace( - emitDiagnostic(anchor->getLoc(), - contextualType->isExistentialType() + emitDiagnostic(contextualType->isExistentialType() ? diag::cannot_convert_sequence_element_protocol : diag::cannot_convert_sequence_element_value, eltType, contextualType)); @@ -4947,14 +4945,14 @@ bool MissingContextualConformanceFailure::diagnoseAsError() { auto srcType = getFromType(); auto dstType = getToType(); - emitDiagnostic(anchor->getLoc(), *diagnostic, srcType, dstType); + emitDiagnostic(*diagnostic, srcType, dstType); if (isa(anchor)) return true; if (srcType->isAny() && dstType->isAnyObject()) { - emitDiagnostic(anchor->getLoc(), diag::any_as_anyobject_fixit) - .fixItInsertAfter(anchor->getEndLoc(), " as AnyObject"); + emitDiagnostic(diag::any_as_anyobject_fixit) + .fixItInsertAfter(getSourceRange().End, " as AnyObject"); } return true; @@ -4996,18 +4994,18 @@ bool MissingGenericArgumentsFailure::diagnoseForAnchor( return true; if (auto *SD = dyn_cast(DC)) { - emitDiagnostic(SD, diag::note_call_to_subscript, SD->getFullName()); + emitDiagnosticAt(SD, diag::note_call_to_subscript, SD->getFullName()); return true; } if (auto *AFD = dyn_cast(DC)) { if (isa(AFD)) { - emitDiagnostic(AFD, diag::note_call_to_initializer); + emitDiagnosticAt(AFD, diag::note_call_to_initializer); } else { - emitDiagnostic(AFD, - AFD->isOperator() ? diag::note_call_to_operator - : diag::note_call_to_func, - AFD->getFullName()); + emitDiagnosticAt(AFD, + AFD->isOperator() ? diag::note_call_to_operator + : diag::note_call_to_func, + AFD->getFullName()); } return true; } @@ -5038,10 +5036,10 @@ bool MissingGenericArgumentsFailure::diagnoseParameter( if (auto *CE = dyn_cast(getRawAnchor())) { auto castTo = getType(CE->getCastTypeLoc()); auto *NTD = castTo->getAnyNominal(); - emitDiagnostic(loc, diag::unbound_generic_parameter_cast, GP, - NTD ? NTD->getDeclaredType() : castTo); + emitDiagnosticAt(loc, diag::unbound_generic_parameter_cast, GP, + NTD ? NTD->getDeclaredType() : castTo); } else { - emitDiagnostic(loc, diag::unbound_generic_parameter, GP); + emitDiagnosticAt(loc, diag::unbound_generic_parameter, GP); } Type baseTyForNote; @@ -5061,8 +5059,8 @@ bool MissingGenericArgumentsFailure::diagnoseParameter( return true; } - emitDiagnostic(GP->getDecl(), diag::archetype_declared_in_type, GP, - baseTyForNote); + emitDiagnosticAt(GP->getDecl(), diag::archetype_declared_in_type, GP, + baseTyForNote); return true; } @@ -5114,7 +5112,7 @@ void MissingGenericArgumentsFailure::emitGenericSignatureNote( auto baseType = anchor.get(); if (TypeChecker::getDefaultGenericArgumentsString(paramsAsString, GTD, getPreferredType)) { - auto diagnostic = emitDiagnostic( + auto diagnostic = emitDiagnosticAt( baseType->getLoc(), diag::unbound_generic_parameter_explicit_fix); if (auto *genericTy = dyn_cast(baseType)) { @@ -5199,17 +5197,21 @@ bool MissingGenericArgumentsFailure::findArgumentLocations( return associator.allParamsAssigned(); } +SourceLoc SkipUnhandledConstructInFunctionBuilderFailure::getLoc() const { + if (auto stmt = unhandled.dyn_cast()) + return stmt->getStartLoc(); + + return unhandled.get()->getLoc(); +} + void SkipUnhandledConstructInFunctionBuilderFailure::diagnosePrimary( bool asNote) { - if (auto stmt = unhandled.dyn_cast()) { - emitDiagnostic(stmt->getStartLoc(), - asNote? diag::note_function_builder_control_flow - : diag::function_builder_control_flow, + if (unhandled.is()) { + emitDiagnostic(asNote ? diag::note_function_builder_control_flow + : diag::function_builder_control_flow, builder->getFullName()); } else { - auto decl = unhandled.get(); - emitDiagnostic(decl, - asNote ? diag::note_function_builder_decl + emitDiagnostic(asNote ? diag::note_function_builder_decl : diag::function_builder_decl, builder->getFullName()); } @@ -5217,10 +5219,8 @@ void SkipUnhandledConstructInFunctionBuilderFailure::diagnosePrimary( bool SkipUnhandledConstructInFunctionBuilderFailure::diagnoseAsError() { diagnosePrimary(/*asNote=*/false); - emitDiagnostic(builder, - diag::kind_declname_declared_here, - builder->getDescriptiveKind(), - builder->getFullName()); + emitDiagnosticAt(builder, diag::kind_declname_declared_here, + builder->getDescriptiveKind(), builder->getFullName()); return true; } @@ -5297,13 +5297,12 @@ bool InvalidTupleSplatWithSingleParameterFailure::diagnoseAsError() { auto diagnostic = name.isSpecial() - ? emitDiagnostic(argExpr->getLoc(), - diag::single_tuple_parameter_mismatch_special, - choice->getDescriptiveKind(), paramTy, subsStr) - : emitDiagnostic(argExpr->getLoc(), - diag::single_tuple_parameter_mismatch_normal, - choice->getDescriptiveKind(), name, paramTy, subsStr); - + ? emitDiagnosticAt(argExpr->getLoc(), + diag::single_tuple_parameter_mismatch_special, + choice->getDescriptiveKind(), paramTy, subsStr) + : emitDiagnosticAt( + argExpr->getLoc(), diag::single_tuple_parameter_mismatch_normal, + choice->getDescriptiveKind(), name, paramTy, subsStr); auto newLeftParenLoc = argExpr->getStartLoc(); if (auto *TE = dyn_cast(argExpr)) { @@ -5333,9 +5332,8 @@ bool InvalidTupleSplatWithSingleParameterFailure::diagnoseAsError() { } bool ThrowingFunctionConversionFailure::diagnoseAsError() { - auto *anchor = getAnchor(); - emitDiagnostic(anchor->getLoc(), diag::throws_functiontype_mismatch, - getFromType(), getToType()); + emitDiagnostic(diag::throws_functiontype_mismatch, getFromType(), + getToType()); return true; } @@ -5347,8 +5345,8 @@ bool InOutConversionFailure::diagnoseAsError() { if (!path.empty() && path.back().getKind() == ConstraintLocator::FunctionArgument) { if (auto argApplyInfo = getFunctionArgApplyInfo(locator)) { - emitDiagnostic(anchor->getLoc(), diag::cannot_convert_argument_value, - argApplyInfo->getArgType(), argApplyInfo->getParamType()); + emitDiagnostic(diag::cannot_convert_argument_value, + argApplyInfo->getArgType(), argApplyInfo->getParamType()); } else { assert(locator->findLast()); auto contextualType = getContextualType(anchor); @@ -5358,15 +5356,14 @@ bool InOutConversionFailure::diagnoseAsError() { if (!diagnostic) return false; - emitDiagnostic(anchor->getLoc(), *diagnostic, getType(anchor), - contextualType); + emitDiagnostic(*diagnostic, getType(anchor), contextualType); } return true; } - emitDiagnostic(anchor->getLoc(), diag::cannot_pass_rvalue_inout_converted, - getFromType(), getToType()); + emitDiagnostic(diag::cannot_pass_rvalue_inout_converted, getFromType(), + getToType()); fixItChangeArgumentType(); return true; } @@ -5434,8 +5431,8 @@ void InOutConversionFailure::fixItChangeArgumentType() const { if (!startLoc.isValid()) startLoc = endLoc; - emitDiagnostic(VD->getLoc(), diag::inout_change_var_type_if_possible, - actualType, neededType) + emitDiagnosticAt(VD, diag::inout_change_var_type_if_possible, actualType, + neededType) .fixItReplaceChars(startLoc, endLoc, scratch); } @@ -5462,8 +5459,8 @@ bool ArgumentMismatchFailure::diagnoseAsError() { auto paramType = getToType(); if (paramType->isAnyObject()) { - emitDiagnostic(getLoc(), diag::cannot_convert_argument_value_anyobject, - argType, paramType); + emitDiagnostic(diag::cannot_convert_argument_value_anyobject, argType, + paramType); return true; } @@ -5474,7 +5471,7 @@ bool ArgumentMismatchFailure::diagnoseAsError() { if (paramType->isExistentialType()) diagnostic = diag::cannot_convert_argument_value_protocol; - auto diag = emitDiagnostic(getLoc(), diagnostic, argType, paramType); + auto diag = emitDiagnostic(diagnostic, argType, paramType); // If argument is an l-value type and parameter is a pointer type, // let's match up its element type to the argument to see whether @@ -5495,9 +5492,10 @@ bool ArgumentMismatchFailure::diagnoseAsError() { bool ArgumentMismatchFailure::diagnoseAsNote() { auto *locator = getLocator(); if (auto *callee = getCallee()) { - emitDiagnostic(callee, diag::candidate_has_invalid_argument_at_position, - getToType(), getParamPosition(), - locator->isLastElement()); + emitDiagnosticAt( + callee, diag::candidate_has_invalid_argument_at_position, getToType(), + getParamPosition(), + locator->isLastElement()); return true; } @@ -5546,13 +5544,13 @@ bool ArgumentMismatchFailure::diagnoseUseOfReferenceEqualityOperator() const { // reference semantics rather than value semantics. The fixit will // lop off the extra '=' in the operator. if (nonNilType->getOptionalObjectType()) { - emitDiagnostic(loc, - diag::value_type_comparison_with_nil_illegal_did_you_mean, - nonNilType) + emitDiagnosticAt( + loc, diag::value_type_comparison_with_nil_illegal_did_you_mean, + nonNilType) .fixItReplace(loc, revisedName); } else { - emitDiagnostic(loc, diag::value_type_comparison_with_nil_illegal, - nonNilType) + emitDiagnosticAt(loc, diag::value_type_comparison_with_nil_illegal, + nonNilType) .highlight(nonNilExpr->getSourceRange()); } @@ -5560,8 +5558,8 @@ bool ArgumentMismatchFailure::diagnoseUseOfReferenceEqualityOperator() const { } if (lhsType->is() || rhsType->is()) { - emitDiagnostic(binaryOp->getLoc(), diag::cannot_reference_compare_types, - name.str(), lhsType, rhsType) + emitDiagnosticAt(binaryOp->getLoc(), diag::cannot_reference_compare_types, + name.str(), lhsType, rhsType) .highlight(lhs->getSourceRange()) .highlight(rhs->getSourceRange()); return true; @@ -5584,10 +5582,9 @@ bool ArgumentMismatchFailure::diagnosePatternMatchingMismatch() const { auto diagnostic = lhsType->is() ? emitDiagnostic( - getLoc(), diag::cannot_match_unresolved_expr_pattern_with_value, - rhsType) - : emitDiagnostic(getLoc(), diag::cannot_match_expr_pattern_with_value, - lhsType, rhsType); + diag::cannot_match_unresolved_expr_pattern_with_value, rhsType) + : emitDiagnostic(diag::cannot_match_expr_pattern_with_value, lhsType, + rhsType); diagnostic.highlight(lhsExpr->getSourceRange()); diagnostic.highlight(rhsExpr->getSourceRange()); @@ -5631,15 +5628,15 @@ bool ArgumentMismatchFailure::diagnoseArchetypeMismatch() const { if (!(paramDecl && argDecl)) return false; - emitDiagnostic( - getAnchor()->getLoc(), diag::cannot_convert_argument_value_generic, argTy, - describeGenericType(argDecl), paramTy, describeGenericType(paramDecl)); + emitDiagnostic(diag::cannot_convert_argument_value_generic, argTy, + describeGenericType(argDecl), paramTy, + describeGenericType(paramDecl)); - emitDiagnostic(argDecl, diag::descriptive_generic_type_declared_here, - describeGenericType(argDecl, true)); + emitDiagnosticAt(argDecl, diag::descriptive_generic_type_declared_here, + describeGenericType(argDecl, true)); - emitDiagnostic(paramDecl, diag::descriptive_generic_type_declared_here, - describeGenericType(paramDecl, true)); + emitDiagnosticAt(paramDecl, diag::descriptive_generic_type_declared_here, + describeGenericType(paramDecl, true)); return true; } @@ -5685,8 +5682,7 @@ bool ArgumentMismatchFailure::diagnosePropertyWrapperMismatch() const { argType->is()) return true; - emitDiagnostic(getLoc(), diag::cannot_convert_initializer_value, argType, - paramType); + emitDiagnostic(diag::cannot_convert_initializer_value, argType, paramType); return true; } @@ -5695,8 +5691,8 @@ void ExpandArrayIntoVarargsFailure::tryDropArrayBracketsFixIt( // If this is an array literal, offer to remove the brackets and pass the // elements directly as variadic arguments. if (auto *arrayExpr = dyn_cast(anchor)) { - auto diag = emitDiagnostic(arrayExpr->getLoc(), - diag::suggest_pass_elements_directly); + auto diag = emitDiagnosticAt(arrayExpr->getLoc(), + diag::suggest_pass_elements_directly); diag.fixItRemove(arrayExpr->getLBracketLoc()) .fixItRemove(arrayExpr->getRBracketLoc()); // Handle the case where the array literal has a trailing comma. @@ -5707,8 +5703,8 @@ void ExpandArrayIntoVarargsFailure::tryDropArrayBracketsFixIt( bool ExpandArrayIntoVarargsFailure::diagnoseAsError() { if (auto anchor = getAnchor()) { - emitDiagnostic(anchor->getLoc(), diag::cannot_convert_array_to_variadic, - getFromType(), getToType()); + emitDiagnostic(diag::cannot_convert_array_to_variadic, getFromType(), + getToType()); tryDropArrayBracketsFixIt(anchor); // TODO: Array splat fix-it once that's supported. return true; @@ -5723,8 +5719,8 @@ bool ExpandArrayIntoVarargsFailure::diagnoseAsNote() { return false; if (auto chosenDecl = overload->choice.getDeclOrNull()) { - emitDiagnostic(chosenDecl, diag::candidate_would_match_array_to_variadic, - getToType()); + emitDiagnosticAt(chosenDecl, diag::candidate_would_match_array_to_variadic, + getToType()); tryDropArrayBracketsFixIt(anchor); return true; } @@ -5754,9 +5750,9 @@ bool ExtraneousCallFailure::diagnoseAsError() { if (auto overload = getCalleeOverloadChoiceIfAvailable(locator)) { if (auto *decl = overload->choice.getDeclOrNull()) { if (auto *enumCase = dyn_cast(decl)) { - auto diagnostic = emitDiagnostic( - anchor->getLoc(), diag::unexpected_arguments_in_enum_case, - enumCase->getBaseIdentifier()); + auto diagnostic = + emitDiagnostic(diag::unexpected_arguments_in_enum_case, + enumCase->getBaseIdentifier()); removeParensFixIt(diagnostic); return true; } @@ -5768,7 +5764,7 @@ bool ExtraneousCallFailure::diagnoseAsError() { auto *call = cast(getRawAnchor()); if (getType(baseExpr)->isAnyObject()) { - emitDiagnostic(anchor->getLoc(), diag::cannot_call_with_params, + emitDiagnostic(diag::cannot_call_with_params, UDE->getName().getBaseName().userFacingName(), getType(call->getArg())->getString(), isa(baseExpr)); @@ -5776,22 +5772,19 @@ bool ExtraneousCallFailure::diagnoseAsError() { } } - auto diagnostic = emitDiagnostic( - anchor->getLoc(), diag::cannot_call_non_function_value, getType(anchor)); + auto diagnostic = + emitDiagnostic(diag::cannot_call_non_function_value, getType(anchor)); removeParensFixIt(diagnostic); return true; } bool InvalidUseOfTrailingClosure::diagnoseAsError() { - auto *anchor = getAnchor(); - - emitDiagnostic(anchor->getLoc(), diag::trailing_closure_bad_param, - getToType()) - .highlight(anchor->getSourceRange()); + emitDiagnostic(diag::trailing_closure_bad_param, getToType()) + .highlight(getSourceRange()); if (auto overload = getCalleeOverloadChoiceIfAvailable(getLocator())) { if (auto *decl = overload->choice.getDeclOrNull()) { - emitDiagnostic(decl, diag::decl_declared_here, decl->getFullName()); + emitDiagnosticAt(decl, diag::decl_declared_here, decl->getFullName()); } } @@ -5836,9 +5829,9 @@ void NonEphemeralConversionFailure::emitSuggestionNotes() const { // First emit a note about the implicit conversion only lasting for the // duration of the call. auto *argExpr = getArgExpr(); - emitDiagnostic(argExpr->getLoc(), - diag::ephemeral_pointer_argument_conversion_note, - getArgType(), getParamType(), getCallee(), getCalleeFullName()) + emitDiagnosticAt( + argExpr->getLoc(), diag::ephemeral_pointer_argument_conversion_note, + getArgType(), getParamType(), getCallee(), getCalleeFullName()) .highlight(argExpr->getSourceRange()); // Then try to find a suitable alternative. @@ -5851,9 +5844,9 @@ void NonEphemeralConversionFailure::emitSuggestionNotes() const { // We can suggest using withUnsafe[Mutable][Bytes/BufferPointer]. if (auto alternative = getAlternativeKind()) - emitDiagnostic(argExpr->getLoc(), - diag::ephemeral_use_array_with_unsafe_buffer, - *alternative); + emitDiagnosticAt(argExpr->getLoc(), + diag::ephemeral_use_array_with_unsafe_buffer, + *alternative); break; } case ConversionRestrictionKind::StringToPointer: { @@ -5867,8 +5860,8 @@ void NonEphemeralConversionFailure::emitSuggestionNotes() const { switch (getPointerKind(getParamType())) { case PTK_UnsafePointer: case PTK_UnsafeRawPointer: - emitDiagnostic(argExpr->getLoc(), - diag::ephemeral_use_string_with_c_string); + emitDiagnosticAt(argExpr->getLoc(), + diag::ephemeral_use_string_with_c_string); break; case PTK_UnsafeMutableRawPointer: case PTK_UnsafeMutablePointer: @@ -5882,8 +5875,8 @@ void NonEphemeralConversionFailure::emitSuggestionNotes() const { // For an arbitrary inout-to-pointer, we can suggest // withUnsafe[Mutable][Bytes/Pointer]. if (auto alternative = getAlternativeKind()) - emitDiagnostic(argExpr->getLoc(), diag::ephemeral_use_with_unsafe_pointer, - *alternative); + emitDiagnosticAt(argExpr->getLoc(), + diag::ephemeral_use_with_unsafe_pointer, *alternative); break; case ConversionRestrictionKind::DeepEquality: case ConversionRestrictionKind::Superclass: @@ -5944,7 +5937,7 @@ bool NonEphemeralConversionFailure::diagnosePointerInit() const { : diag::cannot_construct_dangling_pointer; auto *anchor = getRawAnchor(); - emitDiagnostic(anchor->getLoc(), diagID, constructedTy, constructorKind) + emitDiagnosticAt(anchor->getLoc(), diagID, constructedTy, constructorKind) .highlight(anchor->getSourceRange()); emitSuggestionNotes(); @@ -5954,8 +5947,8 @@ bool NonEphemeralConversionFailure::diagnosePointerInit() const { bool NonEphemeralConversionFailure::diagnoseAsNote() { // We can only emit a useful note if we have a callee. if (auto *callee = getCallee()) { - emitDiagnostic(callee, diag::candidate_performs_illegal_ephemeral_conv, - getParamPosition()); + emitDiagnosticAt(callee, diag::candidate_performs_illegal_ephemeral_conv, + getParamPosition()); return true; } return false; @@ -5978,16 +5971,16 @@ bool NonEphemeralConversionFailure::diagnoseAsError() { ? diag::cannot_use_inout_non_ephemeral_warning : diag::cannot_use_inout_non_ephemeral; - emitDiagnostic(argExpr->getLoc(), diagID, argDesc, getCallee(), - getCalleeFullName()) + emitDiagnosticAt(argExpr->getLoc(), diagID, argDesc, getCallee(), + getCalleeFullName()) .highlight(argExpr->getSourceRange()); } else { auto diagID = DowngradeToWarning ? diag::cannot_pass_type_to_non_ephemeral_warning : diag::cannot_pass_type_to_non_ephemeral; - emitDiagnostic(argExpr->getLoc(), diagID, getArgType(), argDesc, - getCallee(), getCalleeFullName()) + emitDiagnosticAt(argExpr->getLoc(), diagID, getArgType(), argDesc, + getCallee(), getCalleeFullName()) .highlight(argExpr->getSourceRange()); } emitSuggestionNotes(); @@ -6027,9 +6020,7 @@ bool AssignmentTypeMismatchFailure::diagnoseMissingConformance() const { if (dstMembers.size() == 1) dstType = (*dstMembers.begin())->getDeclaredType(); - auto *anchor = getAnchor(); - emitDiagnostic(anchor->getLoc(), diag::cannot_convert_assign_protocol, - srcType, dstType); + emitDiagnostic(diag::cannot_convert_assign_protocol, srcType, dstType); return true; } @@ -6046,9 +6037,9 @@ bool AssignmentTypeMismatchFailure::diagnoseAsNote() { if (auto overload = getCalleeOverloadChoiceIfAvailable(getConstraintLocator(anchor))) { if (auto *decl = overload->choice.getDeclOrNull()) { - emitDiagnostic(decl, - diag::cannot_convert_candidate_result_to_contextual_type, - decl->getFullName(), getFromType(), getToType()); + emitDiagnosticAt(decl, + diag::cannot_convert_candidate_result_to_contextual_type, + decl->getFullName(), getFromType(), getToType()); return true; } } @@ -6073,18 +6064,15 @@ bool MissingContextualBaseInMemberRefFailure::diagnoseAsError() { ? diag::cannot_infer_base_of_unresolved_member : diag::unresolved_member_no_inference; - emitDiagnostic(anchor->getLoc(), diagnostic, MemberName) - .highlight(anchor->getSourceRange()); + emitDiagnostic(diagnostic, MemberName).highlight(getSourceRange()); return true; } bool UnableToInferClosureReturnType::diagnoseAsError() { auto *closure = cast(getRawAnchor()); - auto diagnostic = - emitDiagnostic(closure->getLoc(), - diag::cannot_infer_closure_result_type, - closure->hasSingleExpressionBody()); + auto diagnostic = emitDiagnostic(diag::cannot_infer_closure_result_type, + closure->hasSingleExpressionBody()); // If there is a location for an 'in' token, then the argument list was // specified somehow but no return type was. Insert a "-> ReturnType " @@ -6137,10 +6125,14 @@ getImportModuleAndDefaultType(const ASTContext &ctx, ObjectLiteralExpr *expr) { return std::make_pair("", ""); } +SourceLoc UnableToInferProtocolLiteralType::getLoc() const { + return getRawAnchor()->getLoc(); +} + bool UnableToInferProtocolLiteralType::diagnoseAsError() { auto &cs = getConstraintSystem(); auto &ctx = cs.getASTContext(); - auto *expr = cast(getLocator()->getAnchor()); + auto *expr = cast(getRawAnchor()); StringRef importModule; StringRef importDefaultTypeName; @@ -6148,11 +6140,10 @@ bool UnableToInferProtocolLiteralType::diagnoseAsError() { getImportModuleAndDefaultType(ctx, expr); auto plainName = expr->getLiteralKindPlainName(); - emitDiagnostic(expr->getLoc(), diag::object_literal_default_type_missing, - plainName); + emitDiagnostic(diag::object_literal_default_type_missing, plainName); if (!importModule.empty()) { - emitDiagnostic(expr->getLoc(), diag::object_literal_resolve_import, - importModule, importDefaultTypeName, plainName); + emitDiagnostic(diag::object_literal_resolve_import, importModule, + importDefaultTypeName, plainName); } return true; @@ -6177,33 +6168,30 @@ bool MissingQuialifierInMemberRefFailure::diagnoseAsError() { auto *DC = choice->getDeclContext(); if (!(DC->isModuleContext() || DC->isModuleScopeContext())) { - emitDiagnostic(UDE->getLoc(), diag::member_shadows_function, UDE->getName(), - methodKind, choice->getDescriptiveKind(), - choice->getFullName()); + emitDiagnostic(diag::member_shadows_function, UDE->getName(), methodKind, + choice->getDescriptiveKind(), choice->getFullName()); return true; } auto qualifier = DC->getParentModule()->getName(); - emitDiagnostic(UDE->getLoc(), diag::member_shadows_global_function, - UDE->getName(), methodKind, choice->getDescriptiveKind(), + emitDiagnostic(diag::member_shadows_global_function, UDE->getName(), + methodKind, choice->getDescriptiveKind(), choice->getFullName(), qualifier); SmallString<32> namePlusDot = qualifier.str(); namePlusDot.push_back('.'); - emitDiagnostic(UDE->getLoc(), diag::fix_unqualified_access_top_level_multi, - namePlusDot, choice->getDescriptiveKind(), qualifier) + emitDiagnostic(diag::fix_unqualified_access_top_level_multi, namePlusDot, + choice->getDescriptiveKind(), qualifier) .fixItInsert(UDE->getStartLoc(), namePlusDot); - emitDiagnostic(choice, diag::decl_declared_here, choice->getFullName()); + emitDiagnosticAt(choice, diag::decl_declared_here, choice->getFullName()); return true; } bool CoercionAsForceCastFailure::diagnoseAsError() { - auto *coercion = cast(getRawAnchor()); - emitDiagnostic(coercion->getLoc(), diag::coercion_may_fail_warning, - getFromType(), getToType()) - .highlight(coercion->getSourceRange()); + emitDiagnostic(diag::coercion_may_fail_warning, getFromType(), getToType()) + .highlight(getSourceRange()); return true; } diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 6ca8227611e91..85534ebffcb32 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -56,6 +56,12 @@ class FailureDiagnostic { virtual ~FailureDiagnostic(); + virtual SourceLoc getLoc() const { return getAnchor()->getLoc(); } + + virtual SourceRange getSourceRange() const { + return getAnchor()->getSourceRange(); + } + /// Try to diagnose a problem given affected expression, /// failure location, types and declarations deduced by /// constraint system, and other auxiliary information. @@ -79,7 +85,7 @@ class FailureDiagnostic { Expr *getRawAnchor() const { return RawAnchor; } - Expr *getAnchor() const { return Anchor; } + virtual Expr *getAnchor() const { return Anchor; } ConstraintLocator *getLocator() const { return Locator; } @@ -108,6 +114,9 @@ class FailureDiagnostic { template InFlightDiagnostic emitDiagnostic(ArgTypes &&... Args) const; + template + InFlightDiagnostic emitDiagnosticAt(ArgTypes &&... Args) const; + protected: const Solution &getSolution() const { return S; } @@ -354,7 +363,7 @@ class MissingConformanceFailure final : public RequirementFailure { } private: - bool diagnoseTypeCannotConform(Expr *anchor, Type nonConformingType, + bool diagnoseTypeCannotConform(Type nonConformingType, Type protocolType) const; }; @@ -642,7 +651,7 @@ class ContextualFailure : public FailureDiagnostic { /// Try to add a fix-it to convert a stored property into a computed /// property - void tryComputedPropertyFixIts(Expr *expr) const; + void tryComputedPropertyFixIts() const; bool isIntegerType(Type type) const { return conformsToKnownProtocol( @@ -777,6 +786,8 @@ class MissingExplicitConversionFailure final : public ContextualFailure { Type toType, ConstraintLocator *locator) : ContextualFailure(solution, fromType, toType, locator) {} + Expr *getAnchor() const override; + bool diagnoseAsError() override; private: @@ -832,7 +843,7 @@ class InvalidUseOfAddressOf final : public ContextualFailure { protected: /// Compute location of the failure for diagnostic. - SourceLoc getLoc() const; + SourceLoc getLoc() const override; }; /// Diagnose mismatches relating to tuple destructuring. @@ -934,6 +945,8 @@ class MissingCallFailure final : public FailureDiagnostic { MissingCallFailure(const Solution &solution, ConstraintLocator *locator) : FailureDiagnostic(solution, locator) {} + Expr *getAnchor() const override; + bool diagnoseAsError() override; }; @@ -1028,6 +1041,11 @@ class MissingMemberFailure final : public InvalidMemberRefFailure { DeclNameRef memberName, ConstraintLocator *locator) : InvalidMemberRefFailure(solution, baseType, memberName, locator) {} + SourceLoc getLoc() const override { + // Diagnostic should point to the member instead of its base expression. + return getRawAnchor()->getLoc(); + } + bool diagnoseAsError() override; private: @@ -1122,6 +1140,8 @@ class InvalidInitRefFailure : public FailureDiagnostic { const ConstructorDecl *Init; SourceRange BaseRange; + Expr *getAnchor() const override { return getRawAnchor(); } + InvalidInitRefFailure(const Solution &solution, Type baseTy, const ConstructorDecl *init, SourceRange baseRange, ConstraintLocator *locator) @@ -1195,6 +1215,8 @@ class ImplicitInitOnNonConstMetatypeFailure final ConstraintLocator *locator) : InvalidInitRefFailure(solution, baseTy, init, SourceRange(), locator) {} + SourceLoc getLoc() const override; + bool diagnoseAsError() override; }; @@ -1212,6 +1234,8 @@ class MissingArgumentsFailure final : public FailureDiagnostic { assert(!SynthesizedArgs.empty() && "No missing arguments?!"); } + Expr *getAnchor() const override; + bool diagnoseAsError() override; bool diagnoseAsNote() override; @@ -1322,6 +1346,9 @@ class ClosureParamDestructuringFailure final : public FailureDiagnostic { ConstraintLocator *locator) : FailureDiagnostic(solution, locator), ContextualType(contextualType) {} + SourceLoc getLoc() const override; + SourceRange getSourceRange() const override; + bool diagnoseAsError() override; private: @@ -1390,6 +1417,9 @@ class AnyObjectKeyPathRootFailure final : public FailureDiagnostic { ConstraintLocator *locator) : FailureDiagnostic(solution, locator) {} + SourceLoc getLoc() const override; + SourceRange getSourceRange() const override; + bool diagnoseAsError() override; }; @@ -1418,6 +1448,8 @@ class KeyPathSubscriptIndexHashableFailure final : public FailureDiagnostic { locator->isKeyPathSubscriptComponent()); } + SourceLoc getLoc() const override; + bool diagnoseAsError() override; }; @@ -1441,7 +1473,7 @@ class InvalidMemberRefInKeyPath : public FailureDiagnostic { protected: /// Compute location of the failure for diagnostic. - SourceLoc getLoc() const; + SourceLoc getLoc() const override; bool isForKeyPathDynamicMemberLookup() const { return getLocator()->isForKeyPathDynamicMemberLookup(); @@ -1651,6 +1683,8 @@ class SkipUnhandledConstructInFunctionBuilderFailure final : FailureDiagnostic(solution, locator), unhandled(unhandled), builder(builder) {} + SourceLoc getLoc() const override; + bool diagnoseAsError() override; bool diagnoseAsNote() override; }; @@ -1819,8 +1853,6 @@ class ArgumentMismatchFailure : public ContextualFailure { /// Are currently impossible to fix correctly, /// so we have to attend to that in diagnostics. bool diagnoseMisplacedMissingArgument() const; - - SourceLoc getLoc() const { return getAnchor()->getLoc(); } }; /// Replace a coercion ('as') with a forced checked cast ('as!'). @@ -1830,6 +1862,8 @@ class MissingForcedDowncastFailure final : public ContextualFailure { Type toType, ConstraintLocator *locator) : ContextualFailure(solution, fromType, toType, locator) {} + Expr *getAnchor() const override; + bool diagnoseAsError() override; }; @@ -1927,7 +1961,9 @@ class UnableToInferProtocolLiteralType final : public FailureDiagnostic { ConstraintLocator *locator) : FailureDiagnostic(solution, locator) {} - bool diagnoseAsError(); + SourceLoc getLoc() const override; + + bool diagnoseAsError() override; }; /// Diagnose an attempt to reference a top-level name shadowed by a local diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 61a4bee058587..ecc257c90a47e 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2843,6 +2843,11 @@ namespace { return expr->getType(); } + Type visitPropertyWrapperValuePlaceholderExpr( + PropertyWrapperValuePlaceholderExpr *expr) { + return expr->getType(); + } + Type visitDefaultArgumentExpr(DefaultArgumentExpr *expr) { return expr->getType(); } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 63037344ebe3c..a38b6c096390d 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -4180,6 +4180,7 @@ SolutionApplicationTarget::SolutionApplicationTarget( expression.convertType = convertType; expression.pattern = nullptr; expression.wrappedVar = nullptr; + expression.innermostWrappedValueInit = nullptr; expression.isDiscarded = isDiscarded; expression.bindPatternVarsOneWay = false; expression.initialization.patternBinding = nullptr; @@ -4204,9 +4205,11 @@ void SolutionApplicationTarget::maybeApplyPropertyWrapper() { Expr *backingInitializer; if (Expr *initializer = expression.expression) { // Form init(wrappedValue:) call(s). - Expr *wrappedInitializer = - buildPropertyWrapperWrappedValueCall( - singleVar, Type(), initializer, /*ignoreAttributeArgs=*/false); + Expr *wrappedInitializer = buildPropertyWrapperWrappedValueCall( + singleVar, Type(), initializer, /*ignoreAttributeArgs=*/false, + [&](ApplyExpr *innermostInit) { + expression.innermostWrappedValueInit = innermostInit; + }); if (!wrappedInitializer) return; diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index de4d4cbba6997..fe95854aec002 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -1223,6 +1223,10 @@ class SolutionApplicationTarget { /// this is an initialization involving a property wrapper. VarDecl *wrappedVar; + /// The innermost call to \c init(wrappedValue:), if this is an + /// initialization involving a property wrapper. + ApplyExpr *innermostWrappedValueInit; + /// Whether the expression result will be discarded at the end. bool isDiscarded; @@ -1414,6 +1418,20 @@ class SolutionApplicationTarget { return kind == Kind::expression && expression.bindPatternVarsOneWay; } + /// Whether or not an opaque value placeholder should be injected into the + /// first \c wrappedValue argument of an apply expression. + bool shouldInjectWrappedValuePlaceholder(ApplyExpr *apply) const { + if (kind != Kind::expression || + expression.contextualPurpose != CTP_Initialization) + return false; + + auto *wrappedVar = expression.wrappedVar; + if (!wrappedVar || wrappedVar->isStatic()) + return false; + + return expression.innermostWrappedValueInit == apply; + } + /// Retrieve the wrapped variable when initializing a pattern with a /// property wrapper. VarDecl *getInitializationWrappedVar() const { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 2f0f90bc9a0c1..270a2ad4991e3 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -676,8 +676,9 @@ IsStaticRequest::evaluate(Evaluator &evaluator, FuncDecl *decl) const { dc->isTypeContext()) { const auto operatorName = decl->getBaseIdentifier(); if (auto ED = dyn_cast(dc->getAsDecl())) { - decl->diagnose(diag::nonstatic_operator_in_extension, - operatorName, ED->getExtendedTypeRepr()) + decl->diagnose(diag::nonstatic_operator_in_extension, operatorName, + ED->getExtendedTypeRepr() != nullptr, + ED->getExtendedTypeRepr()) .fixItInsert(decl->getAttributeInsertionLoc(/*forModifier=*/true), "static "); } else { diff --git a/lib/Sema/TypeCheckPropertyWrapper.cpp b/lib/Sema/TypeCheckPropertyWrapper.cpp index 7ea20736e331f..559038568eca5 100644 --- a/lib/Sema/TypeCheckPropertyWrapper.cpp +++ b/lib/Sema/TypeCheckPropertyWrapper.cpp @@ -669,11 +669,11 @@ Type swift::computeWrappedValueType(VarDecl *var, Type backingStorageType, } static bool isOpaquePlaceholderClosure(const Expr *value) { - auto ove = dyn_cast(value); - if (!ove || !ove->isPlaceholder()) + auto *placeholder = dyn_cast(value); + if (!placeholder) return false; - if (auto valueFnTy = ove->getType()->getAs()) { + if (auto valueFnTy = placeholder->getType()->getAs()) { return (valueFnTy->getNumParams() == 0); } @@ -681,12 +681,13 @@ static bool isOpaquePlaceholderClosure(const Expr *value) { } Expr *swift::buildPropertyWrapperWrappedValueCall( - VarDecl *var, Type backingStorageType, Expr *value, - bool ignoreAttributeArgs) { + VarDecl *var, Type backingStorageType, Expr *value, bool ignoreAttributeArgs, + llvm::function_ref innermostInitCallback) { // From the innermost wrapper type out, form init(wrapperValue:) calls. ASTContext &ctx = var->getASTContext(); auto wrapperAttrs = var->getAttachedPropertyWrappers(); Expr *initializer = value; + ApplyExpr *innermostInit = nullptr; if (var->isInnermostPropertyWrapperInitUsesEscapingAutoClosure() && isOpaquePlaceholderClosure(value)) { // We can't pass the opaque closure directly as an autoclosure arg. @@ -727,10 +728,14 @@ Expr *swift::buildPropertyWrapperWrappedValueCall( if (endLoc.isInvalid() && startLoc.isValid()) endLoc = wrapperAttrs[i]->getTypeLoc().getSourceRange().End; - initializer = CallExpr::create( + auto *init = CallExpr::create( ctx, typeExpr, startLoc, {initializer}, {argName}, {initializer->getStartLoc()}, endLoc, nullptr, /*implicit=*/true); + initializer = init; + + if (!innermostInit) + innermostInit = init; continue; } @@ -759,10 +764,17 @@ Expr *swift::buildPropertyWrapperWrappedValueCall( if (endLoc.isInvalid() && startLoc.isValid()) endLoc = wrapperAttrs[i]->getTypeLoc().getSourceRange().End; - initializer = CallExpr::create( + auto *init = CallExpr::create( ctx, typeExpr, startLoc, elements, elementNames, elementLocs, endLoc, nullptr, /*implicit=*/true); + initializer = init; + + if (!innermostInit) + innermostInit = init; } - + + // Invoke the callback, passing in the innermost init(wrappedValue:) call + innermostInitCallback(innermostInit); + return initializer; } diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 6d58d2d439d99..b94e21fd7ce5b 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -2476,6 +2476,7 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator, nominalWrapper->diagnose(diag::property_wrapper_declared_here, nominalWrapper->getFullName()); } + return PropertyWrapperBackingPropertyInfo(); } } @@ -2524,11 +2525,13 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator, TypeChecker::typeCheckPatternBinding(parentPBD, patternNumber); } - Expr *originalInitialValue = nullptr; - if (Expr *init = parentPBD->getInit(patternNumber)) { - pbd->setInit(0, init); + Expr *initializer = nullptr; + PropertyWrapperValuePlaceholderExpr *wrappedValue = nullptr; + + if ((initializer = parentPBD->getInit(patternNumber))) { + pbd->setInit(0, initializer); pbd->setInitializerChecked(0); - originalInitialValue = findOriginalPropertyWrapperInitialValue(var, init); + wrappedValue = findWrappedValuePlaceholder(initializer); } else if (!parentPBD->isInitialized(patternNumber) && wrapperInfo.defaultInit) { // FIXME: Record this expression somewhere so that DI can perform the @@ -2548,30 +2551,37 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator, storageVar = synthesizePropertyWrapperStorageWrapperProperty( ctx, var, storageInterfaceType, wrapperInfo.projectedValueVar); } - - // Get the property wrapper information. - if (!var->allAttachedPropertyWrappersHaveWrappedValueInit() && - !originalInitialValue) { + + // If no initial wrapped value was provided via '=' and either: + // 1. Not all of the attached property wrappers have init(wrappedValue:), or + // 2. An initializer has already been synthesized from arguments in the + // property wrapper attribute, + // then this property wrapper cannot be initialized out-of-line with a wrapped + // value. + if (!wrappedValue && (!var->allAttachedPropertyWrappersHaveWrappedValueInit() || + initializer)) { return PropertyWrapperBackingPropertyInfo( backingVar, storageVar, nullptr, nullptr, nullptr); } // Form the initialization of the backing property from a value of the // original property's type. - Type origValueInterfaceType = var->getPropertyWrapperInitValueInterfaceType(); - Type origValueType = - var->getDeclContext()->mapTypeIntoContext(origValueInterfaceType); - OpaqueValueExpr *origValue = - new (ctx) OpaqueValueExpr(var->getSourceRange(), origValueType, - /*isPlaceholder=*/true); - Expr *initializer = buildPropertyWrapperWrappedValueCall( - var, storageType, origValue, - /*ignoreAttributeArgs=*/!originalInitialValue); - typeCheckSynthesizedWrapperInitializer( - pbd, backingVar, parentPBD, initializer); - - return PropertyWrapperBackingPropertyInfo( - backingVar, storageVar, originalInitialValue, initializer, origValue); + if (!initializer) { + Type origValueInterfaceType = var->getPropertyWrapperInitValueInterfaceType(); + Type origValueType = + var->getDeclContext()->mapTypeIntoContext(origValueInterfaceType); + wrappedValue = PropertyWrapperValuePlaceholderExpr::create( + ctx, var->getSourceRange(), origValueType, /*wrappedValue=*/nullptr); + initializer = buildPropertyWrapperWrappedValueCall( + var, storageType, wrappedValue, /*ignoreAttributeArgs=*/true); + typeCheckSynthesizedWrapperInitializer( + pbd, backingVar, parentPBD, initializer); + } + + return PropertyWrapperBackingPropertyInfo(backingVar, storageVar, + wrappedValue->getOriginalWrappedValue(), + initializer, + wrappedValue->getOpaqueValuePlaceholder()); } /// Given a storage declaration in a protocol, set it up with the right diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 3c9a5584a6dbb..3582eeccb3f48 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1443,14 +1443,15 @@ bool isValidKeyPathDynamicMemberLookup(SubscriptDecl *decl, /// (which will produce the original property type). If not specified, defaults to the maximum. Type computeWrappedValueType(VarDecl *var, Type backingStorageType, Optional limit = None); - + /// Build a call to the init(wrappedValue:) initializers of the property -/// wrappers, filling in the given \c value as the original value. -Expr *buildPropertyWrapperWrappedValueCall(VarDecl *var, - Type backingStorageType, - Expr *value, - bool ignoreAttributeArgs); - +/// wrappers, filling in the given \c value as the original value. Optionally +/// pass a callback that will get invoked with the innermost init(wrappedValue:) +/// call. +Expr *buildPropertyWrapperWrappedValueCall( + VarDecl *var, Type backingStorageType, Expr *value, bool ignoreAttributeArgs, + llvm::function_ref callback = [](ApplyExpr *) {}); + /// Whether an overriding declaration requires the 'override' keyword. enum class OverrideRequiresKeyword { /// The keyword is never required. diff --git a/lib/SymbolGraphGen/SymbolGraph.cpp b/lib/SymbolGraphGen/SymbolGraph.cpp index 980ca64f09edf..61b4a14a9b564 100644 --- a/lib/SymbolGraphGen/SymbolGraph.cpp +++ b/lib/SymbolGraphGen/SymbolGraph.cpp @@ -253,19 +253,29 @@ SymbolGraph::recordInheritanceRelationships(Symbol S) { } void SymbolGraph::recordDefaultImplementationRelationships(Symbol S) { - const auto VD = S.getSymbolDecl(); - if (const auto *Extension = dyn_cast(VD->getDeclContext())) { - if (const auto *Protocol = Extension->getExtendedProtocolDecl()) { - for (const auto *Member : Protocol->getMembers()) { - if (const auto *MemberVD = dyn_cast(Member)) { - if (MemberVD->getFullName().compare(VD->getFullName()) == 0) { - recordEdge(Symbol(this, VD, nullptr), - Symbol(this, MemberVD, nullptr), - RelationshipKind::DefaultImplementationOf()); - } + const auto *VD = S.getSymbolDecl(); + + /// Claim a protocol `P`'s members as default implementation targets + /// for `VD`. + auto HandleProtocol = [=](const ProtocolDecl *P) { + for (const auto *Member : P->getMembers()) { + if (const auto *MemberVD = dyn_cast(Member)) { + if (MemberVD->getFullName().compare(VD->getFullName()) == 0) { + recordEdge(Symbol(this, VD, nullptr), + Symbol(this, MemberVD, nullptr), + RelationshipKind::DefaultImplementationOf()); } } } + }; + + if (const auto *Extension = dyn_cast(VD->getDeclContext())) { + if (const auto *ExtendedProtocol = Extension->getExtendedProtocolDecl()) { + HandleProtocol(ExtendedProtocol); + for (const auto *Inherited : ExtendedProtocol->getInheritedProtocols()) { + HandleProtocol(Inherited); + } + } } } diff --git a/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift b/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift index 8f40856569cd1..7026959536d9c 100644 --- a/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift +++ b/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift @@ -107,7 +107,7 @@ internal func getSectionInfo(_ name: String, /// Get the Swift Reflection section locations for a loaded image. /// -/// An image of interest must have the following sections in the __DATA +/// An image of interest must have the following sections in the __TEXT /// segment: /// - __swift5_fieldmd /// - __swift5_assocty diff --git a/stdlib/public/Darwin/Metal/Metal.swift b/stdlib/public/Darwin/Metal/Metal.swift index 479cd69e917fc..c1dd0847c693c 100644 --- a/stdlib/public/Darwin/Metal/Metal.swift +++ b/stdlib/public/Darwin/Metal/Metal.swift @@ -90,9 +90,10 @@ extension MTLDevice { @available(macOS 10.13, iOS 11.0, tvOS 11.0, *) public func getDefaultSamplePositions(sampleCount: Int) -> [MTLSamplePosition] { - var positions = [MTLSamplePosition](repeating: MTLSamplePosition(x: 0,y: 0), count: sampleCount) - __getDefaultSamplePositions(&positions, count: sampleCount) - return positions + return [MTLSamplePosition](unsafeUninitializedCapacity: sampleCount) { buf, initializedCount in + __getDefaultSamplePositions(buf.baseAddress!, count: sampleCount) + initializedCount = sampleCount + } } } @@ -263,9 +264,10 @@ extension MTLRenderPassDescriptor { @available(macOS 10.13, iOS 11.0, tvOS 11.0, *) public func getSamplePositions() -> [MTLSamplePosition] { let numPositions = __getSamplePositions(nil, count: 0) - var positions = [MTLSamplePosition](repeating: MTLSamplePosition(x: 0,y: 0), count: numPositions) - __getSamplePositions(&positions, count: numPositions) - return positions + return [MTLSamplePosition](unsafeUninitializedCapacity: numPositions) { buf, initializedCount in + __getSamplePositions(buf.baseAddress!, count: numPositions) + initializedCount = numPositions + } } } diff --git a/stdlib/public/SwiftShims/CMakeLists.txt b/stdlib/public/SwiftShims/CMakeLists.txt index b6d3edc47818c..1f29161275d01 100644 --- a/stdlib/public/SwiftShims/CMakeLists.txt +++ b/stdlib/public/SwiftShims/CMakeLists.txt @@ -7,6 +7,7 @@ set(sources KeyPath.h LibcOverlayShims.h LibcShims.h + Metadata.h Random.h RefCount.h RuntimeShims.h diff --git a/stdlib/public/SwiftShims/Metadata.h b/stdlib/public/SwiftShims/Metadata.h new file mode 100644 index 0000000000000..f2d5ebfbb967f --- /dev/null +++ b/stdlib/public/SwiftShims/Metadata.h @@ -0,0 +1,46 @@ +//===--- Metadata.h -------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_STDLIB_SHIMS_METADATA_H +#define SWIFT_STDLIB_SHIMS_METADATA_H + +#include "SwiftStddef.h" +#include "Visibility.h" + +#ifndef __swift__ + +#include "swift/ABI/Metadata.h" + +#else // ifndef __swift__ + +typedef struct { + const void *type; + __swift_size_t state; +} MetadataResponse; + +#endif + +#ifdef __cplusplus +namespace swift { extern "C" { +#endif + +// Shims to call a metadata accessor in Swift. +SWIFT_RUNTIME_STDLIB_API +MetadataResponse _swift_metadataAccessorCall(void *accessor, + __swift_size_t request, + const void * const *args, + __swift_size_t size); +#ifdef __cplusplus +}} // extern "C", namespace swift +#endif + +#endif diff --git a/stdlib/public/SwiftShims/module.modulemap b/stdlib/public/SwiftShims/module.modulemap index 493e0db7df559..1ce05401ad22d 100644 --- a/stdlib/public/SwiftShims/module.modulemap +++ b/stdlib/public/SwiftShims/module.modulemap @@ -6,6 +6,7 @@ module SwiftShims { header "HeapObject.h" header "KeyPath.h" header "LibcShims.h" + header "Metadata.h" header "Random.h" header "RefCount.h" header "RuntimeShims.h" diff --git a/stdlib/public/runtime/Float16Support.cpp b/stdlib/public/runtime/Float16Support.cpp index 2405b639ab913..d7377400ba0be 100644 --- a/stdlib/public/runtime/Float16Support.cpp +++ b/stdlib/public/runtime/Float16Support.cpp @@ -30,7 +30,7 @@ // Android NDK (accessor); + auto array = llvm::ArrayRef(args, size); + return MetadataAccessFunction(func)(MetadataRequest(request), array); +} diff --git a/test/AutoDiff/IRGen/witness_table_differentiable_requirements.sil b/test/AutoDiff/IRGen/witness_table_differentiable_requirements.sil index 305180618a892..a800eda5d3f8f 100644 --- a/test/AutoDiff/IRGen/witness_table_differentiable_requirements.sil +++ b/test/AutoDiff/IRGen/witness_table_differentiable_requirements.sil @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend -parse-sil %s -emit-ir | %FileCheck %s +// REQUIRES: CPU=x86_64 sil_stage canonical diff --git a/test/ClangImporter/Inputs/custom-modules/EnumExhaustivity.apinotes b/test/CXXInterop/enum/Inputs/EnumExhaustivity.apinotes similarity index 100% rename from test/ClangImporter/Inputs/custom-modules/EnumExhaustivity.apinotes rename to test/CXXInterop/enum/Inputs/EnumExhaustivity.apinotes diff --git a/test/ClangImporter/Inputs/custom-modules/EnumExhaustivity.h b/test/CXXInterop/enum/Inputs/EnumExhaustivity.h similarity index 100% rename from test/ClangImporter/Inputs/custom-modules/EnumExhaustivity.h rename to test/CXXInterop/enum/Inputs/EnumExhaustivity.h diff --git a/test/CXXInterop/enum/Inputs/enum-anon.h b/test/CXXInterop/enum/Inputs/enum-anon.h new file mode 100644 index 0000000000000..3379a60747a93 --- /dev/null +++ b/test/CXXInterop/enum/Inputs/enum-anon.h @@ -0,0 +1,19 @@ +enum { + Constant1, + Constant2 +}; + +enum { + VarConstant1, + VarConstant2 +} global; + +typedef struct SR2511 { + int x; + + enum { + SR2511A = 0, SR2511B, SR2511C + } y; + + int z; +} SR2511; diff --git a/test/CXXInterop/enum/Inputs/module.map b/test/CXXInterop/enum/Inputs/module.map new file mode 100644 index 0000000000000..71f48fffcc0c8 --- /dev/null +++ b/test/CXXInterop/enum/Inputs/module.map @@ -0,0 +1,8 @@ +module EnumAnon { + header "enum-anon.h" +} + +module EnumExhaustivity { + header "EnumExhaustivity.h" + export * +} diff --git a/test/ClangImporter/enum-anon-sized.swift b/test/CXXInterop/enum/enum-anon-sized.swift similarity index 67% rename from test/ClangImporter/enum-anon-sized.swift rename to test/CXXInterop/enum/enum-anon-sized.swift index 3d63183094dcb..0f2c837882a87 100644 --- a/test/ClangImporter/enum-anon-sized.swift +++ b/test/CXXInterop/enum/enum-anon-sized.swift @@ -1,4 +1,7 @@ -// RUN: %target-swift-frontend -emit-ir %s -enable-objc-interop -import-objc-header %S/Inputs/enum-anon.h | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-%target-runtime %s +// RUN: %target-swift-frontend -emit-ir %s -I %S/Inputs | %FileCheck -check-prefix=CHECK %s +// RUN: %target-swift-frontend -emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck -check-prefix=CHECK %s + +import EnumAnon func verifyIsInt(_: inout Int) { } func verifyIsInt32(_: inout Int32) { } @@ -23,11 +26,6 @@ public func testIR(x: UnsafePointer) -> CInt { // CHECK: store i32 1, i32* getelementptr inbounds ([[ENUM_TYPE]], [[ENUM_TYPE]]* bitcast (i32* @global to [[ENUM_TYPE]]*), i32 0, i32 0), align 4 global = VarConstant2 -#if _runtime(_ObjC) - // CHECK-objc: store i16 1, i16* getelementptr inbounds (%Ts6UInt16V, %Ts6UInt16V* bitcast (i16* @usGlobal to %Ts6UInt16V*), i32 0, i32 0), align 2 - usGlobal = USVarConstant2 -#endif - // Force the definition of the type above. // CHECK: ret return x.pointee.z diff --git a/test/CXXInterop/enum/enum-anon.swift b/test/CXXInterop/enum/enum-anon.swift new file mode 100644 index 0000000000000..1933a84326afd --- /dev/null +++ b/test/CXXInterop/enum/enum-anon.swift @@ -0,0 +1,17 @@ +// RUN: %target-swift-frontend -typecheck %s -I %S/Inputs -DDIAGS -verify +// RUN: %target-swift-frontend -typecheck %s -enable-cxx-interop -I %S/Inputs -DDIAGS -verify +import EnumAnon + +func testDiags() { + + let us2: UInt16 = 0 + let _: String = us2 // expected-error {{cannot convert value of type 'UInt16' to specified type 'String'}} + + let usVar2: UInt16 = 0 + let _: String = usVar2 // expected-error {{cannot convert value of type 'UInt16' to specified type 'String'}} + + // The nested anonymous enum value should still have top-level scope, because + // that's how C works. It should also have the same type as the field (above). + let _: String = SR2511.SR2511B // expected-error {{type 'SR2511' has no member 'SR2511B'}} +} + diff --git a/test/ClangImporter/enum-cxx.swift b/test/CXXInterop/enum/enum-cxx.swift similarity index 71% rename from test/ClangImporter/enum-cxx.swift rename to test/CXXInterop/enum/enum-cxx.swift index 281e31e3dc6f1..dfd1d7725f164 100644 --- a/test/ClangImporter/enum-cxx.swift +++ b/test/CXXInterop/enum/enum-cxx.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-ir -primary-file %s -I %S/Inputs/custom-modules -module-cache-path %t -enable-cxx-interop -o - | %FileCheck %s +// RUN: %target-swift-frontend -emit-ir -primary-file %s -I %S/../../ClangImporter/Inputs/ -module-cache-path %t -enable-cxx-interop -o - | %FileCheck %s import CXXInterop diff --git a/test/ClangImporter/enum-exhaustivity-system.swift b/test/CXXInterop/enum/enum-exhaustivity-system.swift similarity index 94% rename from test/ClangImporter/enum-exhaustivity-system.swift rename to test/CXXInterop/enum/enum-exhaustivity-system.swift index 3e54e5aabc0ea..b0547b5287648 100644 --- a/test/ClangImporter/enum-exhaustivity-system.swift +++ b/test/CXXInterop/enum/enum-exhaustivity-system.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -typecheck %s -Xcc -isystem -Xcc %S/Inputs/custom-modules -verify -enable-nonfrozen-enum-exhaustivity-diagnostics +// RUN: %target-swift-frontend -typecheck %s -Xcc -isystem -Xcc %S/Inputs -verify -enable-nonfrozen-enum-exhaustivity-diagnostics import EnumExhaustivity diff --git a/test/ClangImporter/enum-exhaustivity.swift b/test/CXXInterop/enum/enum-exhaustivity.swift similarity index 86% rename from test/ClangImporter/enum-exhaustivity.swift rename to test/CXXInterop/enum/enum-exhaustivity.swift index 362b84601ca1b..a3d342ce1816d 100644 --- a/test/ClangImporter/enum-exhaustivity.swift +++ b/test/CXXInterop/enum/enum-exhaustivity.swift @@ -1,6 +1,6 @@ -// RUN: %target-swift-frontend -typecheck %s -I %S/Inputs/custom-modules -verify -warnings-as-errors -enable-nonfrozen-enum-exhaustivity-diagnostics +// RUN: %target-swift-frontend -typecheck %s -I %S/Inputs -verify -warnings-as-errors -enable-nonfrozen-enum-exhaustivity-diagnostics -// RUN: %target-swift-ide-test -source-filename %s -print-module -module-to-print EnumExhaustivity -I %S/Inputs/custom-modules | %FileCheck %s +// RUN: %target-swift-ide-test -source-filename %s -print-module -module-to-print EnumExhaustivity -I %S/Inputs | %FileCheck %s // CHECK-LABEL: {{^}}enum RegularEnum : {{.+}} { // CHECK: case A diff --git a/test/ClangImporter/Inputs/custom-modules/module.map b/test/ClangImporter/Inputs/custom-modules/module.map index 6c4612efb44c0..6d4fec580afa8 100644 --- a/test/ClangImporter/Inputs/custom-modules/module.map +++ b/test/ClangImporter/Inputs/custom-modules/module.map @@ -45,11 +45,6 @@ module ctypes_bits_exported { export * } -module EnumExhaustivity { - header "EnumExhaustivity.h" - export * -} - module ExternIntX { header "x.h" } module HasSubmodule { diff --git a/test/ClangImporter/Inputs/enum-anon.h b/test/ClangImporter/Inputs/enum-anon.h index ae48c3bc4dcd7..43fa6a9057f6d 100644 --- a/test/ClangImporter/Inputs/enum-anon.h +++ b/test/ClangImporter/Inputs/enum-anon.h @@ -1,24 +1,3 @@ -enum { - Constant1, - Constant2 -}; - -enum { - VarConstant1, - VarConstant2 -} global; - -typedef struct SR2511 { - int x; - - enum { - SR2511A = 0, SR2511B, SR2511C - } y; - - int z; -} SR2511; - -#if __OBJC__ enum : unsigned short { USConstant1, USConstant2 @@ -28,4 +7,3 @@ enum : unsigned short { USVarConstant1, USVarConstant2 } usGlobal; -#endif // __OBJC__ diff --git a/test/ClangImporter/enum-anon.swift b/test/ClangImporter/enum-anon.swift index 14e2baa7cca15..d87f930bf2faa 100644 --- a/test/ClangImporter/enum-anon.swift +++ b/test/ClangImporter/enum-anon.swift @@ -1,22 +1,10 @@ // RUN: %target-swift-frontend -typecheck %s -enable-objc-interop -import-objc-header %S/Inputs/enum-anon.h -DDIAGS -verify +// REQUIRES: objc_interop + func testDiags() { -#if _runtime(_ObjC) let us2 = USConstant2 -#else - let us2: UInt16 = 0 -#endif let _: String = us2 // expected-error {{cannot convert value of type 'UInt16' to specified type 'String'}} - -#if _runtime(_ObjC) let usVar2 = USVarConstant2 -#else - let usVar2: UInt16 = 0 -#endif let _: String = usVar2 // expected-error {{cannot convert value of type 'UInt16' to specified type 'String'}} - - // The nested anonymous enum value should still have top-level scope, because - // that's how C works. It should also have the same type as the field (above). - let _: String = SR2511.SR2511B // expected-error {{type 'SR2511' has no member 'SR2511B'}} } - diff --git a/test/Constraints/fixes.swift b/test/Constraints/fixes.swift index 618836f39f538..fc6ac9fa29869 100644 --- a/test/Constraints/fixes.swift +++ b/test/Constraints/fixes.swift @@ -111,7 +111,7 @@ class T { // let l = self.m2!.prop1 // expected-error@-1 {{cannot force unwrap value of non-optional type '() -> U?'}} {{22-23=}} - // expected-error@-2 {{method 'm2' was used as a property; add () to call it}} {{23-23=()}} + // expected-error@-2 {{method 'm2' was used as a property; add () to call it}} {{22-22=()}} } func m2() -> U! { diff --git a/test/Driver/batch_mode_response_files.swift b/test/Driver/batch_mode_response_files.swift index a08805f5abe59..2b3de61aaa306 100644 --- a/test/Driver/batch_mode_response_files.swift +++ b/test/Driver/batch_mode_response_files.swift @@ -2,7 +2,7 @@ // that they also use response files correctly when their argument lists are // too long. -// RUN: %{python} -c 'for i in range(500001): print "-DTEST_" + str(i)' > %t.resp +// RUN: %{python} -c 'for i in range(500001): print("-DTEST_" + str(i))' > %t.resp // RUN: %swiftc_driver -driver-print-jobs -module-name batch -enable-batch-mode -j 1 -c %S/Inputs/main.swift %S/Inputs/lib.swift @%t.resp 2>&1 > %t.jobs.txt // RUN: %FileCheck %s < %t.jobs.txt -check-prefix=BATCH diff --git a/test/Driver/response-file-merge-modules.swift b/test/Driver/response-file-merge-modules.swift index a2220d5517463..737ecf3af25cd 100644 --- a/test/Driver/response-file-merge-modules.swift +++ b/test/Driver/response-file-merge-modules.swift @@ -1,4 +1,4 @@ -// RUN: %{python} -c 'for i in range(500001): print "-DTEST_" + str(i)' > %t.resp +// RUN: %{python} -c 'for i in range(500001): print("-DTEST_" + str(i))' > %t.resp // RUN: %swiftc_driver -driver-print-jobs -module-name merge -emit-module %S/Inputs/main.swift %S/Inputs/lib.swift @%t.resp 2>&1 > %t.jobs.txt // RUN: %FileCheck %s < %t.jobs.txt -check-prefix=MERGE diff --git a/test/Driver/response-file.swift b/test/Driver/response-file.swift index 11b5774669744..5aa6b65a8fb96 100644 --- a/test/Driver/response-file.swift +++ b/test/Driver/response-file.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -typecheck @%t.0.resp %s 2>&1 | %FileCheck %s -check-prefix=SHORT // SHORT: warning: result of call to 'abs' is unused -// RUN: %{python} -c 'for a in ["A", "B", "C", "D"]: print "-DTEST1" + a' > %t.1.resp +// RUN: %{python} -c 'for a in ["A", "B", "C", "D"]: print("-DTEST1" + a)' > %t.1.resp // RUN: %target-build-swift -typecheck @%t.1.resp %s 2>&1 | %FileCheck %s -check-prefix=MULTIPLE // MULTIPLE: warning: result of call to 'abs' is unused @@ -24,7 +24,7 @@ // RUN: %target-build-swift -typecheck @%t.4B.resp 2>&1 | %FileCheck %s -check-prefix=RECURSIVE // RECURSIVE: warning: result of call to 'abs' is unused -// RUN: %{python} -c 'for i in range(500001): print "-DTEST5_" + str(i)' > %t.5.resp +// RUN: %{python} -c 'for i in range(500001): print("-DTEST5_" + str(i))' > %t.5.resp // RUN: %target-build-swift -typecheck @%t.5.resp %s 2>&1 | %FileCheck %s -check-prefix=LONG // LONG: warning: result of call to 'abs' is unused // RUN: %empty-directory(%t/tmp) diff --git a/test/Interpreter/metadata_access.swift b/test/Interpreter/metadata_access.swift new file mode 100644 index 0000000000000..f2c542d8665fc --- /dev/null +++ b/test/Interpreter/metadata_access.swift @@ -0,0 +1,54 @@ +// RUN: %target-run-simple-swift | %FileCheck %s +// REQUIRES: executable_test + +import SwiftShims + +struct MetadataAccessFunction { + let ptr: UnsafeMutableRawPointer + + func callAsFunction(request: Int, args: [Any.Type]) -> MetadataResponse { + args.withUnsafeBufferPointer { + $0.baseAddress!.withMemoryRebound( + to: UnsafeRawPointer?.self, + capacity: args.count + ) { + _swift_metadataAccessorCall(ptr, request, $0, args.count) + } + } + } +} + +func callStructAccessor( + for type: Any.Type, + with generics: Any.Type... +) -> MetadataResponse { + let metadata = unsafeBitCast(type, to: UnsafeRawPointer.self) + let descriptor = metadata.advanced(by: MemoryLayout.size) + .load(as: UnsafeMutableRawPointer.self) + let accessorLoc = descriptor.advanced(by: MemoryLayout.size * 3) + let accessor = accessorLoc.advanced(by: Int(accessorLoc.load(as: Int32.self))) + + let accessFn = MetadataAccessFunction(ptr: accessor) + return accessFn(request: 0, args: generics) +} + +let int = callStructAccessor(for: Int.self) +// CHECK: Int +print(unsafeBitCast(int.type!, to: Any.Type.self)) +// CHECK: 0 +print(int.state) + +let doubleArray = callStructAccessor(for: [Int].self, with: Double.self) +// CHECK: Array +print(unsafeBitCast(doubleArray.type!, to: Any.Type.self)) +// CHECK: 0 +print(doubleArray.state) + +let dictOfIntAndDoubleArray = callStructAccessor( + for: [String: [Int]].self, + with: Int.self, [Double].self +) +// CHECK: Dictionary> +print(unsafeBitCast(dictOfIntAndDoubleArray.type!, to: Any.Type.self)) +// CHECK: 0 +print(dictOfIntAndDoubleArray.state) diff --git a/test/Profiler/coverage_var_init.swift b/test/Profiler/coverage_var_init.swift index 5d54a3b1c22dd..596d25649f928 100644 --- a/test/Profiler/coverage_var_init.swift +++ b/test/Profiler/coverage_var_init.swift @@ -3,7 +3,7 @@ final class VarInit { // CHECK: sil_coverage_map {{.*}} "$s17coverage_var_init7VarInitC018initializedWrapperE0SivpfP" - // CHECK-NEXT: [[@LINE+1]]:4 -> [[@LINE+1]]:38 : 0 + // CHECK-NEXT: [[@LINE+1]]:4 -> [[@LINE+1]]:42 : 0 @Wrapper var initializedWrapperInit = 2 // CHECK: sil_coverage_map {{.*}} "$s17coverage_var_init7VarInitC04lazydE033_49373CB2DFB47C8DC62FA963604688DFLLSSvgSSyXEfU_" diff --git a/test/SILGen/property_wrappers.swift b/test/SILGen/property_wrappers.swift index 6292a49db145f..7c4fde2d5b98d 100644 --- a/test/SILGen/property_wrappers.swift +++ b/test/SILGen/property_wrappers.swift @@ -32,6 +32,9 @@ struct HasMemberwiseInit { @WrapperWithInitialValue(wrappedValue: 17) var z: Int + + @WrapperWithInitialValue + private var p: Bool = true } func forceHasMemberwiseInit() { @@ -76,6 +79,11 @@ func forceHasMemberwiseInit() { // CHECK-NOT: return // CHECK: function_ref @$s17property_wrappers23WrapperWithInitialValueV07wrappedF0ACyxGx_tcfC : $@convention(method) <τ_0_0> (@in τ_0_0, @thin WrapperWithInitialValue<τ_0_0>.Type) -> @out WrapperWithInitialValue<τ_0_0> +// variable initialization expression of HasMemberwiseInit._p +// CHECK-LABEL: sil hidden [transparent] [ossa] @$s17property_wrappers17HasMemberwiseInitV2_p33_{{.*}}23WrapperWithInitialValueVySbGvpfi : $@convention(thin) () -> Bool { +// CHECK: function_ref @$sSb22_builtinBooleanLiteralSbBi1__tcfC : $@convention(method) (Builtin.Int1, @thin Bool.Type) -> Bool +// CHECK: return {{%.*}} : $Bool + // default argument 0 of HasMemberwiseInit.init(x:y:z:) // CHECK: sil hidden [ossa] @$s17property_wrappers17HasMemberwiseInitV1x1y1zACyxGAA7WrapperVySbG_xAA0F16WithInitialValueVySiGtcfcfA_ : $@convention(thin) () -> Wrapper @@ -103,8 +111,33 @@ func forceHasMemberwiseInit() { // CHECK-NOT: return // CHECK: function_ref @$s17property_wrappers17HasMemberwiseInitV2_z33_{{.*}}23WrapperWithInitialValueVySiGvpfi : $@convention(thin) <τ_0_0 where τ_0_0 : DefaultInit> () -> WrapperWithInitialValue +// Initialization of p +// CHECK-NOT: return +// CHECK: function_ref @$s17property_wrappers17HasMemberwiseInitV2_p33_{{.*}}23WrapperWithInitialValueVySbGvpfi : $@convention(thin) <τ_0_0 where τ_0_0 : DefaultInit> () -> Bool +// CHECK-NOT: return +// CHECK: function_ref @$s17property_wrappers17HasMemberwiseInitV1p33_{{.*}} : $@convention(thin) <τ_0_0 where τ_0_0 : DefaultInit> (Bool) -> WrapperWithInitialValue + // CHECK: return +// Non-generic struct with private property wrapper +struct HasMemberwiseInitWithPrivateWrapper { + @WrapperWithInitialValue + var z: Int = 17 + + @WrapperWithInitialValue + private var p: Bool = true + + // CHECK-LABEL: sil hidden [ossa] @$s17property_wrappers35HasMemberwiseInitWithPrivateWrapperV1zACSi_tcfC : $@convention(method) (Int, @thin HasMemberwiseInitWithPrivateWrapper.Type) -> HasMemberwiseInitWithPrivateWrapper { + // CHECK: function_ref @$s17property_wrappers35HasMemberwiseInitWithPrivateWrapperV1zSivpfP : $@convention(thin) (Int) -> WrapperWithInitialValue + // CHECK: function_ref @$s17property_wrappers35HasMemberwiseInitWithPrivateWrapperV1p33_{{.*}} : $@convention(thin) (Bool) -> WrapperWithInitialValue + // CHECK: return {{%.*}} : $HasMemberwiseInitWithPrivateWrapper +} + +func forceHasMemberwiseInitWithPrivateWrapper() { + _ = HasMemberwiseInitWithPrivateWrapper(z: 42) +} + + // CHECK-LABEL: sil hidden [transparent] [ossa] @$s17property_wrappers9HasNestedV2_y33_{{.*}}14PrivateWrapperAELLVyx_SayxGGvpfi : $@convention(thin) () -> @owned Array { // CHECK: bb0: // CHECK: function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF diff --git a/test/Sema/property_wrappers.swift b/test/Sema/property_wrappers.swift new file mode 100644 index 0000000000000..9163077e39feb --- /dev/null +++ b/test/Sema/property_wrappers.swift @@ -0,0 +1,29 @@ +// RUN: %target-swift-frontend -typecheck -disable-availability-checking -dump-ast %s | %FileCheck %s + +struct Transaction { + var state: Int? +} + +@propertyWrapper +struct Wrapper { + var wrappedValue: Value + + init(wrappedValue: Value, + reset: @escaping (Value, inout Transaction) -> Void) { + self.wrappedValue = wrappedValue + } +} + +// rdar://problem/59685601 +// CHECK-LABEL: R_59685601 +struct R_59685601 { + // CHECK: tuple_expr implicit type='(wrappedValue: String, reset: (String, inout Transaction) -> Void)' + // CHECK-NEXT: property_wrapper_value_placeholder_expr implicit type='String' + // CHECK-NEXT: opaque_value_expr implicit type='String' + // CHECK-NEXT: string_literal_expr type='String' + @Wrapper(reset: { value, transaction in + transaction.state = 10 + }) + private var value = "hello" +} + diff --git a/test/SourceKit/Sema/sema_build_session.swift b/test/SourceKit/Sema/sema_build_session.swift index af3eee728627c..5069f80c16cb5 100644 --- a/test/SourceKit/Sema/sema_build_session.swift +++ b/test/SourceKit/Sema/sema_build_session.swift @@ -15,7 +15,8 @@ func test() { // UNSUPPORTED: OS=windows-msvc // ----------------------------------------------------------------------------- -// Test that modifications for frameworks in '-Fsystem' doesn't affect the result. +// Test that modifications for frameworks in '-Fsystem' doesn't affect the result +// within a session, and that they are propagated after restarting SourceKit. // RUN: %empty-directory(%t/ModuleCache) // RUN: %empty-directory(%t/System/Frameworks) @@ -69,7 +70,7 @@ func test() { // RUN: -shell -- cp -R %S/../Inputs/build_session/Frameworks_modified/FooHelper.framework %t/System/Frameworks/ == \ // RUN: -shell -- echo '## TWO' == \ // RUN: -req=sema %s -- %s -D TWO -F %t/Frameworks -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache \ -// RUN: | tee %t.reponse | %FileCheck %s --check-prefix=CHECK_USER +// RUN: | %FileCheck %s --check-prefix=CHECK_USER // CHECK_USER-LABEL: ## ONE // CHECK_USER-NOT: key.description @@ -81,3 +82,35 @@ func test() { // CHECK_USER: key.severity: source.diagnostic.severity.error, // CHECK_USER-NEXT: key.description: "use of unresolved identifier 'fooSubFunc'", // CHECK_USER-NOT: key.severity: + +// ----------------------------------------------------------------------------- +// Test that modifications for frameworks in '-Fsystem' doesn't affect the result +// across SourceKit sessions *if* '-disable-modules-validate-system-headers' is +// passed. + +// RUN: %empty-directory(%t/ModuleCache) +// RUN: %empty-directory(%t/System/Frameworks) +// RUN: cp -R %S/../Inputs/build_session/Frameworks/Foo.framework %t/System/Frameworks/ +// RUN: cp -R %S/../Inputs/build_session/Frameworks/FooHelper.framework %t/System/Frameworks/ +// RUN: %sourcekitd-test \ +// RUN: -shell -- echo '## ONE' == \ +// RUN: -req=sema %s -- %s -D ONE -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache -Xfrontend -disable-modules-validate-system-headers == \ +// RUN: -shell -- cp -R %S/../Inputs/build_session/Frameworks_modified/Foo.framework %t/System/Frameworks/ == \ +// RUN: -shell -- cp -R %S/../Inputs/build_session/Frameworks_modified/FooHelper.framework %t/System/Frameworks/ == \ +// RUN: -shell -- echo '## TWO' == \ +// RUN: -req=sema %s -- %s -D TWO -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache -Xfrontend -disable-modules-validate-system-headers \ +// RUN: | %FileCheck %s --check-prefix=CHECK_DISABLED +// RUN: sleep 2 +// RUN: %sourcekitd-test \ +// RUN: -shell -- echo '## THREE' == \ +// RUN: -req=sema %s -- %s -D THREE -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache -Xfrontend -disable-modules-validate-system-headers \ +// RUN: | %FileCheck %s --check-prefix=CHECK_DISABLED_2 + +// CHECK_DISABLED-LABEL: ## ONE +// CHECK_DISABLED-NOT: key.description + +// CHECK_DISABLED-LABEL: ## TWO +// CHECK_DISABLED-NOT: key.description + +// CHECK_DISABLED_2-LABEL: ## THREE +// CHECK_DISABLED_2-NOT: key.description diff --git a/test/SymbolGraph/Relationships/ConformsTo.swift b/test/SymbolGraph/Relationships/ConformsTo.swift deleted file mode 100644 index 0079b687c95f2..0000000000000 --- a/test/SymbolGraph/Relationships/ConformsTo.swift +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %empty-directory(%t) -// RUN: %target-build-swift %s -module-name ConformsTo -emit-module -emit-module-path %t/ -// RUN: %target-swift-symbolgraph-extract -module-name ConformsTo -I %t -pretty-print -output-dir %t -// RUN: %FileCheck %s --input-file %t/ConformsTo.symbols.json - -public protocol P { - var x: Int { get } -} - -public struct S: P { - public var x: Int -} - -// CHECK: "kind": "conformsTo" -// CHECK-NEXT: "source": "s:10ConformsTo1SV" -// CHECK-NEXT: "target": "s:10ConformsTo1PP" diff --git a/test/SymbolGraph/Relationships/ConformsTo/Basic.swift b/test/SymbolGraph/Relationships/ConformsTo/Basic.swift new file mode 100644 index 0000000000000..cc01c2770e266 --- /dev/null +++ b/test/SymbolGraph/Relationships/ConformsTo/Basic.swift @@ -0,0 +1,16 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name Basic -emit-module -emit-module-path %t/ +// RUN: %target-swift-symbolgraph-extract -module-name Basic -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/Basic.symbols.json + +public protocol P { + var x: Int { get } +} + +public struct S: P { + public var x: Int +} + +// CHECK: "kind": "conformsTo" +// CHECK-NEXT: "source": "s:5Basic1SV" +// CHECK-NEXT: "target": "s:5Basic1PP" diff --git a/test/SymbolGraph/Relationships/ConformsTo/Indirect.swift b/test/SymbolGraph/Relationships/ConformsTo/Indirect.swift new file mode 100644 index 0000000000000..8f24c851c03be --- /dev/null +++ b/test/SymbolGraph/Relationships/ConformsTo/Indirect.swift @@ -0,0 +1,23 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name Indirect -emit-module -emit-module-path %t/ +// RUN: %target-swift-symbolgraph-extract -module-name Indirect -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/Indirect.symbols.json + +public protocol P { + func foo() +} + +public protocol Q : P {} + +public struct S : Q { + public func foo() {} +} + +// Q : P +// CHECK-DAG: "kind": "conformsTo",{{[[:space:]]*}}"source": "s:8Indirect1QP",{{[[:space:]]*}}"target": "s:8Indirect1PP" + +// S : P +// CHECK-DAG: "kind": "conformsTo",{{[[:space:]]*}}"source": "s:8Indirect1SV",{{[[:space:]]*}}"target": "s:8Indirect1PP" + +// S : Q +// CHECK-DAG: "kind": "conformsTo",{{[[:space:]]*}}"source": "s:8Indirect1SV",{{[[:space:]]*}}"target": "s:8Indirect1QP" diff --git a/test/SymbolGraph/Relationships/DefaultImplementationOf.swift b/test/SymbolGraph/Relationships/DefaultImplementationOf/Basic.swift similarity index 100% rename from test/SymbolGraph/Relationships/DefaultImplementationOf.swift rename to test/SymbolGraph/Relationships/DefaultImplementationOf/Basic.swift diff --git a/test/SymbolGraph/Relationships/DefaultImplementationOf/Indirect.swift b/test/SymbolGraph/Relationships/DefaultImplementationOf/Indirect.swift new file mode 100644 index 0000000000000..7467a3ecec129 --- /dev/null +++ b/test/SymbolGraph/Relationships/DefaultImplementationOf/Indirect.swift @@ -0,0 +1,17 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name Indirect -emit-module -emit-module-path %t/ +// RUN: %target-swift-symbolgraph-extract -module-name Indirect -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/Indirect.symbols.json + +public protocol P { + associatedtype Thing + func foo() +} + +public protocol Q : P {} + +extension Q { + public func foo() {} +} + +// CHECK-DAG: "kind": "defaultImplementationOf",{{[[:space:]]*}}"source": "s:8Indirect1QPAAE3fooyyF",{{[[:space:]]*}}"target": "s:8Indirect1PP3fooyyF" diff --git a/test/decl/ext/sr_12460.swift b/test/decl/ext/sr_12460.swift new file mode 100644 index 0000000000000..a281d464639ee --- /dev/null +++ b/test/decl/ext/sr_12460.swift @@ -0,0 +1,9 @@ +// RUN: %target-swift-ide-test -print-indexed-symbols -source-filename %s 2>&1 | %FileCheck -check-prefix CHECK %s + +// Test that we don't crash when validating members inside an extension with no type name. + +// CHECK: :[[@LINE+1]]:11: error: expected type name in extension declaration +extension { + // CHECK: :[[@LINE+1]]:8: error: operator '==' declared in extension must be 'static' + func ==(lhs: Any, rhs: Any) -> Bool {} +} diff --git a/test/decl/var/property_wrappers_library_evolution.swift b/test/decl/var/property_wrappers_library_evolution.swift index 3a690c0913640..3a6163628995b 100644 --- a/test/decl/var/property_wrappers_library_evolution.swift +++ b/test/decl/var/property_wrappers_library_evolution.swift @@ -9,12 +9,12 @@ public struct ResilientWrapper { } } -func getHello() -> String { return "hello" } // expected-note 2 {{global function 'getHello()' is not '@usableFromInline' or public}} +func getHello() -> String { return "hello" } // expected-note {{global function 'getHello()' is not '@usableFromInline' or public}} @frozen public struct StructUsesPublishedAsPrivate { public var integer: Int = 17 - @ResilientWrapper(description: getHello()) // expected-error 2 {{global function 'getHello()' is internal and cannot be referenced from a property initializer in a '@frozen' type}} + @ResilientWrapper(description: getHello()) // expected-error {{global function 'getHello()' is internal and cannot be referenced from a property initializer in a '@frozen' type}} var otherString: String = "World" } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp index 92c8c42a42d3f..fe3b6b9a5d0cd 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp @@ -554,15 +554,20 @@ bool SwiftASTManager::initCompilerInvocation( // To save the time for module validation, consider the lifetime of ASTManager // as a single build session. - // 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"); - + // NOTE: Do this only if '-disable-modules-validate-system-headers' is *not* + // explicitly enabled. auto &SearchPathOpts = Invocation.getSearchPathOptions(); - SearchPathOpts.DisableModulesValidateSystemDependencies = true; + 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()); diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 7cb2516f936c6..5fce42e2a3c3a 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -1357,6 +1357,10 @@ skip-test-swiftsyntax skip-test-skstresstester skip-test-swiftevolve +extra-cmake-options= + -DCMAKE_C_FLAGS="-gline-tables-only" + -DCMAKE_CXX_FLAGS="-gline-tables-only" + #===------------------------------------------------------------------------===# # LLDB build configurations # @@ -1728,20 +1732,36 @@ sourcekit-lsp # Test IndexStore-DB #===------------------------------------------------------------------------===# -[preset: buildbot_indexstoredb_macos] +[preset: buildbot_indexstoredb_macos,no_sanitize] mixin-preset=mixin_swiftpm_package_macos_platform release assertions indexstore-db sourcekit-lsp -[preset: buildbot_indexstoredb_linux] +[preset: buildbot_indexstoredb_linux,no_sanitize] mixin-preset=mixin_swiftpm_package_linux_platform release assertions indexstore-db sourcekit-lsp +[preset: buildbot_indexstoredb_macos,sanitize] +mixin-preset=buildbot_indexstoredb_macos,no_sanitize +test-indexstore-db-sanitize-all + +[preset: buildbot_indexstoredb_linux,sanitize] +mixin-preset=buildbot_indexstoredb_linux,no_sanitize +test-indexstore-db-sanitize-all + +# Default: sanitize-all +[preset: buildbot_indexstoredb_macos] +mixin-preset=buildbot_indexstoredb_macos,sanitize + +# Default: sanitize-all +[preset: buildbot_indexstoredb_linux] +mixin-preset=buildbot_indexstoredb_linux,sanitize + #===------------------------------------------------------------------------===# # Test Swift Corelibs XCTest #===------------------------------------------------------------------------===# diff --git a/utils/build-script-impl b/utils/build-script-impl index bf199ffaa2ceb..dc01e0ad45f86 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -481,6 +481,10 @@ function set_build_options_for_host() { appletvsimulator-* | \ watchos-* | \ watchsimulator-*) + swift_cmake_options+=( + -DPython2_EXECUTABLE=$(xcrun -f python2.7) + -DPython3_EXECUTABLE=$(xcrun -f python3) + ) case ${host} in macosx-x86_64) SWIFT_HOST_TRIPLE="x86_64-apple-macosx${DARWIN_DEPLOYMENT_VERSION_OSX}" @@ -2822,10 +2826,12 @@ for host in "${ALL_HOSTS[@]}"; do # Run dsymutil on executables and shared libraries. # # Exclude shell scripts and static archives. + # Exclude swift-api-digester dSYM to reduce debug toolchain size. (cd "${INSTALL_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}) # Strip executables, shared libraries and static libraries in diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index ba5d6385a02b6..c6588946be7ee 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -567,6 +567,9 @@ def create_argument_parser(): option(['--indexstore-db'], toggle_true('build_indexstoredb'), help='build IndexStoreDB') + option('--test-indexstore-db-sanitize-all', + toggle_true('test_indexstoredb_sanitize_all'), + help='run indexstore-db tests under all sanitizers') option(['--sourcekit-lsp'], toggle_true('build_sourcekitlsp'), help='build SourceKitLSP') option('--install-swiftsyntax', toggle_true('install_swiftsyntax'), diff --git a/utils/build_swift/tests/expected_options.py b/utils/build_swift/tests/expected_options.py index d96780af67fcb..3b3660ed5770e 100644 --- a/utils/build_swift/tests/expected_options.py +++ b/utils/build_swift/tests/expected_options.py @@ -91,6 +91,7 @@ 'build_skstresstester': False, 'build_swiftevolve': False, 'build_indexstoredb': False, + 'test_indexstoredb_sanitize_all': False, 'build_sourcekitlsp': False, 'install_swiftpm': False, 'install_swiftsyntax': False, @@ -503,6 +504,8 @@ class BuildScriptImplOption(_BaseOption): EnableOption('--libdispatch', dest='build_libdispatch'), EnableOption('--libicu', dest='build_libicu'), EnableOption('--indexstore-db', dest='build_indexstoredb'), + EnableOption('--test-indexstore-db-sanitize-all', + dest='test_indexstoredb_sanitize_all'), EnableOption('--sourcekit-lsp', dest='build_sourcekitlsp'), EnableOption('--install-swiftsyntax', dest='install_swiftsyntax'), EnableOption('--swiftsyntax-verify-generated-files', diff --git a/utils/line-directive b/utils/line-directive index 0f6d05f07cddf..b12260be5da39 100755 --- a/utils/line-directive +++ b/utils/line-directive @@ -700,7 +700,7 @@ def run(): ':(?P[0-9]+):(?P[0-9]+):(?P.*?)\n?$') assertion_pattern = re.compile( - '^(?P.*( file | at |#[0-9]+: |[[]))' + + '^(?P.*( file | at |#[0-9]+: |[\[]))' + sources + '(?P, line |:)(?P[0-9]+)(?P.*?)\n?$') 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 f612df34ebc2c..6bd7d2b6f566f 100644 --- a/utils/swift_build_support/swift_build_support/products/indexstoredb.py +++ b/utils/swift_build_support/swift_build_support/products/indexstoredb.py @@ -36,7 +36,8 @@ def should_test(self, host_target): return self.args.test_indexstoredb def test(self, host_target): - run_build_script_helper('test', host_target, self, self.args) + run_build_script_helper('test', host_target, self, self.args, + self.args.test_indexstoredb_sanitize_all) def should_install(self, host_target): return False @@ -45,13 +46,13 @@ def install(self, host_target): pass -def run_build_script_helper(action, host_target, product, args): +def run_build_script_helper(action, host_target, product, args, + sanitize_all=False): script_path = os.path.join( product.source_dir, 'Utilities', 'build-script-helper.py') toolchain_path = targets.toolchain_path(args.install_destdir, args.install_prefix) - is_release = product.is_release() configuration = 'release' if is_release else 'debug' helper_cmd = [ @@ -66,4 +67,13 @@ def run_build_script_helper(action, host_target, product, args): if args.verbose_build: helper_cmd.append('--verbose') + if sanitize_all: + helper_cmd.append('--sanitize-all') + elif args.enable_asan: + helper_cmd.extend(['--sanitize', 'address']) + elif args.enable_ubsan: + helper_cmd.extend(['--sanitize', 'undefined']) + elif args.enable_tsan: + helper_cmd.extend(['--sanitize', 'thread']) + shell.call(helper_cmd)