Skip to content

Commit ee34db4

Browse files
committed
[CodeCompletion] Don’t compute type relations if the contextual type is Any
Computing type relations to 'Any' is not very enlightning because everything would be convertible to it. If the contextual type is 'Any', just report all type relations as 'Unknown'. rdar://64812321 rdar://84684686
1 parent 025e919 commit ee34db4

File tree

3 files changed

+53
-6
lines changed

3 files changed

+53
-6
lines changed

lib/IDE/CodeCompletionResultType.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,12 +305,34 @@ TypeRelation USRBasedTypeContext::ContextualType::typeRelation(
305305

306306
// MARK: - CodeCompletionResultType
307307

308+
/// Returns \c true if \p Ty is the 'Any' type or some type that is sufficiently
309+
/// similar to Any, like the 'Any' metatype or an optional type wrapping 'Any'.
310+
static bool isEssentiallyAnyType(Type Ty) {
311+
while (true) {
312+
if (auto MT = Ty->getAs<AnyMetatypeType>()) {
313+
Ty = MT->getInstanceType();
314+
} else if (auto OT = Ty->getOptionalObjectType()) {
315+
Ty = OT;
316+
} else {
317+
break;
318+
}
319+
}
320+
return Ty->isAny();
321+
}
322+
308323
static TypeRelation calculateTypeRelation(Type Ty, Type ExpectedTy,
309324
const DeclContext &DC) {
310325
if (Ty.isNull() || ExpectedTy.isNull() || Ty->is<ErrorType>() ||
311326
ExpectedTy->is<ErrorType>())
312327
return TypeRelation::Unrelated;
313328

329+
/// Computing type relations to 'Any' is not very enlightning because
330+
/// everything would be convertible to it. If the contextual type is 'Any',
331+
/// just report all type relations as 'Unknown'.
332+
if (isEssentiallyAnyType(ExpectedTy)) {
333+
return TypeRelation::Unknown;
334+
}
335+
314336
// Equality/Conversion of GenericTypeParameterType won't account for
315337
// requirements – ignore them
316338
if (!Ty->hasTypeParameter() && !ExpectedTy->hasTypeParameter()) {

test/IDE/complete_at_top_level.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ var stringInterp = "\(#^STRING_INTERP_3?check=STRING_INTERP^#)"
328328
_ = "" + "\(#^STRING_INTERP_4?check=STRING_INTERP^#)" + ""
329329
// STRING_INTERP: Begin completions
330330
// STRING_INTERP-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]/IsSystem: ['(']{#(value): T#}[')'][#Void#];
331-
// STRING_INTERP-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: FooStruct[#FooStruct#]; name=FooStruct
331+
// STRING_INTERP-DAG: Decl[Struct]/CurrModule: FooStruct[#FooStruct#]; name=FooStruct
332332
// STRING_INTERP-DAG: Decl[FreeFunction]/CurrModule/TypeRelation[Invalid]: fooFunc1()[#Void#];
333333
// STRING_INTERP-DAG: Decl[FreeFunction]/CurrModule: optStr()[#String?#];
334334
// STRING_INTERP-DAG: Decl[GlobalVar]/Local: fooObject[#FooStruct#];

test/IDE/complete_type_any.swift

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ANY_IN_FUNC_PARAM | %FileCheck %s -check-prefix=ANY_IN_FUNC_PARAM
2-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ANY_IN_VAR_TYPE | %FileCheck %s -check-prefix=ANY_IN_VAR_TYPE
3-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ANY_METATYPE_VARIABLE | %FileCheck %s -check-prefix=ANY_METATYPE_VARIABLE
4-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ANY_METATYPE_MEMBER | %FileCheck %s -check-prefix=ANY_METATYPE_MEMBER
5-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ANY_IN_TYPEALIAS | %FileCheck %s -check-prefix=ANY_IN_TYPEALIAS
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t
63

74
func testAnyInParamList(a: #^ANY_IN_FUNC_PARAM^#
85
// ANY_IN_FUNC_PARAM: Begin completions
@@ -31,4 +28,32 @@ typealias A = #^ANY_IN_TYPEALIAS^#
3128
// ANY_IN_TYPEALIAS-DAG: Keyword/None: Any[#Any#]; name=Any
3229
// ANY_IN_TYPEALIAS: End completions
3330

31+
func testRdar64812321() {
32+
func foo<T>(x: T) {}
33+
func foo(x: Any.Type) {}
3434

35+
struct MyStruct {}
36+
let myStruct = MyStruct()
37+
38+
foo(x: #^ANY_RELATIONSHIP^#)
39+
// The MyStruct type should not be preferred over the myStruct instance.
40+
41+
// ANY_RELATIONSHIP: Begin completions
42+
// ANY_RELATIONSHIP-DAG: Decl[LocalVar]/Local: myStruct[#MyStruct#]; name=myStruct
43+
// ANY_RELATIONSHIP-DAG: Decl[Struct]/Local: MyStruct[#MyStruct#]; name=MyStruct
44+
// ANY_RELATIONSHIP: End completions
45+
}
46+
47+
func testRdar84684686() {
48+
func foo(_ x: Any?) {}
49+
50+
struct S {
51+
static func bar(x: Int) -> Int { x }
52+
}
53+
54+
// We should suggest a function call to `bar` here (i.e. `bar(x: <#Int#>)`), not a function reference (i.e. `bar(x:)`)
55+
foo(S.#^ANY_PREFERS_FUNCTION_CALL^#)
56+
// ANY_PREFERS_FUNCTION_CALL: Begin completions
57+
// ANY_PREFERS_FUNCTION_CALL-DAG: Decl[StaticMethod]/CurrNominal: bar({#x: Int#})[#Int#]; name=bar(x:)
58+
// ANY_PREFERS_FUNCTION_CALL: End completions
59+
}

0 commit comments

Comments
 (0)