Skip to content

Commit 5af9282

Browse files
committed
[CS] Avoid penalizing holes for placeholder vars for completion
When doing completion in a result builder, we avoid solving unrelated expressions by replacing them with unbound placeholder variables. Avoid penalizing assigning holes to these placeholders, since otherwise we end up unnecessarily exploring the entire solution space, and bailing due to too complex. rdar://144382123
1 parent b03e989 commit 5af9282

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2895,6 +2895,21 @@ static bool shouldIgnoreHoleForCodeCompletion(ConstraintSystem &cs,
28952895
if (typeVar->getImpl().isCodeCompletionToken())
28962896
return true;
28972897

2898+
// When doing completion in a result builder, we avoid solving unrelated
2899+
// expressions by replacing them with unbound placeholder variables.
2900+
// As such, we need to avoid penalizing holes for references to
2901+
// placeholder variables.
2902+
if (srcLocator->isLastElement<LocatorPathElt::PlaceholderType>()) {
2903+
if (auto *DRE = getAsExpr<DeclRefExpr>(srcLocator->getAnchor())) {
2904+
if (auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl())) {
2905+
if (auto *PBD = VD->getParentPatternBinding()) {
2906+
if (isPlaceholderVar(PBD))
2907+
return true;
2908+
}
2909+
}
2910+
}
2911+
}
2912+
28982913
// Don't penalize solutions with holes due to missing arguments after the
28992914
// code completion position.
29002915
auto argLoc = srcLocator->findLast<LocatorPathElt::SynthesizedArgument>();

test/IDE/issue-79213.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %batch-code-completion
2+
3+
protocol View {}
4+
5+
struct EmptyView: View {}
6+
struct Either<T: View, U: View>: View {}
7+
struct Tuple<T>: View {}
8+
extension Optional: View where Wrapped: View {}
9+
10+
@resultBuilder
11+
struct ViewBuilder {
12+
static func buildBlock() -> EmptyView { .init() }
13+
static func buildBlock<T: View>(_ x: T) -> T { x }
14+
@_disfavoredOverload static func buildBlock<each T: View>(
15+
_ x: repeat each T
16+
) -> Tuple<(repeat each T)> { .init() }
17+
static func buildEither<T, U>(first component: T) -> Either<T, U> { .init() }
18+
static func buildEither<T, U>(second component: U) -> Either<T, U> { .init() }
19+
static func buildIf<T: View>(_ x: T?) -> T? { x }
20+
}
21+
22+
struct R {
23+
var bar: Bool
24+
}
25+
26+
func baz<R>(@ViewBuilder _ fn: () -> R) {}
27+
28+
// https://github.com/swiftlang/swift/issues/79213 - Make sure we get a result here.
29+
func foo(_ x: R, _ b: Bool) {
30+
baz {
31+
if b {
32+
EmptyView()
33+
} else if b {
34+
if x.#^COMPLETE^# {}
35+
// COMPLETE: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: bar[#Bool#]; name=bar
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)