Skip to content

Commit 20a2a23

Browse files
committed
[CodeComplete] Strip out try and optional eval expr in operator compilation
foldSequence() may hoist these expression up by mutating their sub expression. When completing operators, this behavior ruins reusability of operand. Since these expression doesn't affect completion, we can strip them out. rdar://problem/42452085
1 parent cb01e10 commit 20a2a23

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3522,24 +3522,38 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
35223522
flattenBinaryExpr(assignExpr->getSrc(), sequence);
35233523
assignExpr->setDest(nullptr);
35243524
assignExpr->setSrc(nullptr);
3525+
} else if (auto tryExpr = dyn_cast<AnyTryExpr>(expr)) {
3526+
// Strip out try expression. It doesn't affect completion.
3527+
flattenBinaryExpr(tryExpr->getSubExpr(), sequence);
3528+
} else if (auto optEval = dyn_cast<OptionalEvaluationExpr>(expr)){
3529+
// Strip out optional evaluation expression. It doesn't affect completion.
3530+
flattenBinaryExpr(optEval->getSubExpr(), sequence);
35253531
} else {
35263532
sequence.push_back(expr);
35273533
}
35283534
}
35293535

35303536
void typeCheckLeadingSequence(SmallVectorImpl<Expr *> &sequence) {
3537+
3538+
// Strip out try and optional evaluation expr because foldSequence() mutates
3539+
// hierarchy of these expressions. They don't affect completion anyway.
3540+
for (auto &element : sequence) {
3541+
if (auto *tryExpr = dyn_cast<AnyTryExpr>(element))
3542+
element = tryExpr->getSubExpr();
3543+
if (auto *optEval = dyn_cast<OptionalEvaluationExpr>(element))
3544+
element = optEval->getSubExpr();
3545+
}
3546+
35313547
Expr *expr =
35323548
SequenceExpr::create(CurrDeclContext->getASTContext(), sequence);
35333549
prepareForRetypechecking(expr);
35343550
// Take advantage of the fact the type-checker leaves the types on the AST.
35353551
if (!typeCheckExpression(const_cast<DeclContext *>(CurrDeclContext),
35363552
expr)) {
3537-
if (isa<BinaryExpr>(expr) || isa<AssignExpr>(expr)) {
3538-
// Rebuild the sequence from the type-checked version.
3539-
sequence.clear();
3540-
flattenBinaryExpr(expr, sequence);
3541-
return;
3542-
}
3553+
// Rebuild the sequence from the type-checked version.
3554+
sequence.clear();
3555+
flattenBinaryExpr(expr, sequence);
3556+
return;
35433557
}
35443558

35453559
// Fall back to just using the immediate LHS.

test/IDE/complete_crashes.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,3 +312,19 @@ func test_40956846(
312312
// RDAR_40956846-DAG: Decl[LocalVar]/Local: arg_40956846_3[#(() -> Int)!#]; name=arg_40956846_3
313313
// RDAR_40956846-DAG: Decl[LocalVar]/Local: arg_40956846_4[#inout ((Int) -> Int)!#]; name=arg_40956846_4
314314
// RDAR_40956846: End completions
315+
316+
// rdar://problem/42452085
317+
// RUN: %target-swift-ide-test -code-completion -code-completion-token=RDAR_42452085_1 -source-filename=%s | %FileCheck %s -check-prefix=RDAR_42452085
318+
// RUN: %target-swift-ide-test -code-completion -code-completion-token=RDAR_42452085_2 -source-filename=%s | %FileCheck %s -check-prefix=RDAR_42452085
319+
// RUN: %target-swift-ide-test -code-completion -code-completion-token=RDAR_42452085_3 -source-filename=%s | %FileCheck %s -check-prefix=RDAR_42452085
320+
class cls_42452085 {
321+
var value: Any
322+
func canThrow() throws -> Int { return 1 }
323+
}
324+
func test_42452085(any: Any, obj: cls_42452085?) throws {
325+
var object: Any? = nil
326+
object = (any as? String) #^RDAR_42452085_1^#
327+
obj?.value = any #^RDAR_42452085_2^#
328+
_ = try obj?.canThrow() #^RDAR_42452085_3^#
329+
}
330+
// RDAR_42452085: found code completion token

0 commit comments

Comments
 (0)