Skip to content

Commit 7a348c6

Browse files
authored
[5.5] [Async Refactoring] Better handle non-refutable patterns (#37848)
* Explicitly handle error case in fallback logic I don't believe this case currently can come up, but leave it explicitly unhandled for now so we don't perform an erroneous transform if it ever comes up in the future. * Add a couple of getSemanticsProviding calls * Don't handle refutable patterns in async transform These aren't currently supported. * Don't handle unclassified switch cases for now Previously we would silently add these to the success block. For now, let's leave them unhandled. * Allow SemaAnnotator to handle patterns Add the necessary walking hooks, and fix ReferenceCollector to use it. * Adapt ScopedDeclCollector to track number of references Use a DenseMap to track the number of references to a given decl in a scope. * [AST] Add Pattern::hasAnyMutableBindings * Generalise addTupleOf Allow it to iterate over an arbitrary container type. * Better handle non-refutable patterns in async transform Keep track of patterns that bind multiple vars and print them out when converting an async call. If the parameter being bound isn't referenced elsewhere, we'll print the pattern inline as e.g: ``` let ((x, y), z) = await foo() ``` Otherwise, if the parameter is referenced elsewhere in the block we'll print the pattern out of line, such as: ``` let (res, z) = await foo() let (x, y) = res ``` In addition, make sure to print var bindings out of line if there's also a let binding, e.g: ``` let x = await foo() var y = x ``` This ensures any mutations to y doesn't affect x. If there's only a single var binding, we'll print it inline. rdar://77802560 * Handle parent vars in async transform If we're in a case stmt body, any DeclRefExprs to vars bound by a pattern will actually be to an implicit var decl that's declared for the body. We therefore need to walk to its "parent" to get to the var referenced by the pattern, which will have the correct entries in the naming and placeholder maps. * Strip an unused DiagnosticEngine param * Add a release/5.5 workaround for a double AST walk Avoid walking twice for capture lists. On main, this is fixed in the AST walker.
1 parent 4634a0f commit 7a348c6

File tree

8 files changed

+954
-87
lines changed

8 files changed

+954
-87
lines changed

include/swift/AST/DiagnosticsRefactoring.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,7 @@ ERROR(callback_multiple_case_items, none, "cannot refactor switch using a case w
7070

7171
ERROR(callback_where_case_item, none, "cannot refactor switch using a case with where clause", ())
7272

73+
ERROR(unknown_callback_case_item, none, "cannot refactor complex case conditions", ())
74+
7375
#define UNDEFINE_DIAGNOSTIC_MACROS
7476
#include "DefineDiagnosticMacros.h"

include/swift/AST/Pattern.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ class alignas(8) Pattern {
202202
/// Does this binding declare something that requires storage?
203203
bool hasStorage() const;
204204

205+
/// Does this pattern have any mutable 'var' bindings?
206+
bool hasAnyMutableBindings() const;
207+
205208
static bool classof(const Pattern *P) { return true; }
206209

207210
//*** Allocation Routines ************************************************/

include/swift/IDE/SourceEntityWalker.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ class SourceEntityWalker {
7373
/// Walks the provided Expr.
7474
/// \returns true if traversal was aborted, false otherwise.
7575
bool walk(Expr *E);
76+
/// Walks the provided Pattern.
77+
/// \returns true if traversal was aborted, false otherwise.
78+
bool walk(Pattern *P);
7679
/// Walks the provided ASTNode.
7780
/// \returns true if traversal was aborted, false otherwise.
7881
bool walk(ASTNode N);
@@ -101,6 +104,14 @@ class SourceEntityWalker {
101104
/// returns false, the remaining traversal is terminated and returns failure.
102105
virtual bool walkToExprPost(Expr *E) { return true; }
103106

107+
/// This method is called when first visiting a pattern, before walking
108+
/// into its children. If it returns false, the subtree is skipped.
109+
virtual bool walkToPatternPre(Pattern *P) { return true; }
110+
111+
/// This method is called after visiting the children of a pattern. If it
112+
/// returns false, the remaining traversal is terminated and returns failure.
113+
virtual bool walkToPatternPost(Pattern *P) { return true; }
114+
104115
/// This method is called when a ValueDecl is referenced in source. If it
105116
/// returns false, the remaining traversal is terminated and returns failure.
106117
///

lib/AST/Pattern.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,15 @@ bool Pattern::hasStorage() const {
291291
return HasStorage;
292292
}
293293

294+
bool Pattern::hasAnyMutableBindings() const {
295+
auto HasMutable = false;
296+
forEachVariable([&](VarDecl *VD) {
297+
if (!VD->isLet())
298+
HasMutable = true;
299+
});
300+
return HasMutable;
301+
}
302+
294303
/// Return true if this is a non-resolved ExprPattern which is syntactically
295304
/// irrefutable.
296305
static bool isIrrefutableExprPattern(const ExprPattern *EP) {

0 commit comments

Comments
 (0)