Skip to content

Commit 7e3a5dc

Browse files
committed
[CodeCompletion] Don't provide 'init(nilLiteral:)' et al in optional context
For unresolved member completion, member decls in `Optional` referenceable by implicit member expression are useless in most cases. - `init(_: <#Wrapped#>)` - `init(nilLiteral: ())` - `.some(<#Wrapped#>)` - `.none` Instead, provide `nil` with erasing `.` instruction. rdar://problem/47806831
1 parent 6a7b7ad commit 7e3a5dc

File tree

2 files changed

+53
-9
lines changed

2 files changed

+53
-9
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2737,7 +2737,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
27372737
void addKeyword(StringRef Name, Type TypeAnnotation = Type(),
27382738
SemanticContextKind SK = SemanticContextKind::None,
27392739
CodeCompletionKeywordKind KeyKind
2740-
= CodeCompletionKeywordKind::None) {
2740+
= CodeCompletionKeywordKind::None,
2741+
unsigned NumBytesToErase = 0) {
27412742
CodeCompletionResultBuilder Builder(
27422743
Sink, CodeCompletionResult::ResultKind::Keyword, SK,
27432744
expectedTypeContext);
@@ -2746,6 +2747,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
27462747
Builder.setKeywordKind(KeyKind);
27472748
if (TypeAnnotation)
27482749
addTypeAnnotation(Builder, TypeAnnotation);
2750+
if (NumBytesToErase > 0)
2751+
Builder.setNumBytesToErase(NumBytesToErase);
27492752
}
27502753

27512754
void addKeyword(StringRef Name, StringRef TypeAnnotation,
@@ -3634,6 +3637,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
36343637
return false;
36353638
}
36363639

3640+
// In optional context, ignore '.init(<some>)', 'init(nilLiteral:)',
3641+
// '.some(<some>)' and '.none'. They are useless in most cases.
3642+
if (T->getOptionalObjectType() &&
3643+
VD->getModuleContext()->isStdlibModule() &&
3644+
(isa<EnumElementDecl>(VD) || isa<ConstructorDecl>(VD))) {
3645+
return false;
3646+
}
3647+
36373648
// Enum element decls can always be referenced by implicit member
36383649
// expression.
36393650
if (isa<EnumElementDecl>(VD))
@@ -3704,6 +3715,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
37043715
// If this is optional type, perform completion for the object type.
37053716
// i.e. 'let _: Enum??? = .enumMember' is legal.
37063717
getUnresolvedMemberCompletions(objT->lookThroughAllOptionalTypes());
3718+
3719+
// Add 'nil' keyword with erasing '.' instruction.
3720+
unsigned bytesToErase = 0;
3721+
auto &SM = CurrDeclContext->getASTContext().SourceMgr;
3722+
if (DotLoc.isValid())
3723+
bytesToErase = SM.getByteDistance(DotLoc, SM.getCodeCompletionLoc());
3724+
addKeyword("nil", T, SemanticContextKind::ExpressionSpecific,
3725+
CodeCompletionKeywordKind::kw_nil, bytesToErase);
37073726
}
37083727
getUnresolvedMemberCompletions(T);
37093728
}

test/IDE/complete_unresolved_members.swift

Lines changed: 33 additions & 8 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
@@ -252,18 +253,42 @@ class C4 {
252253
// UNRESOLVED_3_OPT: Begin completions
253254
// UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#];
254255
// UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#];
255-
// UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional<SomeEnum1>#]; name=none
256-
// 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>#];
256+
// UNRESOLVED_3_OPT-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#SomeEnum1?#]; name=nil
257+
// UNRESOLVED_3_OPT-NOT: none
258+
// UNRESOLVED_3_OPT-NOT: some
259+
// UNRESOLVED_3_OPT-NOT: init({#(some):
260+
// UNRESOLVED_3_OPT-NOT: init({#nilLiteral:
259261

260262
// UNRESOLVED_3_OPTOPTOPT: Begin completions
261263
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#];
262264
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#];
263-
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional<SomeEnum1??>#]; name=none
264-
// 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??>#];
265+
// UNRESOLVED_3_OPTOPTOPT-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#SomeEnum1???#]; name=nil
266+
// UNRESOLVED_3_OPTOPTOPT-NOT: none
267+
// UNRESOLVED_3_OPTOPTOPT-NOT: some
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
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[Constructor]/CurrNominal: init({#str: String#})[#Optional<Somewhere>#]; name=init(str: String)
285+
// UNRESOLVED_OPT_4-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: nowhere[#Optional<Somewhere>#]; name=nowhere
286+
// UNRESOLVED_OPT_4-NOT: none
287+
// UNRESOLVED_OPT_4-NOT: some
288+
// UNRESOLVED_OPT_4-NOT: init({#(some):
289+
// UNRESOLVED_OPT_4-NOT: init({#nilLiteral:
290+
}
291+
267292

268293
class C5 {
269294
func f1() {

0 commit comments

Comments
 (0)