Skip to content

Commit 2eeff36

Browse files
committed
[CodeCompletion] Record key path component types in the constraint system solution
The added test case fails because the result builder inside `List2` is being type checked twice: Once for every overload of `List2`. Because of the way that result builders are being type checked right now, each overload of `List2` creates a new type variable for the key components in `foo` and the constraint system only keeps track of the key path component -> type mapping for the last solution discovered. When we are now trying to look up the type of the first key path component for the first solution, the constraint system returns the type variable that is being used by the second solution and simplifying that type variable through the first solution fails because it doesn’t know about the type variable. To fix the issue, make sure that the solutions keep track of the their type variables associated to key path components. That way the first solution owns its own key path component -> type variable mapping and is thus also able to simplify the type variable it has associated with the component. Fixes rdar://80522345 [SR-14916]
1 parent b7633a1 commit 2eeff36

File tree

5 files changed

+48
-3
lines changed

5 files changed

+48
-3
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,10 @@ class Solution {
11851185
/// The node -> type mappings introduced by this solution.
11861186
llvm::DenseMap<ASTNode, Type> nodeTypes;
11871187

1188+
/// The key path component types introduced by this solution.
1189+
llvm::DenseMap<std::pair<const KeyPathExpr *, unsigned>, TypeBase *>
1190+
keyPathComponentTypes;
1191+
11881192
/// Contextual types introduced by this solution.
11891193
std::vector<std::pair<ASTNode, ContextualTypeInfo>> contextualTypes;
11901194

@@ -1300,6 +1304,9 @@ class Solution {
13001304
/// Retrieve the type of the given node, as recorded in this solution.
13011305
Type getType(ASTNode node) const;
13021306

1307+
/// Retrieve the type of the \p ComponentIndex-th component in \p KP.
1308+
Type getType(const KeyPathExpr *KP, unsigned ComponentIndex) const;
1309+
13031310
/// Retrieve the type of the given node as recorded in this solution
13041311
/// and resolve all of the type variables in contains to form a fully
13051312
/// "resolved" concrete type.

lib/Sema/CSApply.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8900,8 +8900,9 @@ bool Solution::hasType(ASTNode node) const {
89008900
}
89018901

89028902
bool Solution::hasType(const KeyPathExpr *KP, unsigned ComponentIndex) const {
8903-
auto &cs = getConstraintSystem();
8904-
return cs.hasType(KP, ComponentIndex);
8903+
assert(KP && "Expected non-null key path parameter!");
8904+
return keyPathComponentTypes.find(std::make_pair(KP, ComponentIndex))
8905+
!= keyPathComponentTypes.end();
89058906
}
89068907

89078908
Type Solution::getType(ASTNode node) const {
@@ -8913,6 +8914,11 @@ Type Solution::getType(ASTNode node) const {
89138914
return cs.getType(node);
89148915
}
89158916

8917+
Type Solution::getType(const KeyPathExpr *KP, unsigned I) const {
8918+
assert(hasType(KP, I) && "Expected type to have been set!");
8919+
return keyPathComponentTypes.find(std::make_pair(KP, I))->second;
8920+
}
8921+
89168922
Type Solution::getResolvedType(ASTNode node) const {
89178923
return simplifyType(getType(node));
89188924
}

lib/Sema/CSSolver.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ Solution ConstraintSystem::finalize() {
175175
for (auto &nodeType : NodeTypes) {
176176
solution.nodeTypes.insert(nodeType);
177177
}
178+
for (auto &keyPathComponentType : KeyPathComponentTypes) {
179+
solution.keyPathComponentTypes.insert(keyPathComponentType);
180+
}
178181

179182
// Remember contextual types.
180183
solution.contextualTypes.assign(

lib/Sema/TypeCheckCodeCompletion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1347,7 +1347,7 @@ void KeyPathTypeCheckCompletionCallback::sawSolution(
13471347
} else {
13481348
// We are completing after a component. Get the previous component's result
13491349
// type.
1350-
BaseType = S.simplifyType(CS.getType(KeyPath, ComponentIndex - 1));
1350+
BaseType = S.simplifyType(S.getType(KeyPath, ComponentIndex - 1));
13511351
}
13521352

13531353
// If ExpectedTy is a duplicate of any other result, ignore this solution.

test/IDE/complete_sr14916.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %swift-ide-test -code-completion -code-completion-token COMPLETE -source-filename %s | %FileCheck %s
2+
3+
struct Foo {
4+
var bar: Int
5+
}
6+
7+
protocol View2 {}
8+
struct EmptyView: View2 {}
9+
10+
@resultBuilder public struct ViewBuilder2 {
11+
public static func buildBlock(_ content: EmptyView) -> EmptyView { fatalError() }
12+
}
13+
14+
public struct List2 {
15+
public init(selection: Int?, @ViewBuilder2 content: () -> EmptyView)
16+
public init(selection: String?, @ViewBuilder2 content: () -> EmptyView)
17+
}
18+
19+
func foo(kp: (Foo) -> String) {}
20+
21+
func foo() {
22+
List2 {
23+
foo(kp: \.self#^COMPLETE^#)
24+
// CHECK: Begin completions, 1 items
25+
// CHECK-NEXT: Decl[InstanceVar]/CurrNominal: .bar[#Int#];
26+
// CHECK-NEXT: End completions
27+
}
28+
.unknownMethod()
29+
}

0 commit comments

Comments
 (0)