Skip to content

Commit 44bac33

Browse files
Merge pull request #2904 from adrian-prantl/75905336-1-5.5
Support expression evaluation inside of actors.
2 parents 3162f20 + 683082f commit 44bac33

File tree

4 files changed

+67
-42
lines changed

4 files changed

+67
-42
lines changed

lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp

Lines changed: 30 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ extension %s$__lldb_context {
203203
%s
204204
}
205205
}
206-
%s
206+
@LLDBDebuggerFunction %s
207207
func $__lldb_expr(_ $__lldb_arg : UnsafeMutablePointer<Any>) {
208208
do {
209209
$__lldb_injected_self.$__lldb_wrapped_expr_%u(
@@ -255,63 +255,51 @@ void SwiftASTManipulatorBase::DoInitialization() {
255255
if (m_repl)
256256
return;
257257

258-
static llvm::StringRef s_func_prefix_str("$__lldb_expr");
258+
// First pass: find whether we're dealing with a wrapped function or not.
259259

260-
// First pass: find whether we're dealing with a wrapped function or not
261-
262-
class FuncAndExtensionFinder : public swift::ASTWalker {
263-
public:
264-
swift::FuncDecl *m_function_decl = nullptr; // This is the function in which
265-
// the expression code is
266-
// inserted.
267-
// It is always marked with the DebuggerFunction attribute.
268-
swift::ExtensionDecl *m_extension_decl =
269-
nullptr; // This is an optional extension holding the function
270-
swift::FuncDecl *m_wrapper_decl = nullptr; // This is an optional wrapper
271-
// function that calls
272-
// m_function_decl.
273-
llvm::StringRef m_wrapper_func_prefix; // This is the prefix name for the
274-
// wrapper function. One tricky bit
275-
// is that in the case where there is no wrapper, the m_function_decl
276-
// has this name. That's why we check first for the debugger attribute.
277-
278-
FuncAndExtensionFinder(llvm::StringRef &wrapped_func_prefix)
279-
: m_wrapper_func_prefix(wrapped_func_prefix) {}
260+
struct FuncAndExtensionFinder : public swift::ASTWalker {
261+
/// This is the toplevel entry function for the expression. It may
262+
/// call into \c ext_method_decl or hold the entire expression.
263+
swift::FuncDecl *toplevel_decl = nullptr;
264+
/// This is optional.
265+
swift::FuncDecl *ext_method_decl = nullptr;
266+
/// This is an optional extension holding the above function.
267+
swift::ExtensionDecl *extension_decl = nullptr;
280268

281269
bool walkToDeclPre(swift::Decl *D) override {
282270
auto *FD = llvm::dyn_cast<swift::FuncDecl>(D);
271+
// Traverse into any non-function-decls.
283272
if (!FD)
284273
return true;
285274

286-
if (FD->getAttrs().hasAttribute<swift::LLDBDebuggerFunctionAttr>()) {
287-
m_function_decl = FD;
275+
if (!FD->getAttrs().hasAttribute<swift::LLDBDebuggerFunctionAttr>())
276+
return false;
288277

289-
// Now walk back up the containing DeclContexts, and if we find an
290-
// extension Decl, that's our extension:
291-
for (swift::DeclContext *DC = m_function_decl->getDeclContext(); DC;
292-
DC = DC->getParent()) {
293-
if (auto *extension_decl = llvm::dyn_cast<swift::ExtensionDecl>(DC)) {
294-
m_extension_decl = extension_decl;
295-
break;
296-
}
278+
// Walk up the DeclContext chain, searching for an extension.
279+
for (auto *DC = FD->getDeclContext(); DC; DC = DC->getParent()) {
280+
if (auto *extension = llvm::dyn_cast<swift::ExtensionDecl>(DC)) {
281+
extension_decl = extension;
282+
ext_method_decl = FD;
283+
return false;
297284
}
298-
} else if (FD->hasName() && FD->getBaseIdentifier().str().startswith(
299-
m_wrapper_func_prefix)) {
300-
m_wrapper_decl = FD;
301285
}
302-
303-
// There's nothing buried in a function that we need to find in this
304-
// search.
286+
// Not in an extenstion,
287+
toplevel_decl = FD;
305288
return false;
306289
}
307290
};
308291

309-
FuncAndExtensionFinder func_finder(s_func_prefix_str);
292+
FuncAndExtensionFinder func_finder;
310293
m_source_file.walk(func_finder);
311294

312-
m_function_decl = func_finder.m_function_decl;
313-
m_wrapper_decl = func_finder.m_wrapper_decl;
314-
m_extension_decl = func_finder.m_extension_decl;
295+
m_extension_decl = func_finder.extension_decl;
296+
if (m_extension_decl) {
297+
m_function_decl = func_finder.ext_method_decl;
298+
m_wrapper_decl = func_finder.toplevel_decl;
299+
} else {
300+
m_function_decl = func_finder.toplevel_decl;
301+
m_wrapper_decl = nullptr;
302+
}
315303

316304
assert(m_function_decl);
317305

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFTFLAGS_EXTRAS := -Xfrontend -enable-experimental-concurrency -parse-as-library
3+
include Makefile.rules
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
import lldbsuite.test.lldbtest as lldbtest
4+
import lldbsuite.test.lldbutil as lldbutil
5+
import unittest2
6+
7+
8+
class TestSwiftAsyncExpressions(lldbtest.TestBase):
9+
10+
mydir = lldbtest.TestBase.compute_mydir(__file__)
11+
12+
@swiftTest
13+
@skipIfWindows
14+
@skipIfLinux
15+
@skipIf(archs=no_match(["arm64", "arm64e", "arm64_32", "x86_64"]))
16+
def test_actor(self):
17+
"""Test async unwind"""
18+
self.build()
19+
target, process, thread, main_bkpt = lldbutil.run_to_source_breakpoint(
20+
self, 'break here', lldb.SBFileSpec("main.swift"))
21+
self.expect("expr n", substrs=["42"])
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
actor Actor {
2+
func f(_ n : Int) async {
3+
print(n) // break here
4+
}
5+
}
6+
7+
8+
@main struct Main {
9+
static func main() async {
10+
let A = Actor()
11+
await A.f(42)
12+
}
13+
}

0 commit comments

Comments
 (0)