@@ -61,16 +61,26 @@ class SwiftDispatcher {
61
61
62
62
template <typename Entry>
63
63
void emit (Entry&& entry) {
64
- entry.forEachLabel ([&entry](const char * field, int index, auto & label) {
64
+ bool valid = true ;
65
+ entry.forEachLabel ([&valid, &entry, this ](const char * field, int index, auto & label) {
66
+ using Label = std::remove_reference_t <decltype (label)>;
65
67
if (!label.valid ()) {
66
68
std::cerr << entry.NAME << " has undefined " << field;
67
69
if (index >= 0 ) {
68
70
std::cerr << ' [' << index << ' ]' ;
69
71
}
70
- std::cerr << ' \n ' ;
72
+ if constexpr (std::is_base_of_v<typename Label::Tag, UnspecifiedElementTag>) {
73
+ std::cerr << " , replacing with unspecified element\n " ;
74
+ label = emitUnspecified (idOf (entry), field, index);
75
+ } else {
76
+ std::cerr << " , skipping emission\n " ;
77
+ valid = false ;
78
+ }
71
79
}
72
80
});
73
- trap.emit (entry);
81
+ if (valid) {
82
+ trap.emit (entry);
83
+ }
74
84
}
75
85
76
86
template <typename Entry>
@@ -97,13 +107,39 @@ class SwiftDispatcher {
97
107
emit (ElementIsUnknownTrap{label});
98
108
}
99
109
110
+ TrapLabel<UnspecifiedElementTag> emitUnspecified (std::optional<TrapLabel<ElementTag>>&& parent,
111
+ const char * property,
112
+ int index) {
113
+ UnspecifiedElement entry{trap.createLabel <UnspecifiedElementTag>()};
114
+ entry.error = " element was unspecified by the extractor" ;
115
+ entry.parent = std::move (parent);
116
+ entry.property = property;
117
+ if (index >= 0 ) {
118
+ entry.index = index;
119
+ }
120
+ trap.emit (entry);
121
+ return entry.id ;
122
+ }
123
+
124
+ template <typename E>
125
+ std::optional<TrapLabel<ElementTag>> idOf (const E& entry) {
126
+ if constexpr (HasId<E>::value) {
127
+ return entry.id ;
128
+ } else {
129
+ return std::nullopt;
130
+ }
131
+ }
132
+
100
133
// This method gives a TRAP label for already emitted AST node.
101
134
// If the AST node was not emitted yet, then the emission is dispatched to a corresponding
102
135
// visitor (see `visit(T *)` methods below).
103
136
template <typename E, typename ... Args, std::enable_if_t <IsStorable<E>>* = nullptr >
104
137
TrapLabelOf<E> fetchLabel (const E& e, Args&&... args) {
105
138
if constexpr (std::is_constructible_v<bool , const E&>) {
106
- assert (e && " fetching a label on a null entity, maybe fetchOptionalLabel is to be used?" );
139
+ if (!e) {
140
+ // this will be treated on emission
141
+ return undefined_label;
142
+ }
107
143
}
108
144
// this is required so we avoid any recursive loop: a `fetchLabel` during the visit of `e` might
109
145
// end up calling `fetchLabel` on `e` itself, so we want the visit of `e` to call `fetchLabel`
@@ -214,17 +250,18 @@ class SwiftDispatcher {
214
250
return std::nullopt;
215
251
}
216
252
217
- // map `fetchLabel` on the iterable `arg`, returning a vector of all labels
253
+ // map `fetchLabel` on the iterable `arg`
218
254
// universal reference `Arg&&` is used to catch both temporary and non-const references, not
219
255
// for perfect forwarding
220
256
template <typename Iterable>
221
257
auto fetchRepeatedLabels (Iterable&& arg) {
222
- std::vector<decltype (fetchLabel (*arg.begin ()))> ret;
258
+ using Label = decltype (fetchLabel (*arg.begin ()));
259
+ TrapLabelVectorWrapper<typename Label::Tag> ret;
223
260
if constexpr (HasSize<Iterable>::value) {
224
- ret.reserve (arg.size ());
261
+ ret.data . reserve (arg.size ());
225
262
}
226
263
for (auto && e : arg) {
227
- ret.push_back (fetchLabel (e));
264
+ ret.data . push_back (fetchLabel (e));
228
265
}
229
266
return ret;
230
267
}
@@ -279,6 +316,12 @@ class SwiftDispatcher {
279
316
template <typename T>
280
317
struct HasSize <T, decltype (std::declval<T>().size(), void ())> : std::true_type {};
281
318
319
+ template <typename T, typename = void >
320
+ struct HasId : std::false_type {};
321
+
322
+ template <typename T>
323
+ struct HasId <T, decltype (std::declval<T>().id, void ())> : std::true_type {};
324
+
282
325
void attachLocation (swift::SourceLoc start,
283
326
swift::SourceLoc end,
284
327
TrapLabel<LocatableTag> locatableLabel) {
@@ -302,19 +345,20 @@ class SwiftDispatcher {
302
345
TrapLabel<Tag> fetchLabelFromUnion (const llvm::PointerUnion<Ts...> u) {
303
346
TrapLabel<Tag> ret{};
304
347
// with logical op short-circuiting, this will stop trying on the first successful fetch
305
- // don't feel tempted to replace the variable with the expression inside the `assert`, or
306
- // building with `NDEBUG` will not trigger the fetching
307
348
bool unionCaseFound = (... || fetchLabelFromUnionCase<Tag, Ts>(u, ret));
308
- assert (unionCaseFound && " llvm::PointerUnion not set to a known case" );
349
+ if (!unionCaseFound) {
350
+ // TODO emit error/warning here
351
+ return undefined_label;
352
+ }
309
353
return ret;
310
354
}
311
355
312
356
template <typename Tag, typename T, typename ... Ts>
313
357
bool fetchLabelFromUnionCase (const llvm::PointerUnion<Ts...> u, TrapLabel<Tag>& output) {
314
358
// we rely on the fact that when we extract `ASTNode` instances (which only happens
315
- // on `BraceStmt` elements), we cannot encounter a standalone `TypeRepr` there, so we skip
316
- // this case; extracting `TypeRepr`s here would be problematic as we would not be able to
317
- // provide the corresponding type
359
+ // on `BraceStmt`/`IfConfigDecl` elements), we cannot encounter a standalone `TypeRepr` there,
360
+ // so we skip this case; extracting `TypeRepr`s here would be problematic as we would not be
361
+ // able to provide the corresponding type
318
362
if constexpr (!std::is_same_v<T, swift::TypeRepr*>) {
319
363
if (auto e = u.template dyn_cast <T>()) {
320
364
output = fetchLabel (e);
0 commit comments