Skip to content

Commit 73535cc

Browse files
authored
Merge pull request #17573 from rintaro/4.2-ide-complete-sequence
[4.2][CodeComplete] Fix several crashes in getOperatorCompletions
2 parents 5e45c5f + 3402127 commit 73535cc

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
@@ -3368,8 +3368,17 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
33683368
}
33693369

33703370
void tryPostfixOperator(Expr *expr, PostfixOperatorDecl *op) {
3371-
if (!expr->getType())
3371+
auto Ty = expr->getType();
3372+
if (!Ty)
33723373
return;
3374+
3375+
SWIFT_DEFER {
3376+
// Restore type.
3377+
// FIXME: This is workaround for getTypeOfExpressionWithoutApplying()
3378+
// modifies type of 'expr'.
3379+
expr->setType(Ty);
3380+
};
3381+
33733382
// We allocate these expressions on the stack because we know they can't
33743383
// escape and there isn't a better way to allocate scratch Expr nodes.
33753384
UnresolvedDeclRefExpr UDRE(op->getName(), DeclRefKind::PostfixOperator,
@@ -3444,6 +3453,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34443453
LHS->getType()->is<AnyFunctionType>()))
34453454
return;
34463455

3456+
// Preserve LHS type for restoring it.
3457+
Type LHSTy = LHS->getType();
3458+
34473459
// We allocate these expressions on the stack because we know they can't
34483460
// escape and there isn't a better way to allocate scratch Expr nodes.
34493461
UnresolvedDeclRefExpr UDRE(op->getName(), DeclRefKind::BinaryOperator,
@@ -3456,13 +3468,20 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34563468
// Reset sequence.
34573469
SE->setElement(SE->getNumElements() - 1, nullptr);
34583470
SE->setElement(SE->getNumElements() - 2, nullptr);
3471+
LHS->setType(LHSTy);
34593472
prepareForRetypechecking(SE);
34603473

3461-
// Reset any references to operators in types, so they are properly
3462-
// handled as operators by sequence folding.
3463-
//
3464-
// FIXME: Would be better to have some kind of 'OperatorRefExpr'?
34653474
for (auto &element : sequence.drop_back(2)) {
3475+
// Unfold AssignExpr for re-typechecking sequence.
3476+
if (auto *AE = dyn_cast_or_null<AssignExpr>(element)) {
3477+
AE->setSrc(nullptr);
3478+
AE->setDest(nullptr);
3479+
}
3480+
3481+
// Reset any references to operators in types, so they are properly
3482+
// handled as operators by sequence folding.
3483+
//
3484+
// FIXME: Would be better to have some kind of 'OperatorRefExpr'?
34663485
if (auto operatorRef = element->getMemberOperatorRef()) {
34673486
operatorRef->setType(nullptr);
34683487
element = operatorRef;
@@ -3496,20 +3515,20 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34963515
}
34973516
}
34983517

3499-
void flattenBinaryExpr(BinaryExpr *expr, SmallVectorImpl<Expr *> &sequence) {
3500-
auto LHS = expr->getArg()->getElement(0);
3501-
if (auto binexpr = dyn_cast<BinaryExpr>(LHS))
3502-
flattenBinaryExpr(binexpr, sequence);
3503-
else
3504-
sequence.push_back(LHS);
3505-
3506-
sequence.push_back(expr->getFn());
3507-
3508-
auto RHS = expr->getArg()->getElement(1);
3509-
if (auto binexpr = dyn_cast<BinaryExpr>(RHS))
3510-
flattenBinaryExpr(binexpr, sequence);
3511-
else
3512-
sequence.push_back(RHS);
3518+
void flattenBinaryExpr(Expr *expr, SmallVectorImpl<Expr *> &sequence) {
3519+
if (auto binExpr = dyn_cast<BinaryExpr>(expr)) {
3520+
flattenBinaryExpr(binExpr->getArg()->getElement(0), sequence);
3521+
sequence.push_back(binExpr->getFn());
3522+
flattenBinaryExpr(binExpr->getArg()->getElement(1), sequence);
3523+
} else if (auto assignExpr = dyn_cast<AssignExpr>(expr)) {
3524+
flattenBinaryExpr(assignExpr->getDest(), sequence);
3525+
sequence.push_back(assignExpr);
3526+
flattenBinaryExpr(assignExpr->getSrc(), sequence);
3527+
assignExpr->setDest(nullptr);
3528+
assignExpr->setSrc(nullptr);
3529+
} else {
3530+
sequence.push_back(expr);
3531+
}
35133532
}
35143533

35153534
void typeCheckLeadingSequence(SmallVectorImpl<Expr *> &sequence) {
@@ -3519,10 +3538,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
35193538
// Take advantage of the fact the type-checker leaves the types on the AST.
35203539
if (!typeCheckExpression(const_cast<DeclContext *>(CurrDeclContext),
35213540
expr)) {
3522-
if (auto binexpr = dyn_cast<BinaryExpr>(expr)) {
3541+
if (isa<BinaryExpr>(expr) || isa<AssignExpr>(expr)) {
35233542
// Rebuild the sequence from the type-checked version.
35243543
sequence.clear();
3525-
flattenBinaryExpr(binexpr, sequence);
3544+
flattenBinaryExpr(expr, sequence);
35263545
return;
35273546
}
35283547
}
@@ -3548,6 +3567,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
35483567
if (sequence.size() > 1)
35493568
typeCheckLeadingSequence(sequence);
35503569

3570+
// Retrieve typechecked LHS.
3571+
LHS = sequence.back();
3572+
35513573
// Create a single sequence expression, which we will modify for each
35523574
// operator, filling in the operator and dummy right-hand side.
35533575
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,9 @@ protocol Bar_38149042 {
220220
func foo_38149042(bar: Bar_38149042) {
221221
_ = bar.foo? #^RDAR_38149042^# .x
222222
}
223-
// RDAR_38149042: Begin completions, 3 items
223+
224+
// RDAR_38149042: Begin completions
224225
// 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?
227226
// RDAR_38149042: End completions
228227

229228
// rdar://problem/38272904
@@ -246,3 +245,53 @@ func foo_38272904(a: A_38272904) {
246245
bar_38272904(a: .foo() #^RDAR_38272904^#)
247246
}
248247
// 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
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: End completions

0 commit comments

Comments
 (0)