Skip to content

Commit 98a6c03

Browse files
committed
Eliminate unnecessary SwiftASTContext fallback in GetIndexOfChildMemberWithName().
Enums without payloads are not supposed to have children in the LLDB data formatter sense, so GetIndexOfChildMemberWithName should return 0. However previously we couldn't distinguish between SwiftLanguageRuntime failing to look up a type and a success where the match was a non-payload enum member.
1 parent 81db3d7 commit 98a6c03

File tree

7 files changed

+87
-48
lines changed

7 files changed

+87
-48
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ class SwiftLanguageRuntimeStub {
299299
return {};
300300
}
301301

302-
llvm::Optional<size_t> GetIndexOfChildMemberWithName(
302+
std::pair<bool, llvm::Optional<size_t>> GetIndexOfChildMemberWithName(
303303
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
304304
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
305305
STUB_LOG();
@@ -2209,7 +2209,8 @@ llvm::Optional<std::string> SwiftLanguageRuntime::GetEnumCaseName(
22092209
FORWARD(GetEnumCaseName, type, data, exe_ctx);
22102210
}
22112211

2212-
llvm::Optional<size_t> SwiftLanguageRuntime::GetIndexOfChildMemberWithName(
2212+
std::pair<bool, llvm::Optional<size_t>>
2213+
SwiftLanguageRuntime::GetIndexOfChildMemberWithName(
22132214
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
22142215
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
22152216
FORWARD(GetIndexOfChildMemberWithName, type, name, exe_ctx,

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,17 @@ class SwiftLanguageRuntime : public LanguageRuntime {
280280
const DataExtractor &data,
281281
ExecutionContext *exe_ctx);
282282

283-
llvm::Optional<size_t> GetIndexOfChildMemberWithName(
283+
/// Behaves like the CompilerType::GetIndexOfChildMemberWithName()
284+
/// except for the more nuanced return value.
285+
///
286+
/// \returns {false, {}} on error.
287+
//
288+
/// \returns {true, {}} if the member exists, but it is an enum case
289+
/// without payload. Enum cases without payload
290+
/// don't have an index.
291+
///
292+
/// \returns {true, {num_idexes}} on success.
293+
std::pair<bool, llvm::Optional<size_t>> GetIndexOfChildMemberWithName(
284294
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
285295
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes);
286296

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,26 +1073,32 @@ GetTypeFromTypeRef(TypeSystemSwiftTypeRef &ts,
10731073
return ts.RemangleAsType(dem, node);
10741074
}
10751075

1076-
static llvm::Optional<size_t>
1076+
static std::pair<bool, llvm::Optional<size_t>>
10771077
findFieldWithName(const std::vector<swift::reflection::FieldInfo> &fields,
1078-
llvm::StringRef name, std::vector<uint32_t> &child_indexes,
1079-
uint32_t offset = 0) {
1078+
llvm::StringRef name, bool is_enum,
1079+
std::vector<uint32_t> &child_indexes, uint32_t offset = 0) {
10801080
uint32_t index = 0;
1081+
bool is_nonpayload_enum_case = false;
10811082
auto it = std::find_if(fields.begin(), fields.end(), [&](const auto &field) {
1082-
// A nonnull TypeRef is required for enum cases, where it represents cases
1083-
// that have a payload. In other types it will be true anyway.
1084-
if (field.TR == nullptr)
1085-
return false;
10861083
if (name != field.Name) {
1087-
++index;
1084+
// A nonnull TypeRef is required for enum cases, where it represents cases
1085+
// that have a payload. In other types it will be true anyway.
1086+
if (field.TR)
1087+
++index;
10881088
return false;
10891089
}
1090+
if (is_enum)
1091+
is_nonpayload_enum_case = (field.TR == nullptr);
10901092
return true;
10911093
});
1094+
// Not found.
10921095
if (it == fields.end())
1093-
return {};
1096+
return {false, {}};
1097+
// Found, but no index to report.
1098+
if (is_nonpayload_enum_case)
1099+
return {true, {}};
10941100
child_indexes.push_back(offset + index);
1095-
return child_indexes.size();
1101+
return {true, child_indexes.size()};
10961102
}
10971103

10981104
static llvm::Optional<std::string>
@@ -1136,21 +1142,22 @@ llvm::Optional<std::string> SwiftLanguageRuntimeImpl::GetEnumCaseName(
11361142
return {};
11371143
}
11381144

1139-
llvm::Optional<size_t> SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
1145+
std::pair<bool, llvm::Optional<size_t>>
1146+
SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
11401147
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
11411148
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
11421149
LLDB_SCOPED_TIMER();
11431150
auto *ts =
11441151
llvm::dyn_cast_or_null<TypeSystemSwiftTypeRef>(type.GetTypeSystem());
11451152
if (!ts)
1146-
return {};
1153+
return {false, {}};
11471154

11481155
using namespace swift::reflection;
11491156
// Try the static type metadata.
11501157
const TypeRef *tr = nullptr;
11511158
auto *ti = GetSwiftRuntimeTypeInfo(type, exe_ctx->GetFramePtr(), &tr);
11521159
if (!ti)
1153-
return {};
1160+
return {false, {}};
11541161
switch (ti->getKind()) {
11551162
case TypeInfoKind::Record: {
11561163
// Structs and Tuples.
@@ -1160,7 +1167,7 @@ llvm::Optional<size_t> SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
11601167
case RecordKind::ThickFunction:
11611168
// There are two fields, `function` and `context`, but they're not exposed
11621169
// by lldb.
1163-
return 0;
1170+
return {true, {0}};
11641171
case RecordKind::OpaqueExistential:
11651172
// `OpaqueExistential` is documented as:
11661173
// An existential is a three-word buffer followed by value metadata...
@@ -1170,17 +1177,17 @@ llvm::Optional<size_t> SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
11701177
uint32_t index;
11711178
if (name.take_back().getAsInteger(10, index) && index < 3) {
11721179
child_indexes.push_back(index);
1173-
return child_indexes.size();
1180+
return {true, child_indexes.size()};
11741181
}
11751182
}
1176-
return findFieldWithName(rti->getFields(), name, child_indexes, 3);
1183+
return findFieldWithName(rti->getFields(), name, false, child_indexes, 3);
11771184
default:
1178-
return findFieldWithName(rti->getFields(), name, child_indexes);
1185+
return findFieldWithName(rti->getFields(), name, false, child_indexes);
11791186
}
11801187
}
11811188
case TypeInfoKind::Enum: {
11821189
auto *eti = llvm::cast<EnumTypeInfo>(ti);
1183-
return findFieldWithName(eti->getCases(), name, child_indexes);
1190+
return findFieldWithName(eti->getCases(), name, true, child_indexes);
11841191
}
11851192
case TypeInfoKind::Reference: {
11861193
// Objects.
@@ -1207,20 +1214,21 @@ llvm::Optional<size_t> SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
12071214
break;
12081215
auto *super_tr = builder.lookupSuperclass(current_tr);
12091216
uint32_t offset = super_tr ? 1 : 0;
1210-
if (auto size = findFieldWithName(record_ti->getFields(), name,
1211-
child_indexes, offset))
1212-
return size;
1217+
auto found_size = findFieldWithName(record_ti->getFields(), name, false,
1218+
child_indexes, offset);
1219+
if (found_size.first)
1220+
return found_size;
12131221
current_tr = super_tr;
12141222
child_indexes.push_back(0);
12151223
}
12161224
child_indexes.clear();
1217-
return {};
1225+
return {false, {}};
12181226
}
12191227
}
12201228
}
12211229
default:
12221230
// FIXME: Implement more cases.
1223-
return {};
1231+
return {false, {}};
12241232
}
12251233
}
12261234

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeImpl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ class SwiftLanguageRuntimeImpl {
131131
const DataExtractor &data,
132132
ExecutionContext *exe_ctx);
133133

134-
llvm::Optional<size_t> GetIndexOfChildMemberWithName(
134+
std::pair<bool, llvm::Optional<size_t>> GetIndexOfChildMemberWithName(
135135
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
136136
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes);
137137

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

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,27 +2802,29 @@ size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName(
28022802
child_indexes));
28032803
if (auto *exe_scope = exe_ctx->GetBestExecutionContextScope())
28042804
if (auto *runtime =
2805-
SwiftLanguageRuntime::Get(exe_scope->CalculateProcess()))
2806-
if (auto index_size = runtime->GetIndexOfChildMemberWithName(
2807-
GetCanonicalType(type), name, exe_ctx, omit_empty_base_classes,
2808-
child_indexes)) {
2805+
SwiftLanguageRuntime::Get(exe_scope->CalculateProcess())) {
2806+
auto found_numidx = runtime->GetIndexOfChildMemberWithName(
2807+
GetCanonicalType(type), name, exe_ctx, omit_empty_base_classes,
2808+
child_indexes);
2809+
if (found_numidx.first) {
2810+
size_t index_size = found_numidx.second.getValueOr(0);
28092811
#ifndef NDEBUG
28102812
// This block is a custom VALIDATE_AND_RETURN implementation to support
28112813
// checking the return value, plus the by-ref `child_indexes`.
28122814
if (!GetSwiftASTContext())
2813-
return *index_size;
2815+
return index_size;
28142816
auto ast_type = ReconstructType(type);
28152817
if (!ast_type)
2816-
return *index_size;
2818+
return index_size;
28172819
std::vector<uint32_t> ast_child_indexes;
28182820
auto ast_index_size =
28192821
GetSwiftASTContext()->GetIndexOfChildMemberWithName(
28202822
ast_type, name, exe_ctx, omit_empty_base_classes,
28212823
ast_child_indexes);
28222824
// The runtime has more info than the AST. No useful validation can be
28232825
// done.
2824-
if (*index_size > ast_index_size)
2825-
return *index_size;
2826+
if (index_size > ast_index_size)
2827+
return index_size;
28262828

28272829
auto fail = [&]() {
28282830
auto join = [](const auto &v) {
@@ -2841,17 +2843,20 @@ size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName(
28412843
assert(false &&
28422844
"TypeSystemSwiftTypeRef diverges from SwiftASTContext");
28432845
};
2844-
if (*index_size != ast_index_size)
2846+
if (index_size != ast_index_size)
28452847
fail();
2846-
for (unsigned i = 0; i < *index_size; ++i)
2848+
for (unsigned i = 0; i < index_size; ++i)
28472849
if (child_indexes[i] < ast_child_indexes[i])
28482850
// When the runtime may know know about more children. When this
28492851
// happens, indexes will be larger. But if an index is smaller, that
28502852
// means the runtime has dropped info somehow.
28512853
fail();
28522854
#endif
2853-
return *index_size;
2855+
return index_size;
28542856
}
2857+
// If we're here, the runtime didn't find type info.
2858+
assert(!found_numidx.first);
2859+
}
28552860

28562861
LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES),
28572862
"Using SwiftASTContext::GetIndexOfChildMemberWithName fallback for "

lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
import NoSwiftmoduleHelper
22

33
// The struct is resolved using type metadata and the Swift runtime.
4-
struct s { let i = 0 }
4+
struct S { let i = 0 }
55

66
func useTypeFromOtherModule(x: S2) {
77
// break here
88
}
99

10+
enum NoPayload {
11+
case first
12+
case second
13+
}
14+
15+
enum WithPayload {
16+
case empty
17+
case with(i: Int)
18+
}
19+
1020
func f<T>(_ t: T) {
11-
let number = 1 // CHECK-DAG: (Int) number = 1
12-
let array = [1, 2, 3] // CHECK-DAG: ([Int]) array = 3 values
13-
let string = "hello" // CHECK-DAG: (String) string = "hello"
14-
let tuple = (0, 1) // CHECK-DAG: (Int, Int) tuple = (0 = 0, 1 = 1)
15-
let strct = s() // CHECK-DAG: strct = (i = 0)
16-
let strct2 = S2() // CHECK-DAG: strct2 = {}{{$}}
17-
let generic = t // CHECK-DAG: (Int) generic = 23
18-
let generic_tuple = (t, t) // CHECK-DAG: generic_tuple = (0 = 23, 1 = 23)
19-
let word = 0._builtinWordValue // CHECK-DAG: word = 0
21+
let number = 1 // CHECK-DAG: (Int) number {{=}} 1
22+
let array = [1, 2, 3] // CHECK-DAG: ([Int]) array {{=}} 3 values
23+
let string = "hello" // CHECK-DAG: (String) string {{=}} "hello"
24+
let tuple = (0, 1) // CHECK-DAG: (Int, Int) tuple {{=}} (0 = 0, 1 = 1)
25+
let strct = S() // CHECK-DAG: strct {{=}} (i = 0)
26+
let strct2 = S2() // CHECK-DAG: strct2 {{=}} {}{{$}}
27+
let generic = t // CHECK-DAG: (Int) generic {{=}} 23
28+
let generic_tuple = (t, t) // CHECK-DAG: generic_tuple {{=}} (0 = 23, 1 = 23)
29+
let word = 0._builtinWordValue // CHECK-DAG: word {{=}} 0
30+
let enum1 = NoPayload.second // CHECK-DAG: enum1 {{=}}
31+
// FIXME: Fails in swift::reflection::NoPayloadEnumTypeInfo::projectEnumValue: .second
32+
let enum2 = WithPayload.with(i:42) // CHECK-DAG: enum2 {{=}} with
33+
// CHECK-DAG: i {{=}} 42
2034
print(number)
2135
useTypeFromOtherModule(x: S2())
2236
}

lldb/test/Shell/Swift/No.swiftmodule.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ run
2727
fr var
2828
up
2929
fr var
30+
quit

0 commit comments

Comments
 (0)