Skip to content

Commit a44ddac

Browse files
authored
Merge pull request swiftlang#31792 from rintaro/5.3-ide-completion-rdar60982638
[5.3][CodeCompletion] Avoid re-typechecking pre-checked expressions
2 parents 13076ab + e35083d commit a44ddac

File tree

3 files changed

+65
-6
lines changed

3 files changed

+65
-6
lines changed

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -379,12 +379,16 @@ static void collectPossibleCalleesByQualifiedLookup(
379379
tyExpr->getTypeLoc().setType(nullptr);
380380
}
381381

382-
auto baseTyOpt = getTypeOfCompletionContextExpr(
383-
DC.getASTContext(), &DC, CompletionTypeCheckKind::Normal, baseExpr, ref);
384-
if (!baseTyOpt)
385-
return;
386-
387-
auto baseTy = (*baseTyOpt)->getWithoutSpecifierType();
382+
Type baseTy = baseExpr->getType();
383+
if (!baseTy || baseTy->is<ErrorType>()) {
384+
auto baseTyOpt = getTypeOfCompletionContextExpr(
385+
DC.getASTContext(), &DC, CompletionTypeCheckKind::Normal, baseExpr,
386+
ref);
387+
if (!baseTyOpt)
388+
return;
389+
baseTy = *baseTyOpt;
390+
}
391+
baseTy = baseTy->getWithoutSpecifierType();
388392
if (!baseTy->getMetatypeInstanceType()->mayHaveMembers())
389393
return;
390394

lib/Sema/CSGen.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,35 @@ namespace {
914914
};
915915
} // end anonymous namespace
916916

917+
namespace {
918+
// Check if \p E is a call expression to curried thunk of "KeyPath as function".
919+
// i.e. '{ `$kp$` in { $0[keyPath: $kp$] } }(keypath)'
920+
static bool isKeyPathCurriedThunkCallExpr(Expr *E) {
921+
auto CE = dyn_cast<CallExpr>(E);
922+
if (!CE)
923+
return false;
924+
auto thunk = dyn_cast<AutoClosureExpr>(CE->getFn());
925+
if (!thunk)
926+
return false;
927+
if (thunk->getParameters()->size() != 1 ||
928+
thunk->getParameters()->get(0)->getParameterName().str() != "$kp$")
929+
return false;
930+
931+
auto PE = dyn_cast<ParenExpr>(CE->getArg());
932+
if (!PE)
933+
return false;
934+
return isa<KeyPathExpr>(PE->getSubExpr());
935+
}
936+
937+
// Extract the keypath expression from the curried thunk expression.
938+
static Expr *extractKeyPathFromCurryThunkCall(Expr *E) {
939+
assert(isKeyPathCurriedThunkCallExpr(E));
940+
auto call = cast<CallExpr>(E);
941+
auto arg = cast<ParenExpr>(call->getArg());
942+
return arg->getSubExpr();
943+
}
944+
} // end anonymous namespace
945+
917946
namespace {
918947

919948
class ConstraintGenerator : public ExprVisitor<ConstraintGenerator, Type> {
@@ -3781,13 +3810,20 @@ namespace {
37813810
continue;
37823811
}
37833812

3813+
// Extract keypath from '{ `$kp$` in { $0[keyPath: $kp$] } }(keypath)'
3814+
if (isKeyPathCurriedThunkCallExpr(expr)) {
3815+
expr = extractKeyPathFromCurryThunkCall(expr);
3816+
continue;
3817+
}
3818+
37843819
// Restore '@autoclosure'd value.
37853820
if (auto ACE = dyn_cast<AutoClosureExpr>(expr)) {
37863821
// This is only valid if the closure doesn't have parameters.
37873822
if (ACE->getParameters()->size() == 0) {
37883823
expr = ACE->getSingleExpressionBody();
37893824
continue;
37903825
}
3826+
llvm_unreachable("other AutoClosureExpr must be handled specially");
37913827
}
37923828

37933829
// Remove any semantic expression injected by typechecking.

test/IDE/complete_call_arg.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@
104104
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TUPLEELEM_1 | %FileCheck %s -check-prefix=TUPLEELEM_1
105105
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TUPLEELEM_2 | %FileCheck %s -check-prefix=TUPLEELEM_2
106106

107+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYPATH_THUNK_BASE | %FileCheck %s -check-prefix=KEYPATH_THUNK_BASE
108+
107109
var i1 = 1
108110
var i2 = 2
109111
var oi1 : Int?
@@ -829,3 +831,20 @@ func testTupleElement(arg: (SimpleEnum, SimpleEnum)) {
829831
testTupleElement(arg: (.foo, .bar, .#^TUPLEELEM_2^#))
830832
// TUPLEELEM_2-NOT: Begin completions
831833
}
834+
835+
func testKeyPathThunkInBase() {
836+
struct TestKP {
837+
var value: Int { 1 }
838+
}
839+
struct TestKPResult {
840+
func testFunc(_ arg: SimpleEnum) {}
841+
}
842+
func foo(_ fn: (TestKP) -> Int) -> TestKPResult { TestKPResult() }
843+
844+
foo(\.value).testFunc(.#^KEYPATH_THUNK_BASE^#)
845+
// KEYPATH_THUNK_BASE: Begin completions, 3 items
846+
// KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: foo[#SimpleEnum#]; name=foo
847+
// KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: bar[#SimpleEnum#]; name=bar
848+
// KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: baz[#SimpleEnum#]; name=baz
849+
// KEYPATH_THUNK_BASE: End completions
850+
}

0 commit comments

Comments
 (0)