Skip to content

Commit 8c970ab

Browse files
committed
[CodeComplete] Handle assign expression in sequence completion
rdar://problem/41232519 rdar://problem/41159258
1 parent c622722 commit 8c970ab

File tree

2 files changed

+72
-23
lines changed

2 files changed

+72
-23
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3358,11 +3358,17 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
33583358
SE->setElement(SE->getNumElements() - 2, nullptr);
33593359
prepareForRetypechecking(SE);
33603360

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'?
33653361
for (auto &element : sequence.drop_back(2)) {
3362+
// Unfold AssignExpr for re-typechecking sequence.
3363+
if (auto *AE = dyn_cast_or_null<AssignExpr>(element)) {
3364+
AE->setSrc(nullptr);
3365+
AE->setDest(nullptr);
3366+
}
3367+
3368+
// Reset any references to operators in types, so they are properly
3369+
// handled as operators by sequence folding.
3370+
//
3371+
// FIXME: Would be better to have some kind of 'OperatorRefExpr'?
33663372
if (auto operatorRef = element->getMemberOperatorRef()) {
33673373
operatorRef->setType(nullptr);
33683374
element = operatorRef;
@@ -3396,20 +3402,20 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
33963402
}
33973403
}
33983404

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);
3405+
void flattenBinaryExpr(Expr *expr, SmallVectorImpl<Expr *> &sequence) {
3406+
if (auto binExpr = dyn_cast<BinaryExpr>(expr)) {
3407+
flattenBinaryExpr(binExpr->getArg()->getElement(0), sequence);
3408+
sequence.push_back(binExpr->getFn());
3409+
flattenBinaryExpr(binExpr->getArg()->getElement(1), sequence);
3410+
} else if (auto assignExpr = dyn_cast<AssignExpr>(expr)) {
3411+
flattenBinaryExpr(assignExpr->getDest(), sequence);
3412+
sequence.push_back(assignExpr);
3413+
flattenBinaryExpr(assignExpr->getSrc(), sequence);
3414+
assignExpr->setDest(nullptr);
3415+
assignExpr->setSrc(nullptr);
3416+
} else {
3417+
sequence.push_back(expr);
3418+
}
34133419
}
34143420

34153421
void typeCheckLeadingSequence(SmallVectorImpl<Expr *> &sequence) {
@@ -3419,10 +3425,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34193425
// Take advantage of the fact the type-checker leaves the types on the AST.
34203426
if (!typeCheckExpression(const_cast<DeclContext *>(CurrDeclContext),
34213427
expr)) {
3422-
if (auto binexpr = dyn_cast<BinaryExpr>(expr)) {
3428+
if (isa<BinaryExpr>(expr) || isa<AssignExpr>(expr)) {
34233429
// Rebuild the sequence from the type-checked version.
34243430
sequence.clear();
3425-
flattenBinaryExpr(binexpr, sequence);
3431+
flattenBinaryExpr(expr, sequence);
34263432
return;
34273433
}
34283434
}
@@ -3448,6 +3454,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34483454
if (sequence.size() > 1)
34493455
typeCheckLeadingSequence(sequence);
34503456

3457+
// Retrieve typechecked LHS.
3458+
LHS = sequence.back();
3459+
34513460
// Create a single sequence expression, which we will modify for each
34523461
// operator, filling in the operator and dummy right-hand side.
34533462
sequence.push_back(nullptr); // operator

test/IDE/complete_crashes.swift

Lines changed: 43 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,45 @@ func foo_38272904(a: A_38272904) {
247245
bar_38272904(a: .foo() #^RDAR_38272904^#)
248246
}
249247
// RDAR_38272904: Begin completions
248+
249+
250+
// rdar://problem/41159258
251+
// RUN: %target-swift-ide-test -code-completion -source-filename=%s -code-completion-token=RDAR41159258_1 | %FileCheck %s -check-prefix=RDAR_41159258
252+
// RUN: %target-swift-ide-test -code-completion -source-filename=%s -code-completion-token=RDAR41159258_2 | %FileCheck %s -check-prefix=RDAR_41159258
253+
public func ==(lhs: RDAR41159258_MyResult1, rhs: RDAR41159258_MyResult1) -> Bool {
254+
fatalError()
255+
}
256+
public func ==(lhs: RDAR41159258_MyResult2, rhs: RDAR41159258_MyResult2) -> Bool {
257+
fatalError()
258+
}
259+
public enum RDAR41159258_MyResult1 {
260+
case failure(Error)
261+
}
262+
public enum RDAR41159258_MyResult2 {
263+
case failure(Error)
264+
}
265+
266+
public struct RDAR41159258_MyError: Error {}
267+
268+
func foo(x: RDAR41159258_MyResult1) {
269+
let x: RDAR41159258_MyResult1
270+
x = .failure(RDAR41159258_MyError()) #^RDAR41159258_1^#
271+
let y: Bool
272+
y = .failure(RDAR41159258_MyError()) #^RDAR41159258_2^#
273+
}
274+
// RDAR_41159258: Begin completions
275+
276+
277+
// rdar://problem/41232519
278+
// RUN: %target-swift-ide-test -code-completion -source-filename=%s -code-completion-token=RDAR41232519 | %FileCheck %s -check-prefix=RDAR_41232519
279+
public protocol IntProvider {
280+
func nextInt() -> Int
281+
}
282+
283+
public final class IntStore {
284+
public var myInt: Int = 0
285+
func readNextInt(from provider: IntProvider) {
286+
myInt = provider.nextInt() #^RDAR41232519^#
287+
}
288+
}
289+
// RDAR_41232519: Begin completions

0 commit comments

Comments
 (0)