These are currently added implicitly by the compiler in the context of
`if`/`switch` expressions. In the future, there might be explicit
`then <expr>` statement useful for cases where one would like to add
more than one statement in the branch, to mark what value to actually
use.
See https://forums.swift.org/t/pitch-multi-statement-if-switch-do-expressions/68443
* `variables` under `CaseStmt` are now AST children, which solves
orphan `VarDecl`s in that case
* reordered `CaseStmt` AST children to be `labels > variables > body`
(was `body > labels`)
* made `NamedPattern::getVarDecl` an extracted property instead of
`getName`
* The above led to duplicate DB entities because of a quirk in the
Swift compiler code. This is solved by tweaking the extraction of
`variables` under `CaseStmt` to not use `getCaseBodyVariables`.
Before we extracted all the subexpressions from the `SequenceExpr` while we should've only extracted the expressions at odd indices:
```
...
/// SequenceExpr - A list of binary operations which has not yet been
/// folded into a tree. The operands all have even indices, while the
/// subexpressions with odd indices are all (potentially overloaded)
/// references to binary operators.
class SequenceExpr final : public Expr,
...
```
The AST for a `SequenceExpr` looks like this:
```
sequence_expr:
unresolved_dot_expr:
...
assign_expr:
member_ref_expr:
...
dot_syntax_call_expr:
...
unresolved_member_chain_expr:
...
```
however, what's is not visible with the "final" AST is that `unresolved_dot_expr` is the unresolved version of `assign_expr.member_ref_expr` and the `unresolved_member_chain_expr` is the unresolved version of `assign_expr.dot_syntax_call_expr`.
This becomes visible when I enable typechecker debugging:
```c++
auto &typeCheckerOptions = invocation.getTypeCheckerOptions();
typeCheckerOptions.DebugConstraintSolver = true;
```
Which prints the following snippets:
```
---Initial constraints for the given expression---
(assign_expr type='()' location=foo.swift:25:54 range=[foo.swift:25:13 - line:25:57]
(unresolved_dot_expr type='$T2' location=foo.swift:25:29 range=[foo.swift:25:13 - line:25:29] field 'preferredDatePickerStyle' function_ref=unapplied
(unresolved_dot_expr type='$T1' location=foo.swift:25:18 range=[foo.swift:25:13 - line:25:18] field 'datePicker' function_ref=unapplied
(declref_expr type='DatePickerCell' location=foo.swift:25:13 range=[foo.swift:25:13 - line:25:13] decl=foo.(file).DatePickerRowProtocol extension.configurePickerStyle(_:_:).cell@foo.swift:15:33 function_ref=unapplied)))
(unresolved_member_chain_expr implicit type='$T5' location=foo.swift:25:57 range=[foo.swift:25:56 - line:25:57]
(unresolved_member_expr type='$T4' location=foo.swift:25:57 range=[foo.swift:25:56 - line:25:57] name='wheels' function_ref=unapplied)))
// ...
---Type-checked expression---
(assign_expr type='()' location=foo.swift:25:54 range=[foo.swift:25:13 - line:25:57]
(member_ref_expr type='@lvalue UIDatePickerStyle' location=foo.swift:25:29 range=[foo.swift:25:13 - line:25:29] decl=UIKit.(file).UIDatePicker.preferredDatePickerStyle
(force_value_expr implicit type='UIDatePicker' location=foo.swift:25:18 range=[foo.swift:25:13 - line:25:18] implicit_iuo_unwrap
(load_expr implicit type='UIDatePicker?' location=foo.swift:25:18 range=[foo.swift:25:13 - line:25:18]
(member_ref_expr type='@lvalue UIDatePicker?' location=foo.swift:25:18 range=[foo.swift:25:13 - line:25:18] decl=foo.(file).DatePickerCell.datePicker@foo.swift:10:29
(declref_expr type='DatePickerCell' location=foo.swift:25:13 range=[foo.swift:25:13 - line:25:13] decl=foo.(file).DatePickerRowProtocol extension.configurePickerStyle(_:_:).cell@foo.swift:15:33 function_ref=unapplied)))))
(dot_syntax_call_expr type='UIDatePickerStyle' location=foo.swift:25:57 range=[foo.swift:25:56 - line:25:57]
(declref_expr type='(UIDatePickerStyle.Type) -> UIDatePickerStyle' location=foo.swift:25:57 range=[foo.swift:25:57 - line:25:57] decl=UIKit.(file).UIDatePickerStyle.wheels function_ref=unapplied)
(argument_list implicit
(argument
(type_expr implicit type='UIDatePickerStyle.Type' location=foo.swift:25:56 range=[foo.swift:25:56 - line:25:56] typerepr='UIDatePickerStyle')))))
```
The proposed solution is to only extract subexpressions at indices from `SequenceExpr` thus ignoring all the unresolved leftovers.
Note: I'm not entirely sure about the case when there is only child (`elements.size() == 1`) so I'm always extracting it.
This patch fixes the last source of unresolved expressions.
This simplifies several instances of metaprogramming by leveraging
[constraints and concepts from C++20][1]. This:
* gets rid of `std::enable_if` by usage of `requires`, making it more
readable and yield better compiler messages.
* uses `requires` instead of `static_assert` to enforce `TrapLabel`
typing
* simplifies all compile-time tests for validity of a given expression
* uses some standard library concepts where possible
* generalizes and simplifies `SwiftLocationExtractor`
Notice that in order to use the `std::derived_from` concept, `virtual`
inheritance had to be added to the label tags, because diamond
inheritance is a problem otherwise. That's because
`std::derived_from<T, U>` requires that `T*` be convertible to `U*`,
which is false if there are multiple non-virtual inheritance paths from
`U` to `T`. As tags never get actually instantiated, there is no runtime
performance penalty in using `virtual` inheritance.
[1]: https://en.cppreference.com/w/cpp/language/constraints
Our mangler is split in two version:
* `SwiftTrapMangler`, with the same behaviour as the previous
`SwiftMangler`, constructing mangled names with trap label references
* `SwiftRecursiveMangler` that replaces trap label references with
recursive calls to its own `mangle` functions, effectively rolling out
the entire chain of references
The latter is used to create lazy trap file names. Hashing is used to
avoid excessively long filenames.
Specifically, this adds custom formatters using `path::operator string()` and `error_code::message()` and dereferences a (non-empty) optional. `fmtlib` provides formatters for these standard library types in `fmt/std.h`, but that file also requires RTTI (which we disable) for `std::exception` so we can't use it without either patching `fmtlib` (which they're open to: https://github.com/fmtlib/fmt/issues/3170) or enabling RTTI (which will require some consideration).
* visiting now happens in a later stage than fetching labels. While
fetching a list of entities to be visited is created, and then acted
upon in actual extraction. This partially flattens the recursive
nature of `fetchLabel` into a loop inside `SwiftVisitor::extract`.
Recursion in `fetchLabel` will only happen on labels fetched while
naming an entity (calling into `SwiftMangler`).
* The choice whether to name a declaration or type has been moved from
the translators to `SwiftMangler`. Acting on this choice is contained
in `SwiftDispatcher::createLabel`.
* The choice whether to emit a body of a declaration has been moved from
`DeclTranslator` to the dispatcher. This choice is also contained in
`SwiftDispatcher::createLabel`.
* The simple functionality of the `LabelStore` has been moved to the
`SwiftDispatcher` as well.