Skip to content

Commit b612aa6

Browse files
committed
[lldb] Implement support for constrained generics in generic expression
evaluator Evaluating an expression without binging generic parameters in a context where there are generics which are constrained to protocols require passing the protocol witness tables to the generated function. rdar://104446865
1 parent 94a95ed commit b612aa6

File tree

11 files changed

+307
-23
lines changed

11 files changed

+307
-23
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -879,8 +879,8 @@ swift::FuncDecl *SwiftASTManipulator::GetFunctionToInjectVariableInto(
879879
// pointers in the wrapper, so we can pass them as opaque pointers in the
880880
// trampoline function later on.
881881
if (!ShouldBindGenericTypes(m_bind_generic_types) &&
882-
(variable.IsMetadataPointer() || variable.IsPackCount() ||
883-
variable.IsUnboundPack()))
882+
(variable.IsMetadataPointer() || variable.IsWitnessTable() ||
883+
variable.IsPackCount() || variable.IsUnboundPack()))
884884
return m_entrypoint_decl;
885885

886886
return m_function_decl;

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ class SwiftASTManipulatorBase {
103103

104104
struct VariableInfo {
105105
CompilerType GetType() const { return m_type; }
106+
/// The unbound swift::Type. Unbound means that the generic type parameters
107+
/// are not substituted (for example, Array<T> instead of Array<Int>). Only
108+
/// valid the the variable that represents self when evaluating the
109+
/// expression without the generic types.
110+
const swift::Type &GetUnboundType() const { return m_unbound_type; }
106111
swift::Identifier GetName() const { return m_name; }
107112
VariableMetadata *GetMetadata() const { return m_metadata.get(); }
108113
void TakeMetadata(VariableMetadata *vmd) { m_metadata.reset(vmd); }
@@ -113,6 +118,7 @@ class SwiftASTManipulatorBase {
113118
bool IsOutermostMetadataPointer() const {
114119
return m_name.str().starts_with("$τ_0_");
115120
}
121+
bool IsWitnessTable() const { return m_name.str().starts_with("$WT"); }
116122
bool IsSelf() const {
117123
return m_name.str() == "$__lldb_injected_self";
118124
}
@@ -125,14 +131,16 @@ class SwiftASTManipulatorBase {
125131
VariableInfo(CompilerType type, swift::Identifier name,
126132
VariableMetadataSP metadata,
127133
swift::VarDecl::Introducer introducer,
128-
bool is_capture_list = false, bool is_unbound_pack = false)
129-
: m_type(type), m_name(name), m_metadata(metadata),
130-
m_var_introducer(introducer), m_is_capture_list(is_capture_list),
134+
bool is_capture_list = false, bool is_unbound_pack = false,
135+
swift::Type unbound_type = {})
136+
: m_type(type), m_unbound_type(unbound_type), m_name(name),
137+
m_metadata(metadata), m_var_introducer(introducer),
138+
m_is_capture_list(is_capture_list),
131139
m_is_unbound_pack(is_unbound_pack) {}
132140
VariableInfo(const VariableInfo &other)
133-
: m_type(other.m_type), m_name(other.m_name),
134-
m_metadata(other.m_metadata), m_decl(other.m_decl),
135-
m_var_introducer(other.m_var_introducer),
141+
: m_type(other.m_type), m_unbound_type(other.m_unbound_type),
142+
m_name(other.m_name), m_metadata(other.m_metadata),
143+
m_decl(other.m_decl), m_var_introducer(other.m_var_introducer),
136144
m_lookup_error(other.m_lookup_error.Clone()),
137145
m_is_capture_list(other.m_is_capture_list),
138146
m_is_unbound_pack(other.m_is_unbound_pack) {}
@@ -150,6 +158,7 @@ class SwiftASTManipulatorBase {
150158
m_lookup_error = other.m_lookup_error.Clone();
151159
m_is_capture_list = other.m_is_capture_list;
152160
m_is_unbound_pack = other.m_is_unbound_pack;
161+
m_unbound_type = other.m_unbound_type;
153162
return *this;
154163
}
155164

@@ -165,6 +174,7 @@ class SwiftASTManipulatorBase {
165174

166175
protected:
167176
CompilerType m_type;
177+
swift::Type m_unbound_type;
168178
swift::Identifier m_name;
169179
VariableMetadataSP m_metadata;
170180
swift::VarDecl *m_decl = nullptr;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,7 @@ AddArchetypeTypeAliases(std::unique_ptr<SwiftASTManipulator> &code_manipulator,
11791179
llvm::SmallDenseMap<llvm::StringRef, MetadataPointerInfo>
11801180
visible_metadata_pointers;
11811181
for (auto &variable : code_manipulator->GetVariableInfo()) {
1182-
if (!variable.IsMetadataPointer())
1182+
if (!variable.IsMetadataPointer() && !variable.IsWitnessTable())
11831183
continue;
11841184

11851185
llvm::StringRef type_name;

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

Lines changed: 165 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "lldb/Target/Target.h"
1919
#include "lldb/Utility/StreamString.h"
2020

21+
#include "swift/AST/ASTContext.h"
22+
#include "swift/AST/ASTMangler.h"
2123
#include "swift/Basic/LangOptions.h"
2224
#include "swift/Demangling/Demangle.h"
2325
#include "swift/Demangling/Demangler.h"
@@ -30,8 +32,11 @@ using namespace lldb_private;
3032

3133
namespace lldb_private {
3234
std::optional<std::pair<unsigned, unsigned>>
33-
ParseSwiftGenericParameter(llvm::StringRef name) {
34-
if (!name.consume_front("$τ_"))
35+
ParseSwiftGenericParameter(llvm::StringRef name, bool expect_dollar_prefix) {
36+
if (expect_dollar_prefix && !name.consume_front("$"))
37+
return {};
38+
39+
if (!name.consume_front("τ_"))
3540
return {};
3641

3742
auto pair = name.split('_');
@@ -165,6 +170,127 @@ static llvm::Expected<llvm::SmallVector<MetadataInfo>> CollectMetadataInfos(
165170
}
166171
return metadata_info;
167172
}
173+
174+
/// Returns a map from the index and depth to the archetype name, for example,
175+
/// given: struct S<T, U> {} This function returns {{0, 0} -> T, {0, 1} -> U}.
176+
static llvm::DenseMap<std::pair<unsigned, unsigned>, llvm::StringRef>
177+
MakeIndexAndDepthToArchetypeMap(
178+
llvm::ArrayRef<swift::Requirement> requirements) {
179+
llvm::DenseMap<std::pair<unsigned, unsigned>, llvm::StringRef> map;
180+
for (auto &req : requirements) {
181+
if (req.getKind() != swift::RequirementKind::Conformance)
182+
continue;
183+
auto type = req.getFirstType();
184+
auto *generic_type =
185+
llvm::dyn_cast<swift::GenericTypeParamType>(type.getPointer());
186+
if (!generic_type)
187+
continue;
188+
189+
unsigned depth = generic_type->getDepth();
190+
unsigned index = generic_type->getIndex();
191+
auto name = generic_type->getName().str();
192+
map.insert({{depth, index}, name});
193+
}
194+
return map;
195+
}
196+
197+
struct ParsedWitnessTable {
198+
/// The full name of the variable in debug info. For example:
199+
/// $WTτ_0_0$SubType$$MangledProtocol.
200+
llvm::StringRef full_name;
201+
/// The archetype name, for example T.SubType
202+
std::string archetype_name;
203+
/// The mangled protocol name.
204+
llvm::StringRef mangled_protocol_name;
205+
/// The "display" protocol name.
206+
std::string protocol_name;
207+
ParsedWitnessTable(llvm::StringRef full_name, std::string archetype_name,
208+
llvm::StringRef mangled_protocol_name,
209+
std::string protocol_name)
210+
: full_name(full_name), archetype_name(archetype_name),
211+
mangled_protocol_name(mangled_protocol_name),
212+
protocol_name(protocol_name) {}
213+
};
214+
215+
/// Parses the witness table artificial variables.
216+
static llvm::Expected<llvm::SmallVector<ParsedWitnessTable>> ParseWitnessInfos(
217+
llvm::ArrayRef<SwiftASTManipulator::VariableInfo> local_variables,
218+
llvm::ArrayRef<swift::Requirement> requirements) {
219+
llvm::SmallVector<ParsedWitnessTable> witness_tables;
220+
auto indexes_to_archetype = MakeIndexAndDepthToArchetypeMap(requirements);
221+
for (auto &local_variable : local_variables) {
222+
if (!local_variable.IsWitnessTable())
223+
continue;
224+
225+
// Full name looks something like "$WTτ_0_0$SubType$$MangledProtocol.".
226+
auto full_name = local_variable.GetName().str();
227+
auto [metadata_name, mangled_protocol_name] = full_name.split("$$");
228+
229+
if (metadata_name.empty() || mangled_protocol_name.empty() ||
230+
!SwiftLanguageRuntime::IsSwiftMangledName(mangled_protocol_name))
231+
return llvm::createStringError(
232+
"malformed witness table name in debug info");
233+
234+
metadata_name = metadata_name.drop_front(StringRef("$WT").size());
235+
auto [front, back] = metadata_name.split('$');
236+
auto maybe_depth_and_index =
237+
ParseSwiftGenericParameter(front, /*expect_dollar_prefix*/ false);
238+
if (!maybe_depth_and_index)
239+
return llvm::createStringError(
240+
"malformed witness table name in debug info");
241+
242+
auto [depth, index] = *maybe_depth_and_index;
243+
244+
auto it = indexes_to_archetype.find({depth, index});
245+
if (it == indexes_to_archetype.end())
246+
return llvm::createStringError(
247+
"malformed witness table name in debug info");
248+
249+
std::string archetype_name = it->getSecond().str();
250+
if (!back.empty())
251+
archetype_name += "." + back.str();
252+
std::replace(archetype_name.begin(), archetype_name.end(), '$', '.');
253+
auto protocol_name =
254+
swift::Demangle::demangleSymbolAsString(mangled_protocol_name);
255+
witness_tables.emplace_back(full_name, archetype_name,
256+
mangled_protocol_name, protocol_name);
257+
}
258+
259+
// Order the witness tables according to the requirements, otherwise we risk
260+
// passing the witness table pointers in the wrong order when generating the
261+
// expression.
262+
llvm::SmallVector<ParsedWitnessTable> ordered_witness_tables;
263+
for (auto &Requirement : requirements) {
264+
if (Requirement.getKind() != swift::RequirementKind::Conformance)
265+
continue;
266+
swift::ProtocolDecl *ProtocolDecl = Requirement.getProtocolDecl();
267+
auto protocol_type = ProtocolDecl->getDeclaredType();
268+
auto type = Requirement.getFirstType();
269+
auto &ast_ctx = type->getASTContext();
270+
swift::Mangle::ASTMangler mangler(ast_ctx, true);
271+
std::string mangled_protocol_name =
272+
mangler.mangleTypeForDebugger(protocol_type, nullptr);
273+
std::string name;
274+
if (auto *generic_type =
275+
llvm::dyn_cast<swift::GenericTypeParamType>(type.getPointer()))
276+
name = generic_type->getName().str();
277+
else if (auto *dependent =
278+
llvm::dyn_cast<swift::DependentMemberType>(type.getPointer()))
279+
name = dependent->getString();
280+
281+
for (auto &parsed_witness_table : witness_tables) {
282+
if (name == parsed_witness_table.archetype_name &&
283+
mangled_protocol_name == parsed_witness_table.mangled_protocol_name) {
284+
ordered_witness_tables.emplace_back(std::move(parsed_witness_table));
285+
}
286+
}
287+
}
288+
assert(ordered_witness_tables.size() == witness_tables.size() &&
289+
"Ordered witness table size does not match");
290+
291+
return ordered_witness_tables;
292+
}
293+
168294
/// Constructs the signatures for the expression evaluation functions based on
169295
/// the metadata variables in scope and any variadic functiontion parameters.
170296
/// For every outermost metadata pointer in scope ($τ_0_0, $τ_0_1, etc), we want
@@ -208,10 +334,27 @@ static llvm::Expected<CallsAndArgs> MakeGenericSignaturesAndCalls(
208334
return llvm::createStringError(llvm::errc::not_supported,
209335
"Inconsistent generic signature");
210336

211-
auto maybe_metadata_infos = CollectMetadataInfos(metadata_variables, generic_sig);
212-
if (!maybe_metadata_infos)
213-
return maybe_metadata_infos.takeError();
214-
auto metadata_infos = *maybe_metadata_infos;
337+
auto self = llvm::find_if(
338+
local_variables, [](const SwiftASTManipulator::VariableInfo &variable) {
339+
return variable.IsSelf();
340+
});
341+
llvm::SmallVector<ParsedWitnessTable> witness_infos;
342+
if (self && self->GetUnboundType()) {
343+
auto bound_generic = llvm::cast<swift::NominalOrBoundGenericNominalType>(
344+
self->GetUnboundType().getPointer());
345+
auto decl = bound_generic->getDecl();
346+
auto requirements = decl->getGenericRequirements();
347+
auto witness_infos_or_err = ParseWitnessInfos(local_variables, requirements);
348+
if (!witness_infos_or_err)
349+
return witness_infos_or_err.takeError();
350+
witness_infos = *witness_infos_or_err;
351+
}
352+
353+
auto metatada_infos_or_err =
354+
CollectMetadataInfos(metadata_variables, generic_sig);
355+
if (!metatada_infos_or_err)
356+
return metatada_infos_or_err.takeError();
357+
auto metadata_infos = *metatada_infos_or_err;
215358

216359
llvm::SmallDenseMap<std::pair<unsigned, unsigned>, llvm::SmallString<4>> subs;
217360
std::string generic_params;
@@ -230,11 +373,17 @@ static llvm::Expected<CallsAndArgs> MakeGenericSignaturesAndCalls(
230373
s_generic_params << sig_archetype_name << ",";
231374
subs.insert({{depth, index}, sig_archetype_name});
232375
}
376+
std::string type_constraints;
377+
llvm::raw_string_ostream s_type_constraints(type_constraints);
378+
for (auto &wi : witness_infos)
379+
s_type_constraints << wi.archetype_name << ": " << wi.protocol_name << ",";
233380

234381
if (!generic_params.empty())
235382
generic_params.pop_back();
236383
if (!generic_params_no_packs.empty())
237384
generic_params_no_packs.pop_back();
385+
if (!type_constraints.empty())
386+
type_constraints.pop_back();
238387

239388
std::string user_expr;
240389
llvm::raw_string_ostream user_expr_stream(user_expr);
@@ -250,6 +399,8 @@ static llvm::Expected<CallsAndArgs> MakeGenericSignaturesAndCalls(
250399
<< *pack_type;
251400
}
252401
user_expr_stream << ")";
402+
if (!type_constraints.empty())
403+
user_expr_stream << "where " << type_constraints;
253404

254405
std::string trampoline;
255406
llvm::raw_string_ostream trampoline_stream(trampoline);
@@ -259,6 +410,8 @@ static llvm::Expected<CallsAndArgs> MakeGenericSignaturesAndCalls(
259410
if (needs_object_ptr)
260411
trampoline_stream << ", _ $__lldb_injected_self: inout $__lldb_context";
261412
trampoline_stream << ")";
413+
if (!type_constraints.empty())
414+
trampoline_stream << "where " << type_constraints;
262415

263416
std::string sink;
264417
std::string call;
@@ -291,6 +444,12 @@ static llvm::Expected<CallsAndArgs> MakeGenericSignaturesAndCalls(
291444
sink_stream << ", _: $__lldb_builtin_ptr_t";
292445
call_stream << ", " << var->GetName().str();
293446
}
447+
448+
for (auto &wi : witness_infos) {
449+
sink_stream << ", _: $__lldb_builtin_ptr_t";
450+
call_stream << ", " << wi.full_name;
451+
}
452+
294453
sink_stream << ")";
295454
call_stream << ")";
296455

lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionSourceCode.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ namespace lldb_private {
1919

2020
/// Parse a name such as "$τ_0_0".
2121
std::optional<std::pair<unsigned, unsigned>>
22-
ParseSwiftGenericParameter(llvm::StringRef name);
22+
ParseSwiftGenericParameter(llvm::StringRef name,
23+
bool expect_dollar_prefix = true);
2324

2425
class SwiftExpressionSourceCode : public ExpressionSourceCode {
2526
public:

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ static llvm::Error AddVariableInfo(
327327
return llvm::Error::success();
328328

329329
CompilerType target_type;
330+
swift::Type unbound_type;
330331
bool should_not_bind_generic_types =
331332
!SwiftASTManipulator::ShouldBindGenericTypes(bind_generic_types);
332333
bool is_unbound_pack =
@@ -338,11 +339,17 @@ static llvm::Error AddVariableInfo(
338339
// opaque pointer type. This is necessary because we don't bind the generic
339340
// parameters, and we can't have a type with unbound generics in a non-generic
340341
// function.
341-
if (should_not_bind_generic_types && is_self)
342+
if (should_not_bind_generic_types && is_self) {
342343
target_type = ast_context.GetBuiltinRawPointerType();
343-
else if (is_unbound_pack)
344+
CompilerType var_type = SwiftExpressionParser::ResolveVariable(
345+
variable_sp, stack_frame_sp, runtime, use_dynamic, bind_generic_types);
346+
if (auto unbound_type_or_err = ast_context.GetSwiftType(var_type))
347+
unbound_type = *unbound_type_or_err;
348+
else
349+
return unbound_type_or_err.takeError();
350+
} else if (is_unbound_pack) {
344351
target_type = variable_sp->GetType()->GetForwardCompilerType();
345-
else {
352+
} else {
346353
CompilerType var_type = SwiftExpressionParser::ResolveVariable(
347354
variable_sp, stack_frame_sp, runtime, use_dynamic, bind_generic_types);
348355

@@ -433,7 +440,7 @@ static llvm::Error AddVariableInfo(
433440
metadata_sp,
434441
variable_sp->IsConstant() ? swift::VarDecl::Introducer::Let
435442
: swift::VarDecl::Introducer::Var,
436-
false, is_unbound_pack);
443+
false, is_unbound_pack, unbound_type);
437444
processed_variables.insert(overridden_name);
438445
return llvm::Error::success();
439446
}

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4863,6 +4863,7 @@ bool TypeSystemSwiftTypeRef::DumpTypeValue(
48634863
format = eFormatPointer;
48644864
LLVM_FALLTHROUGH;
48654865
case Node::Kind::BuiltinTypeName:
4866+
case Node::Kind::DependentMemberType:
48664867
case Node::Kind::DependentGenericParamType:
48674868
case Node::Kind::FunctionType:
48684869
case Node::Kind::NoEscapeFunctionType:

0 commit comments

Comments
 (0)