Skip to content

Commit 4a29944

Browse files
authored
Merge pull request #17556 from rintaro/ide-complete-sequence
[CodeComplete] Fix several crashes in getOperatorCompletions
2 parents f7e6309 + 52e3109 commit 4a29944

File tree

3 files changed

+99
-24
lines changed

3 files changed

+99
-24
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3268,8 +3268,17 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
32683268
}
32693269

32703270
void tryPostfixOperator(Expr *expr, PostfixOperatorDecl *op) {
3271-
if (!expr->getType())
3271+
auto Ty = expr->getType();
3272+
if (!Ty)
32723273
return;
3274+
3275+
SWIFT_DEFER {
3276+
// Restore type.
3277+
// FIXME: This is workaround for getTypeOfExpressionWithoutApplying()
3278+
// modifies type of 'expr'.
3279+
expr->setType(Ty);
3280+
};
3281+
32733282
// We allocate these expressions on the stack because we know they can't
32743283
// escape and there isn't a better way to allocate scratch Expr nodes.
32753284
UnresolvedDeclRefExpr UDRE(op->getName(), DeclRefKind::PostfixOperator,
@@ -3344,6 +3353,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
33443353
LHS->getType()->is<AnyFunctionType>()))
33453354
return;
33463355

3356+
// Preserve LHS type for restoring it.
3357+
Type LHSTy = LHS->getType();
3358+
33473359
// We allocate these expressions on the stack because we know they can't
33483360
// escape and there isn't a better way to allocate scratch Expr nodes.
33493361
UnresolvedDeclRefExpr UDRE(op->getName(), DeclRefKind::BinaryOperator,
@@ -3356,13 +3368,20 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
33563368
// Reset sequence.
33573369
SE->setElement(SE->getNumElements() - 1, nullptr);
33583370
SE->setElement(SE->getNumElements() - 2, nullptr);
3371+
LHS->setType(LHSTy);
33593372
prepareForRetypechecking(SE);
33603373

3361-
// Reset any references to operators in types, so they are properly
3362-
// handled as operators by sequence folding.
3363-
//
3364-
// FIXME: Would be better to have some kind of 'OperatorRefExpr'?
33653374
for (auto &element : sequence.drop_back(2)) {
3375+
// Unfold AssignExpr for re-typechecking sequence.
3376+
if (auto *AE = dyn_cast_or_null<AssignExpr>(element)) {
3377+
AE->setSrc(nullptr);
3378+
AE->setDest(nullptr);
3379+
}
3380+
3381+
// Reset any references to operators in types, so they are properly
3382+
// handled as operators by sequence folding.
3383+
//
3384+
// FIXME: Would be better to have some kind of 'OperatorRefExpr'?
33663385
if (auto operatorRef = element->getMemberOperatorRef()) {
33673386
operatorRef->setType(nullptr);
33683387
element = operatorRef;
@@ -3396,20 +3415,20 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
33963415
}
33973416
}
33983417

3399-
void flattenBinaryExpr(BinaryExpr *expr, SmallVectorImpl<Expr *> &sequence) {
3400-
auto LHS = expr->getArg()->getElement(0);
3401-
if (auto binexpr = dyn_cast<BinaryExpr>(LHS))
3402-
flattenBinaryExpr(binexpr, sequence);
3403-
else
3404-
sequence.push_back(LHS);
3405-
3406-
sequence.push_back(expr->getFn());
3407-
3408-
auto RHS = expr->getArg()->getElement(1);
3409-
if (auto binexpr = dyn_cast<BinaryExpr>(RHS))
3410-
flattenBinaryExpr(binexpr, sequence);
3411-
else
3412-
sequence.push_back(RHS);
3418+
void flattenBinaryExpr(Expr *expr, SmallVectorImpl<Expr *> &sequence) {
3419+
if (auto binExpr = dyn_cast<BinaryExpr>(expr)) {
3420+
flattenBinaryExpr(binExpr->getArg()->getElement(0), sequence);
3421+
sequence.push_back(binExpr->getFn());
3422+
flattenBinaryExpr(binExpr->getArg()->getElement(1), sequence);
3423+
} else if (auto assignExpr = dyn_cast<AssignExpr>(expr)) {
3424+
flattenBinaryExpr(assignExpr->getDest(), sequence);
3425+
sequence.push_back(assignExpr);
3426+
flattenBinaryExpr(assignExpr->getSrc(), sequence);
3427+
assignExpr->setDest(nullptr);
3428+
assignExpr->setSrc(nullptr);
3429+
} else {
3430+
sequence.push_back(expr);
3431+
}
34133432
}
34143433

34153434
void typeCheckLeadingSequence(SmallVectorImpl<Expr *> &sequence) {
@@ -3419,10 +3438,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34193438
// Take advantage of the fact the type-checker leaves the types on the AST.
34203439
if (!typeCheckExpression(const_cast<DeclContext *>(CurrDeclContext),
34213440
expr)) {
3422-
if (auto binexpr = dyn_cast<BinaryExpr>(expr)) {
3441+
if (isa<BinaryExpr>(expr) || isa<AssignExpr>(expr)) {
34233442
// Rebuild the sequence from the type-checked version.
34243443
sequence.clear();
3425-
flattenBinaryExpr(binexpr, sequence);
3444+
flattenBinaryExpr(expr, sequence);
34263445
return;
34273446
}
34283447
}
@@ -3448,6 +3467,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34483467
if (sequence.size() > 1)
34493468
typeCheckLeadingSequence(sequence);
34503469

3470+
// Retrieve typechecked LHS.
3471+
LHS = sequence.back();
3472+
34513473
// Create a single sequence expression, which we will modify for each
34523474
// operator, filling in the operator and dummy right-hand side.
34533475
sequence.push_back(nullptr); // operator

lib/Sema/CSRanking.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,10 @@ static bool paramIsIUO(Decl *decl, int paramNum) {
372372
auto *param = paramList->get(paramNum);
373373
return param->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
374374
}
375+
if (auto *ee = dyn_cast<EnumElementDecl>(decl)) {
376+
auto *param = ee->getParameterList()->get(paramNum);
377+
return param->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
378+
}
375379

376380
auto *subscript = cast<SubscriptDecl>(decl);
377381
auto *index = subscript->getIndices()->get(paramNum);

test/IDE/complete_crashes.swift

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,8 @@ protocol Bar_38149042 {
220220
func foo_38149042(bar: Bar_38149042) {
221221
_ = bar.foo? #^RDAR_38149042^# .x
222222
}
223-
// RDAR_38149042: Begin completions, 4 items
223+
// RDAR_38149042: Begin completions, 2 items
224224
// RDAR_38149042-DAG: Decl[InstanceVar]/CurrNominal: .x[#Int#]; name=x
225-
// RDAR_38149042-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: [' ']=== {#AnyObject?#}[#Bool#]; name==== AnyObject?
226-
// RDAR_38149042-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: [' ']!== {#AnyObject?#}[#Bool#]; name=!== AnyObject?
227225
// RDAR_38149042-DAG: Keyword[self]/CurrNominal: .self[#Baz_38149042#]; name=self
228226
// RDAR_38149042: End completions
229227

@@ -247,3 +245,54 @@ func foo_38272904(a: A_38272904) {
247245
bar_38272904(a: .foo() #^RDAR_38272904^#)
248246
}
249247
// RDAR_38272904: Begin completions
248+
249+
// rdar://problem/41159258
250+
// RUN: %target-swift-ide-test -code-completion -source-filename=%s -code-completion-token=RDAR41159258_1 | %FileCheck %s -check-prefix=RDAR_41159258
251+
// RUN: %target-swift-ide-test -code-completion -source-filename=%s -code-completion-token=RDAR41159258_2 | %FileCheck %s -check-prefix=RDAR_41159258
252+
public func ==(lhs: RDAR41159258_MyResult1, rhs: RDAR41159258_MyResult1) -> Bool {
253+
fatalError()
254+
}
255+
public func ==(lhs: RDAR41159258_MyResult2, rhs: RDAR41159258_MyResult2) -> Bool {
256+
fatalError()
257+
}
258+
public enum RDAR41159258_MyResult1 {
259+
case failure(Error)
260+
}
261+
public enum RDAR41159258_MyResult2 {
262+
case failure(Error)
263+
}
264+
265+
public struct RDAR41159258_MyError: Error {}
266+
267+
func foo(x: RDAR41159258_MyResult1) {
268+
let x: RDAR41159258_MyResult1
269+
x = .failure(RDAR41159258_MyError()) #^RDAR41159258_1^#
270+
let y: Bool
271+
y = .failure(RDAR41159258_MyError()) #^RDAR41159258_2^#
272+
}
273+
// RDAR_41159258: Begin completions
274+
275+
276+
// rdar://problem/41232519
277+
// RUN: %target-swift-ide-test -code-completion -source-filename=%s -code-completion-token=RDAR41232519 | %FileCheck %s -check-prefix=RDAR_41232519
278+
public protocol IntProvider {
279+
func nextInt() -> Int
280+
}
281+
282+
public final class IntStore {
283+
public var myInt: Int = 0
284+
func readNextInt(from provider: IntProvider) {
285+
myInt = provider.nextInt() #^RDAR41232519^#
286+
}
287+
}
288+
// RDAR_41232519: Begin completions
289+
290+
// rdar://problem/28188259
291+
// RUN: %target-swift-ide-test -code-completion -code-completion-token=RDAR_28188259 -source-filename=%s | %FileCheck %s -check-prefix=RDAR_28188259
292+
func test_28188259(x: ((Int) -> Void) -> Void) {
293+
x({_ in }#^RDAR_28188259^#)
294+
}
295+
// RDAR_28188259: Begin completions
296+
// RDAR_28188259-DAG: Pattern/CurrModule: ({#_#})[#Void#]; name=(_)
297+
// RDAR_28188259-DAG: Keyword[self]/CurrNominal: .self[#(_) -> ()#]; name=self
298+
// RDAR_28188259: End completions

0 commit comments

Comments
 (0)