Skip to content

Commit 562ab8a

Browse files
authored
Merge pull request #71211 from hamishknight/completion-tweaks
[CodeComplete] A couple of contextual type handling tweaks
2 parents 13a1505 + d022cf8 commit 562ab8a

File tree

4 files changed

+91
-18
lines changed

4 files changed

+91
-18
lines changed

lib/IDE/PostfixCompletion.cpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -189,23 +189,27 @@ void PostfixCompletionCallback::sawSolutionImpl(
189189

190190
bool BaseIsStaticMetaType = S.isStaticallyDerivedMetatype(ParsedExpr);
191191

192+
bool ExpectsNonVoid = false;
192193
SmallVector<Type, 4> ExpectedTypes;
193194
if (ExpectedTy) {
194195
ExpectedTypes.push_back(ExpectedTy);
195-
}
196-
197-
bool ExpectsNonVoid = false;
198-
ExpectsNonVoid |= ExpectedTy && !ExpectedTy->isVoid();
199-
ExpectsNonVoid |=
200-
!ParentExpr && CS.getContextualTypePurpose(CompletionExpr) != CTP_Unused;
201-
202-
for (auto SAT : S.targets) {
203-
if (ExpectsNonVoid) {
204-
// ExpectsNonVoid is already set. No need to iterate further.
205-
break;
206-
}
207-
if (SAT.second.getAsExpr() == CompletionExpr) {
208-
ExpectsNonVoid |= SAT.second.getExprContextualTypePurpose() != CTP_Unused;
196+
ExpectsNonVoid = !ExpectedTy->isVoid();
197+
} else {
198+
// If we don't know what the expected type is, assume it must be non-Void
199+
// if we have a contextual type that is not unused. This prevents us from
200+
// suggesting Void values for e.g bindings without explicit types.
201+
ExpectsNonVoid |= !ParentExpr &&
202+
CS.getContextualTypePurpose(CompletionExpr) != CTP_Unused;
203+
204+
for (auto SAT : S.targets) {
205+
if (ExpectsNonVoid) {
206+
// ExpectsNonVoid is already set. No need to iterate further.
207+
break;
208+
}
209+
if (SAT.second.getAsExpr() == CompletionExpr) {
210+
ExpectsNonVoid |=
211+
SAT.second.getExprContextualTypePurpose() != CTP_Unused;
212+
}
209213
}
210214
}
211215

lib/IDE/TypeCheckCompletionCallback.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,11 @@ void TypeCheckCompletionCallback::fallbackTypeCheck(DeclContext *DC) {
4747

4848
Type swift::ide::getTypeForCompletion(const constraints::Solution &S,
4949
ASTNode Node) {
50+
// Use the contextual type, unless it is still unresolved, in which case fall
51+
// back to getting the type from the expression.
5052
if (auto ContextualType = S.getContextualType(Node)) {
51-
return ContextualType;
53+
if (!ContextualType->hasUnresolvedType())
54+
return ContextualType;
5255
}
5356

5457
if (!S.hasType(Node)) {

test/IDE/complete_issue-55711.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
// RUN: %swift-ide-test -code-completion -source-filename=%s -code-completion-token=A | %FileCheck %s --check-prefix=A
2-
// RUN: %swift-ide-test -code-completion -source-filename=%s -code-completion-token=B | %FileCheck %s --check-prefix=B
3-
// RUN: %swift-ide-test -code-completion -source-filename=%s -code-completion-token=D | %FileCheck %s --check-prefix=D
1+
// RUN: %batch-code-completion
42

53
// https://github.com/apple/swift/issues/55711
64
// https://forums.swift.org/t/code-completion-enhancement-request/38677
@@ -37,6 +35,10 @@ func test() {
3735
C(.a) {
3836
.#^A^#
3937
}
38+
C(.a) {
39+
()
40+
return .#^A_MULTISTMT?check=A^#
41+
}
4042
// A: Begin completions, 2 items
4143
// A-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: foo({#arg: Bool#})[#A<X>#];
4244
// A-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: bar({#arg: Int#})[#A<Y>#];

test/IDE/complete_single_expression_return.swift

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,55 @@ struct TestSingleExprClosureGlobal {
128128
// TestSingleExprClosureGlobal-DAG: Decl[InstanceMethod]/CurrNominal: void()[#Void#];
129129
}
130130

131+
struct TestSingleExprClosureBinding {
132+
func void() -> Void {}
133+
func str() -> String { return "" }
134+
func int() -> Int { return 0 }
135+
136+
func test() -> Int {
137+
let fn = {
138+
self.#^TestSingleExprClosureBinding^#
139+
}
140+
return fn()
141+
}
142+
// Void is always valid in an implicit single expr closure.
143+
// TestSingleExprClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal: str()[#String#];
144+
// TestSingleExprClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal: int()[#Int#];
145+
// TestSingleExprClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal: void()[#Void#];
146+
}
147+
148+
struct TestExplicitSingleExprClosureBinding {
149+
func void() -> Void {}
150+
func str() -> String { return "" }
151+
func int() -> Int { return 0 }
152+
153+
func test() {
154+
let fn = {
155+
return self.#^TestExplicitSingleExprClosureBinding^#
156+
}
157+
}
158+
// FIXME: Because we have an explicit return, and no expected type, we shouldn't suggest Void.
159+
// TestExplicitSingleExprClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal: str()[#String#];
160+
// TestExplicitSingleExprClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal: int()[#Int#];
161+
// TestExplicitSingleExprClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal: void()[#Void#];
162+
}
163+
164+
struct TestExplicitSingleExprClosureBindingWithContext {
165+
func void() -> Void {}
166+
func str() -> String { return "" }
167+
func int() -> Int { return 0 }
168+
169+
func test() {
170+
let fn: () -> Void = {
171+
return self.#^TestExplicitSingleExprClosureBindingWithContext^#
172+
}
173+
}
174+
// We know Void is valid.
175+
// TestExplicitSingleExprClosureBindingWithContext-DAG: Decl[InstanceMethod]/CurrNominal: str()[#String#];
176+
// TestExplicitSingleExprClosureBindingWithContext-DAG: Decl[InstanceMethod]/CurrNominal: int()[#Int#];
177+
// TestExplicitSingleExprClosureBindingWithContext-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Convertible]: void()[#Void#];
178+
}
179+
131180
struct TestNonSingleExprClosureGlobal {
132181
func void() -> Void {}
133182
func str() -> String { return "" }
@@ -190,6 +239,21 @@ struct TestSingleExprFunc {
190239
// TestSingleExprFunc-DAG: Decl[InstanceMethod]/CurrNominal: void()[#Void#];
191240
}
192241

242+
struct TestSingleExprFuncReturnVoid {
243+
func void() -> Void {}
244+
func str() -> String { return "" }
245+
func int() -> Int { return 0 }
246+
247+
func test() {
248+
return self.#^TestSingleExprFuncReturnVoid^#
249+
}
250+
251+
// Void is the only possible type that can be used here.
252+
// TestSingleExprFuncReturnVoid-DAG: Decl[InstanceMethod]/CurrNominal: str()[#String#];
253+
// TestSingleExprFuncReturnVoid-DAG: Decl[InstanceMethod]/CurrNominal: int()[#Int#];
254+
// TestSingleExprFuncReturnVoid-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Convertible]: void()[#Void#];
255+
}
256+
193257
struct TestSingleExprFuncUnresolved {
194258
enum MyEnum { case myEnum }
195259
enum NotMine { case notMine }

0 commit comments

Comments
 (0)