@@ -61,16 +61,26 @@ class SwiftDispatcher {
6161
6262 template <typename Entry>
6363 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)>;
6567 if (!label.valid ()) {
6668 std::cerr << entry.NAME << " has undefined " << field;
6769 if (index >= 0 ) {
6870 std::cerr << ' [' << index << ' ]' ;
6971 }
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+ }
7179 }
7280 });
73- trap.emit (entry);
81+ if (valid) {
82+ trap.emit (entry);
83+ }
7484 }
7585
7686 template <typename Entry>
@@ -97,13 +107,39 @@ class SwiftDispatcher {
97107 emit (ElementIsUnknownTrap{label});
98108 }
99109
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+
100133 // This method gives a TRAP label for already emitted AST node.
101134 // If the AST node was not emitted yet, then the emission is dispatched to a corresponding
102135 // visitor (see `visit(T *)` methods below).
103136 template <typename E, typename ... Args, std::enable_if_t <IsStorable<E>>* = nullptr >
104137 TrapLabelOf<E> fetchLabel (const E& e, Args&&... args) {
105138 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+ }
107143 }
108144 // this is required so we avoid any recursive loop: a `fetchLabel` during the visit of `e` might
109145 // end up calling `fetchLabel` on `e` itself, so we want the visit of `e` to call `fetchLabel`
@@ -214,17 +250,18 @@ class SwiftDispatcher {
214250 return std::nullopt ;
215251 }
216252
217- // map `fetchLabel` on the iterable `arg`, returning a vector of all labels
253+ // map `fetchLabel` on the iterable `arg`
218254 // universal reference `Arg&&` is used to catch both temporary and non-const references, not
219255 // for perfect forwarding
220256 template <typename Iterable>
221257 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;
223260 if constexpr (HasSize<Iterable>::value) {
224- ret.reserve (arg.size ());
261+ ret.data . reserve (arg.size ());
225262 }
226263 for (auto && e : arg) {
227- ret.push_back (fetchLabel (e));
264+ ret.data . push_back (fetchLabel (e));
228265 }
229266 return ret;
230267 }
@@ -279,6 +316,12 @@ class SwiftDispatcher {
279316 template <typename T>
280317 struct HasSize <T, decltype (std::declval<T>().size(), void ())> : std::true_type {};
281318
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+
282325 void attachLocation (swift::SourceLoc start,
283326 swift::SourceLoc end,
284327 TrapLabel<LocatableTag> locatableLabel) {
@@ -302,19 +345,20 @@ class SwiftDispatcher {
302345 TrapLabel<Tag> fetchLabelFromUnion (const llvm::PointerUnion<Ts...> u) {
303346 TrapLabel<Tag> ret{};
304347 // 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
307348 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+ }
309353 return ret;
310354 }
311355
312356 template <typename Tag, typename T, typename ... Ts>
313357 bool fetchLabelFromUnionCase (const llvm::PointerUnion<Ts...> u, TrapLabel<Tag>& output) {
314358 // 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
318362 if constexpr (!std::is_same_v<T, swift::TypeRepr*>) {
319363 if (auto e = u.template dyn_cast <T>()) {
320364 output = fetchLabel (e);
0 commit comments