Skip to content

Commit e9f53eb

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 8b19bae commit e9f53eb

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
@@ -308,12 +308,34 @@ TypeRelation USRBasedTypeContext::ContextualType::typeRelation(
308308

309309
// MARK: - CodeCompletionResultType
310310

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

332+
/// Computing type relations to 'Any' is not very enlightning because
333+
/// everything would be convertible to it. If the contextual type is 'Any',
334+
/// just report all type relations as 'Unknown'.
335+
if (isEssentiallyAnyType(ExpectedTy)) {
336+
return TypeRelation::Unknown;
337+
}
338+
317339
// Equality/Conversion of GenericTypeParameterType won't account for
318340
// requirements – ignore them
319341
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)