Skip to content

Commit 38b2066

Browse files
authored
Merge pull request #32287 from rintaro/5.3-ide-completion-keypathsubscript-rdar61016147
[5.3][CodeCompletion] Add keypath apply subscript after open bracket
2 parents 1517ceb + 5753754 commit 38b2066

File tree

3 files changed

+63
-21
lines changed

3 files changed

+63
-21
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2762,23 +2762,32 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
27622762
const AnyFunctionType *AFT, const SubscriptDecl *SD,
27632763
const Optional<SemanticContextKind> SemanticContext = None) {
27642764
foundFunction(AFT);
2765-
auto genericSig =
2766-
SD->getInnermostDeclContext()->getGenericSignatureOfContext();
2767-
AFT = eraseArchetypes(const_cast<AnyFunctionType *>(AFT), genericSig)
2768-
->castTo<AnyFunctionType>();
2765+
if (SD) {
2766+
auto genericSig =
2767+
SD->getInnermostDeclContext()->getGenericSignatureOfContext();
2768+
AFT = eraseArchetypes(const_cast<AnyFunctionType *>(AFT), genericSig)
2769+
->castTo<AnyFunctionType>();
2770+
}
27692771

27702772
CommandWordsPairs Pairs;
27712773
CodeCompletionResultBuilder Builder(
2772-
Sink, CodeCompletionResult::ResultKind::Declaration,
2774+
Sink,
2775+
SD ? CodeCompletionResult::ResultKind::Declaration
2776+
: CodeCompletionResult::ResultKind::Pattern,
27732777
SemanticContext ? *SemanticContext : getSemanticContextKind(SD),
27742778
expectedTypeContext);
2775-
Builder.setAssociatedDecl(SD);
2776-
setClangDeclKeywords(SD, Pairs, Builder);
2779+
if (SD) {
2780+
Builder.setAssociatedDecl(SD);
2781+
setClangDeclKeywords(SD, Pairs, Builder);
2782+
}
27772783
if (!HaveLParen)
27782784
Builder.addLeftBracket();
27792785
else
27802786
Builder.addAnnotatedLeftBracket();
2781-
addCallArgumentPatterns(Builder, AFT, SD->getIndices());
2787+
ArrayRef<const ParamDecl *> declParams;
2788+
if (SD)
2789+
declParams = SD->getIndices()->getArray();
2790+
addCallArgumentPatterns(Builder, AFT->getParams(), declParams);
27822791
if (!HaveLParen)
27832792
Builder.addRightBracket();
27842793
else
@@ -6061,7 +6070,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
60616070
Lookup.getUnresolvedMemberCompletions(ContextInfo.getPossibleTypes());
60626071
break;
60636072
}
6064-
case CompletionKind::CallArg : {
6073+
case CompletionKind::CallArg: {
60656074
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
60666075

60676076
bool shouldPerformGlobalCompletion = true;
@@ -6070,9 +6079,12 @@ void CodeCompletionCallbacksImpl::doneParsing() {
60706079
!ContextInfo.getPossibleCallees().empty()) {
60716080
Lookup.setHaveLParen(true);
60726081
for (auto &typeAndDecl : ContextInfo.getPossibleCallees()) {
6073-
if (auto SD = dyn_cast_or_null<SubscriptDecl>(typeAndDecl.Decl)) {
6074-
Lookup.addSubscriptCallPattern(typeAndDecl.Type, SD,
6075-
typeAndDecl.SemanticContext);
6082+
auto apply = ContextInfo.getAnalyzedExpr();
6083+
if (apply && isa<SubscriptExpr>(apply)) {
6084+
Lookup.addSubscriptCallPattern(
6085+
typeAndDecl.Type,
6086+
dyn_cast_or_null<SubscriptDecl>(typeAndDecl.Decl),
6087+
typeAndDecl.SemanticContext);
60766088
} else {
60776089
Lookup.addFunctionCallPattern(
60786090
typeAndDecl.Type,

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,11 @@ class ExprParentFinder : public ASTWalker {
299299
static void collectPossibleCalleesByQualifiedLookup(
300300
DeclContext &DC, Type baseTy, DeclNameRef name,
301301
SmallVectorImpl<FunctionTypeAndDecl> &candidates) {
302-
bool isOnMetaType = baseTy->is<AnyMetatypeType>();
303302
auto baseInstanceTy = baseTy->getMetatypeInstanceType();
303+
if (!baseInstanceTy->mayHaveMembers())
304+
return;
305+
306+
bool isOnMetaType = baseTy->is<AnyMetatypeType>();
304307

305308
SmallVector<ValueDecl *, 2> decls;
306309
if (!DC.lookupQualified(baseInstanceTy,
@@ -389,15 +392,29 @@ static void collectPossibleCalleesByQualifiedLookup(
389392
baseTy = *baseTyOpt;
390393
}
391394
baseTy = baseTy->getWithoutSpecifierType();
392-
if (!baseTy->getMetatypeInstanceType()->mayHaveMembers())
393-
return;
394395

395396
// Use metatype for lookup 'super.init' if it's inside constructors.
396397
if (isa<SuperRefExpr>(baseExpr) && isa<ConstructorDecl>(DC) &&
397398
name == DeclNameRef::createConstructor())
398399
baseTy = MetatypeType::get(baseTy);
399400

400401
collectPossibleCalleesByQualifiedLookup(DC, baseTy, name, candidates);
402+
403+
// Add virtual 'subscript<Value>(keyPath: KeyPath<Root, Value>) -> Value'.
404+
if (name.getBaseName() == DeclBaseName::createSubscript() &&
405+
(baseTy->getAnyNominal() || baseTy->is<ArchetypeType>() ||
406+
baseTy->is<TupleType>())) {
407+
auto &Ctx = DC.getASTContext();
408+
409+
auto *kpDecl = Ctx.getKeyPathDecl();
410+
Type kpTy = kpDecl->mapTypeIntoContext(kpDecl->getDeclaredInterfaceType());
411+
Type kpValueTy = kpTy->castTo<BoundGenericType>()->getGenericArgs()[1];
412+
kpTy = BoundGenericType::get(kpDecl, Type(), {baseTy, kpValueTy});
413+
414+
Type fnTy = FunctionType::get(
415+
{AnyFunctionType::Param(kpTy, Ctx.Id_keyPath)}, kpValueTy);
416+
candidates.emplace_back(fnTy->castTo<AnyFunctionType>(), nullptr);
417+
}
401418
}
402419

403420
/// For the given \c callExpr, collect possible callee types and declarations.

test/IDE/complete_subscript.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SUPER_IN_STATICMETHOD | %FileCheck %s -check-prefix=SUPER_IN_STATICMETHOD
1717

1818
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LABELED_SUBSCRIPT | %FileCheck %s -check-prefix=LABELED_SUBSCRIPT
19+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TUPLE | %FileCheck %s -check-prefix=TUPLE
1920

2021
struct MyStruct<T> {
2122
static subscript(x: Int, static defValue: T) -> MyStruct<T> {
@@ -62,6 +63,7 @@ func test1() {
6263
let _ = MyStruct<Int>()[#^INSTANCE_INT_BRACKET^#
6364
// INSTANCE_INT_BRACKET: Begin completions
6465
// INSTANCE_INT_BRACKET-DAG: Decl[Subscript]/CurrNominal: ['[']{#(x): Int#}, {#instance: Int#}[']'][#Int#];
66+
// INSTANCE_INT_BRACKET-DAG: Pattern/CurrModule: ['[']{#keyPath: KeyPath<MyStruct<Int>, Value>#}[']'][#Value#];
6567
// INSTANCE_INT_BRACKET: End completions
6668
}
6769
func test2<U>(value: MyStruct<U>) {
@@ -87,6 +89,7 @@ func test2<U>(value: MyStruct<U>) {
8789
let _ = value[#^INSTANCE_ARCHETYPE_BRACKET^#
8890
// INSTANCE_ARCHETYPE_BRACKET: Begin completions
8991
// INSTANCE_ARCHETYPE_BRACKET-DAG: Decl[Subscript]/CurrNominal: ['[']{#(x): Int#}, {#instance: U#}[']'][#Int#];
92+
// INSTANCE_ARCHETYPE_BRACKET-DAG: Pattern/CurrModule: ['[']{#keyPath: KeyPath<MyStruct<U>, Value>#}[']'][#Value#];
9093
// INSTANCE_ARCHETYPE_BRACKET: End completions
9194

9295
let _ = MyStruct<U>[42, #^METATYPE_LABEL^#
@@ -110,14 +113,16 @@ class Derived: Base {
110113

111114
func testInstance() {
112115
let _ = self[#^SELF_IN_INSTANCEMETHOD^#]
113-
// SELF_IN_INSTANCEMETHOD: Begin completions, 2 items
116+
// SELF_IN_INSTANCEMETHOD: Begin completions, 3 items
114117
// SELF_IN_INSTANCEMETHOD-DAG: Decl[Subscript]/CurrNominal: ['[']{#derivedInstance: Int#}[']'][#Int#];
115118
// SELF_IN_INSTANCEMETHOD-DAG: Decl[Subscript]/Super: ['[']{#instance: Int#}[']'][#Int#];
119+
// SELF_IN_INSTANCEMETHOD-DAG: Pattern/CurrModule: ['[']{#keyPath: KeyPath<Derived, Value>#}[']'][#Value#];
116120
// SELF_IN_INSTANCEMETHOD: End completions
117121

118122
let _ = super[#^SUPER_IN_INSTANCEMETHOD^#]
119-
// SUPER_IN_INSTANCEMETHOD: Begin completions, 1 items
120-
// SUPER_IN_INSTANCEMETHOD-DAG: Decl[Subscript]/CurrNominal: ['[']{#instance: Int#}[']'][#Int#];
123+
// SUPER_IN_INSTANCEMETHOD: Begin completions, 2 items
124+
// SUPER_IN_INSTANCEMETHOD-DAG: Decl[Subscript]/CurrNominal: ['[']{#instance: Int#}[']'][#Int#];
125+
// SUPER_IN_INSTANCEMETHOD-DAG: Pattern/CurrModule: ['[']{#keyPath: KeyPath<Base, Value>#}[']'][#Value#];
121126
// SUPER_IN_INSTANCEMETHOD: End completions
122127
}
123128

@@ -130,7 +135,7 @@ class Derived: Base {
130135

131136
let _ = super[#^SUPER_IN_STATICMETHOD^#]
132137
// SUPER_IN_STATICMETHOD: Begin completions, 1 items
133-
// SUPER_IN_STATICMETHOD-DAG: Decl[Subscript]/CurrNominal: ['[']{#static: Int#}[']'][#Int#];
138+
// SUPER_IN_STATICMETHOD-DAG: Decl[Subscript]/CurrNominal: ['[']{#static: Int#}[']'][#Int#];
134139
// SUPER_IN_STATICMETHOD: End completions
135140
}
136141
}
@@ -140,7 +145,15 @@ struct MyStruct1<X: Comparable> {
140145
}
141146
func testSubscriptCallSig<T>(val: MyStruct1<T>) {
142147
val[#^LABELED_SUBSCRIPT^#
143-
// LABELED_SUBSCRIPT: Begin completions, 1 items
144-
// LABELED_SUBSCRIPT: Decl[Subscript]/CurrNominal: ['[']{#idx1: Int#}, {#idx2: Comparable#}[']'][#Int!#];
148+
// LABELED_SUBSCRIPT: Begin completions, 2 items
149+
// LABELED_SUBSCRIPT-DAG: Decl[Subscript]/CurrNominal: ['[']{#idx1: Int#}, {#idx2: Comparable#}[']'][#Int!#];
150+
// LABELED_SUBSCRIPT-DAG: Pattern/CurrModule: ['[']{#keyPath: KeyPath<MyStruct1<T>, Value>#}[']'][#Value#];
145151
// LABELED_SUBSCRIPT: End completions
146152
}
153+
154+
func testSubcscriptTuple(val: (x: Int, String)) {
155+
val[#^TUPLE^#]
156+
// TUPLE: Begin completions, 1 items
157+
// TUPLE-DAG: Pattern/CurrModule: ['[']{#keyPath: KeyPath<(x: Int, String), Value>#}[']'][#Value#];
158+
// TUPLE: End completions
159+
}

0 commit comments

Comments
 (0)