Skip to content

Commit b8f6471

Browse files
authored
Merge pull request #31774 from rintaro/ide-completion-rdar60982638
[CodeCompletion] Avoid re-typechecking pre-checked expressions
2 parents 816b00e + 3337d7b commit b8f6471

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
@@ -393,12 +393,16 @@ static void collectPossibleCalleesByQualifiedLookup(
393393
tyExpr->setType(nullptr);
394394
}
395395

396-
auto baseTyOpt = getTypeOfCompletionContextExpr(
397-
DC.getASTContext(), &DC, CompletionTypeCheckKind::Normal, baseExpr, ref);
398-
if (!baseTyOpt)
399-
return;
400-
401-
auto baseTy = (*baseTyOpt)->getWithoutSpecifierType();
396+
Type baseTy = baseExpr->getType();
397+
if (!baseTy || baseTy->is<ErrorType>()) {
398+
auto baseTyOpt = getTypeOfCompletionContextExpr(
399+
DC.getASTContext(), &DC, CompletionTypeCheckKind::Normal, baseExpr,
400+
ref);
401+
if (!baseTyOpt)
402+
return;
403+
baseTy = *baseTyOpt;
404+
}
405+
baseTy = baseTy->getWithoutSpecifierType();
402406
if (!baseTy->getMetatypeInstanceType()->mayHaveMembers())
403407
return;
404408

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> {
@@ -3787,13 +3816,20 @@ namespace {
37873816
continue;
37883817
}
37893818

3819+
// Extract keypath from '{ `$kp$` in { $0[keyPath: $kp$] } }(keypath)'
3820+
if (isKeyPathCurriedThunkCallExpr(expr)) {
3821+
expr = extractKeyPathFromCurryThunkCall(expr);
3822+
continue;
3823+
}
3824+
37903825
// Restore '@autoclosure'd value.
37913826
if (auto ACE = dyn_cast<AutoClosureExpr>(expr)) {
37923827
// This is only valid if the closure doesn't have parameters.
37933828
if (ACE->getParameters()->size() == 0) {
37943829
expr = ACE->getSingleExpressionBody();
37953830
continue;
37963831
}
3832+
llvm_unreachable("other AutoClosureExpr must be handled specially");
37973833
}
37983834

37993835
// 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)