mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Sema] Avoid folding sequences multiple times for completion
Completion can end up calling into pre-checking multiple times in certain cases, make sure we don't attempt to fold a SequenceExpr multiple times since its original AST is in a broken state post-folding. Instead, just return the already-folded expression. rdar://133717866
This commit is contained in:
@@ -288,12 +288,7 @@ static Expr *makeBinOp(ASTContext &Ctx, Expr *Op, Expr *LHS, Expr *RHS,
|
||||
|
||||
if (auto *ternary = dyn_cast<TernaryExpr>(Op)) {
|
||||
// Resolve the ternary expression.
|
||||
if (!Ctx.CompletionCallback) {
|
||||
// In code completion we might call preCheckTarget twice - once for
|
||||
// the first pass and once for the second pass. This is fine since
|
||||
// preCheckTarget is idempotent.
|
||||
assert(!ternary->isFolded() && "already folded if expr in sequence?!");
|
||||
}
|
||||
ASSERT(!ternary->isFolded() && "already folded if expr in sequence?!");
|
||||
ternary->setCondExpr(LHS);
|
||||
ternary->setElseExpr(RHS);
|
||||
return ternary;
|
||||
@@ -301,12 +296,7 @@ static Expr *makeBinOp(ASTContext &Ctx, Expr *Op, Expr *LHS, Expr *RHS,
|
||||
|
||||
if (auto *assign = dyn_cast<AssignExpr>(Op)) {
|
||||
// Resolve the assignment expression.
|
||||
if (!Ctx.CompletionCallback) {
|
||||
// In code completion we might call preCheckTarget twice - once for
|
||||
// the first pass and once for the second pass. This is fine since
|
||||
// preCheckTarget is idempotent.
|
||||
assert(!assign->isFolded() && "already folded assign expr in sequence?!");
|
||||
}
|
||||
ASSERT(!assign->isFolded() && "already folded assign expr in sequence?!");
|
||||
assign->setDest(LHS);
|
||||
assign->setSrc(RHS);
|
||||
return assign;
|
||||
@@ -314,12 +304,7 @@ static Expr *makeBinOp(ASTContext &Ctx, Expr *Op, Expr *LHS, Expr *RHS,
|
||||
|
||||
if (auto *as = dyn_cast<ExplicitCastExpr>(Op)) {
|
||||
// Resolve the 'as' or 'is' expression.
|
||||
if (!Ctx.CompletionCallback) {
|
||||
// In code completion we might call preCheckTarget twice - once for
|
||||
// the first pass and once for the second pass. This is fine since
|
||||
// preCheckTarget is idempotent.
|
||||
assert(!as->isFolded() && "already folded 'as' expr in sequence?!");
|
||||
}
|
||||
ASSERT(!as->isFolded() && "already folded 'as' expr in sequence?!");
|
||||
assert(RHS == as && "'as' with non-type RHS?!");
|
||||
as->setSubExpr(LHS);
|
||||
return as;
|
||||
@@ -327,12 +312,7 @@ static Expr *makeBinOp(ASTContext &Ctx, Expr *Op, Expr *LHS, Expr *RHS,
|
||||
|
||||
if (auto *arrow = dyn_cast<ArrowExpr>(Op)) {
|
||||
// Resolve the '->' expression.
|
||||
if (!Ctx.CompletionCallback) {
|
||||
// In code completion we might call preCheckTarget twice - once for
|
||||
// the first pass and once for the second pass. This is fine since
|
||||
// preCheckTarget is idempotent.
|
||||
assert(!arrow->isFolded() && "already folded '->' expr in sequence?!");
|
||||
}
|
||||
ASSERT(!arrow->isFolded() && "already folded '->' expr in sequence?!");
|
||||
arrow->setArgsExpr(LHS);
|
||||
arrow->setResultExpr(RHS);
|
||||
return arrow;
|
||||
@@ -633,6 +613,15 @@ swift::DefaultTypeRequest::evaluate(Evaluator &evaluator,
|
||||
}
|
||||
|
||||
Expr *TypeChecker::foldSequence(SequenceExpr *expr, DeclContext *dc) {
|
||||
// We may end up running pre-checking multiple times for completion, just use
|
||||
// the folded expression if we've already folded the sequence.
|
||||
// FIXME: We ought to fix completion to not pre-check multiple times, strictly
|
||||
// speaking it isn't idempotent (e.g for things like `markDirectCallee`).
|
||||
if (auto *folded = expr->getFoldedExpr()) {
|
||||
ASSERT(dc->getASTContext().CompletionCallback &&
|
||||
"Attempting to fold sequence twice?");
|
||||
return folded;
|
||||
}
|
||||
// First resolve any unresolved decl references in operator positions.
|
||||
for (auto i : indices(expr->getElements())) {
|
||||
if (i % 2 == 0)
|
||||
|
||||
17
validation-test/IDE/issues_fixed/issue-75845.swift
Normal file
17
validation-test/IDE/issues_fixed/issue-75845.swift
Normal file
@@ -0,0 +1,17 @@
|
||||
// RUN: %batch-code-completion
|
||||
|
||||
// https://github.com/apple/swift/issues/75845
|
||||
// Make sure we don't crash.
|
||||
|
||||
struct Foo {
|
||||
init() {
|
||||
do {
|
||||
} catch {
|
||||
#^A^#self#^B^# = #^C^#error#^D^#
|
||||
}
|
||||
}
|
||||
}
|
||||
// A: Decl[LocalVar]/Local: error[#any Error#]; name=error
|
||||
// B: Begin completions
|
||||
// C: Decl[LocalVar]/Local: error[#any Error#]; name=error
|
||||
// D: Begin completions
|
||||
Reference in New Issue
Block a user