Skip to content

Commit 42d3643

Browse files
authored
Merge pull request #23502 from rintaro/ide-completion-unresolvedoptional-rdar47806831
[CodeCompletion] Don't provide 'init(nilLiteral:)' et al in optional context
2 parents ba5e344 + b1efc21 commit 42d3643

File tree

2 files changed

+54
-8
lines changed

2 files changed

+54
-8
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2725,7 +2725,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
27252725
void addKeyword(StringRef Name, Type TypeAnnotation = Type(),
27262726
SemanticContextKind SK = SemanticContextKind::None,
27272727
CodeCompletionKeywordKind KeyKind
2728-
= CodeCompletionKeywordKind::None) {
2728+
= CodeCompletionKeywordKind::None,
2729+
unsigned NumBytesToErase = 0) {
27292730
CodeCompletionResultBuilder Builder(
27302731
Sink, CodeCompletionResult::ResultKind::Keyword, SK,
27312732
expectedTypeContext);
@@ -2734,6 +2735,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
27342735
Builder.setKeywordKind(KeyKind);
27352736
if (TypeAnnotation)
27362737
addTypeAnnotation(Builder, TypeAnnotation);
2738+
if (NumBytesToErase > 0)
2739+
Builder.setNumBytesToErase(NumBytesToErase);
27372740
}
27382741

27392742
void addKeyword(StringRef Name, StringRef TypeAnnotation,
@@ -3622,6 +3625,15 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
36223625
return false;
36233626
}
36243627

3628+
if (T->getOptionalObjectType() &&
3629+
VD->getModuleContext()->isStdlibModule()) {
3630+
// In optional context, ignore '.init(<some>)', 'init(nilLiteral:)',
3631+
if (isa<ConstructorDecl>(VD))
3632+
return false;
3633+
// TODO: Ignore '.some(<Wrapped>)' and '.none' too *in expression
3634+
// context*. They are useful in pattern context though.
3635+
}
3636+
36253637
// Enum element decls can always be referenced by implicit member
36263638
// expression.
36273639
if (isa<EnumElementDecl>(VD))
@@ -3692,6 +3704,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
36923704
// If this is optional type, perform completion for the object type.
36933705
// i.e. 'let _: Enum??? = .enumMember' is legal.
36943706
getUnresolvedMemberCompletions(objT->lookThroughAllOptionalTypes());
3707+
3708+
// Add 'nil' keyword with erasing '.' instruction.
3709+
unsigned bytesToErase = 0;
3710+
auto &SM = CurrDeclContext->getASTContext().SourceMgr;
3711+
if (DotLoc.isValid())
3712+
bytesToErase = SM.getByteDistance(DotLoc, SM.getCodeCompletionLoc());
3713+
addKeyword("nil", T, SemanticContextKind::ExpressionSpecific,
3714+
CodeCompletionKeywordKind::kw_nil, bytesToErase);
36953715
}
36963716
getUnresolvedMemberCompletions(T);
36973717
}

test/IDE/complete_unresolved_members.swift

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_1 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPT
1515
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_2 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPT
1616
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_3 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPTOPTOPT
17+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_4 | %FileCheck %s -check-prefix=UNRESOLVED_OPT_4
1718

1819
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_12 | %FileCheck %s -check-prefix=UNRESOLVED_3
1920
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_13 | %FileCheck %s -check-prefix=UNRESOLVED_3
@@ -241,29 +242,54 @@ class C4 {
241242
var _: SomeEnum1??? = .#^UNRESOLVED_OPT_3^#
242243
}
243244
}
244-
// UNRESOLVED_3: Begin completions
245+
// UNRESOLVED_3: Begin completions, 2 items
245246
// UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#]; name=North
246247
// UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#]; name=South
247248
// UNRESOLVED_3-NOT: SomeOptions1
248249
// UNRESOLVED_3-NOT: SomeOptions2
249250
// UNRESOLVED_3-NOT: none
250251
// UNRESOLVED_3-NOT: some(
251252

252-
// UNRESOLVED_3_OPT: Begin completions
253+
// UNRESOLVED_3_OPT: Begin completions, 5 items
253254
// UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#];
254255
// UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#];
256+
// UNRESOLVED_3_OPT-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#SomeEnum1?#]; name=nil
255257
// UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional<SomeEnum1>#]; name=none
256258
// UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: some({#SomeEnum1#})[#Optional<SomeEnum1>#];
257-
// UNRESOLVED_3_OPT-DAG: Decl[Constructor]/CurrNominal: init({#(some): SomeEnum1#})[#Optional<SomeEnum1>#];
258-
// UNRESOLVED_3_OPT-DAG: Decl[Constructor]/CurrNominal: init({#nilLiteral: ()#})[#Optional<SomeEnum1>#];
259+
// UNRESOLVED_3_OPT-NOT: init({#(some):
260+
// UNRESOLVED_3_OPT-NOT: init({#nilLiteral:
259261

260-
// UNRESOLVED_3_OPTOPTOPT: Begin completions
262+
// UNRESOLVED_3_OPTOPTOPT: Begin completions, 5 items
261263
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#];
262264
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#];
265+
// UNRESOLVED_3_OPTOPTOPT-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#SomeEnum1???#]; name=nil
263266
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional<SomeEnum1??>#]; name=none
264267
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: some({#SomeEnum1??#})[#Optional<SomeEnum1??>#];
265-
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[Constructor]/CurrNominal: init({#(some): SomeEnum1??#})[#Optional<SomeEnum1??>#];
266-
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[Constructor]/CurrNominal: init({#nilLiteral: ()#})[#Optional<SomeEnum1??>#];
268+
// UNRESOLVED_3_OPTOPTOPT-NOT: init({#(some):
269+
// UNRESOLVED_3_OPTOPTOPT-NOT: init({#nilLiteral:
270+
271+
enum Somewhere {
272+
case earth, mars
273+
}
274+
extension Optional where Wrapped == Somewhere {
275+
init(str: String) { fatalError() }
276+
static var nowhere: Self { return nil }
277+
}
278+
func testOptionalWithCustomExtension() {
279+
var _: Somewhere? = .#^UNRESOLVED_OPT_4^#
280+
// UNRESOLVED_OPT_4: Begin completions, 7 items
281+
// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: earth[#Somewhere#];
282+
// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: mars[#Somewhere#];
283+
// UNRESOLVED_OPT_4-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#Somewhere?#]; name=nil
284+
// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional<Somewhere>#]; name=none
285+
// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: some({#Somewhere#})[#Optional<Somewhere>#];
286+
// UNRESOLVED_OPT_4-DAG: Decl[Constructor]/CurrNominal: init({#str: String#})[#Optional<Somewhere>#]; name=init(str: String)
287+
// UNRESOLVED_OPT_4-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: nowhere[#Optional<Somewhere>#]; name=nowhere
288+
// UNRESOLVED_OPT_4-NOT: init({#(some):
289+
// UNRESOLVED_OPT_4-NOT: init({#nilLiteral:
290+
// UNRESOLVED_OPT_4: End completions
291+
}
292+
267293

268294
class C5 {
269295
func f1() {

0 commit comments

Comments
 (0)