Skip to content

Commit fba9d83

Browse files
authored
Merge pull request #37174 from hamishknight/off-the-chain
[Refactoring] Unwrap optional chains in async transform
2 parents 7bf0f02 + 07cdc20 commit fba9d83

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

lib/IDE/Refactoring.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4762,8 +4762,9 @@ class AsyncConverter : private SourceEntityWalker {
47624762
SmallString<0> Buffer;
47634763
llvm::raw_svector_ostream OS;
47644764

4765-
// Decls where any force-unwrap of that decl should be unwrapped, eg. for a
4766-
// previously optional closure paramter has become a non-optional local
4765+
// Decls where any force unwrap or optional chain of that decl should be
4766+
// elided, e.g for a previously optional closure parameter that has become a
4767+
// non-optional local.
47674768
llvm::DenseSet<const Decl *> Unwraps;
47684769
// Decls whose references should be replaced with, either because they no
47694770
// longer exist or are a different type. Any replaced code should ideally be
@@ -4874,11 +4875,19 @@ class AsyncConverter : private SourceEntityWalker {
48744875
OS << PLACEHOLDER_END;
48754876
});
48764877
}
4877-
} else if (auto *FTE = dyn_cast<ForceValueExpr>(E)) {
4878-
if (auto *D = FTE->getReferencedDecl().getDecl()) {
4878+
} else if (isa<ForceValueExpr>(E) || isa<BindOptionalExpr>(E)) {
4879+
// Remove a force unwrap or optional chain of a returned success value,
4880+
// as it will no longer be optional. For force unwraps, this is always a
4881+
// valid transform. For optional chains, it is a locally valid transform
4882+
// within the optional chain e.g foo?.x -> foo.x, but may change the type
4883+
// of the overall chain, which could cause errors elsewhere in the code.
4884+
// However this is generally more useful to the user than just leaving
4885+
// 'foo' as a placeholder. Note this is only the case when no other
4886+
// optionals are involved in the chain, e.g foo?.x?.y -> foo.x?.y is
4887+
// completely valid.
4888+
if (auto *D = E->getReferencedDecl().getDecl()) {
48794889
if (Unwraps.count(D))
4880-
return addCustom(FTE->getStartLoc(),
4881-
FTE->getEndLoc().getAdvancedLoc(1),
4890+
return addCustom(E->getStartLoc(), E->getEndLoc().getAdvancedLoc(1),
48824891
[&]() { OS << newNameFor(D, true); });
48834892
}
48844893
} else if (NestedExprCount == 0) {

test/refactoring/ConvertAsync/convert_params_single.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,3 +406,35 @@ withError { res, err in
406406
print("got result \(res!)")
407407
print("after")
408408
}
409+
410+
// RUN: %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=UNWRAPPING %s
411+
withError { str, err in
412+
print("before")
413+
guard err == nil else { return }
414+
_ = str!.count
415+
_ = str?.count
416+
_ = str!.count.bitWidth
417+
_ = str?.count.bitWidth
418+
_ = (str?.count.bitWidth)!
419+
_ = str!.first?.isWhitespace
420+
_ = str?.first?.isWhitespace
421+
_ = (str?.first?.isWhitespace)!
422+
print("after")
423+
}
424+
// UNWRAPPING: let str = try await withError()
425+
// UNWRAPPING-NEXT: print("before")
426+
// UNWRAPPING-NEXT: _ = str.count
427+
// UNWRAPPING-NEXT: _ = str.count
428+
// UNWRAPPING-NEXT: _ = str.count.bitWidth
429+
// UNWRAPPING-NEXT: _ = str.count.bitWidth
430+
431+
// Note this transform results in invalid code as str.count.bitWidth is no
432+
// longer optional, but arguably it's more useful than leaving str as a
433+
// placeholder. In general, the tranform we perform here is locally valid
434+
// within the optional chain, but may change the type of the overall chain.
435+
// UNWRAPPING-NEXT: _ = (str.count.bitWidth)!
436+
437+
// UNWRAPPING-NEXT: _ = str.first?.isWhitespace
438+
// UNWRAPPING-NEXT: _ = str.first?.isWhitespace
439+
// UNWRAPPING-NEXT: _ = (str.first?.isWhitespace)!
440+
// UNWRAPPING-NEXT: print("after")

0 commit comments

Comments
 (0)