Skip to content

Commit 9157372

Browse files
authored
Merge pull request swiftlang#9840 from jckarter/already-checked-key-path
Sema: Don't crash when type-checking a KeyPathExpr that's already type-checked.
2 parents 5034dc6 + 2425258 commit 9157372

File tree

4 files changed

+83
-4
lines changed

4 files changed

+83
-4
lines changed

include/swift/AST/Expr.h

+19
Original file line numberDiff line numberDiff line change
@@ -4744,6 +4744,25 @@ class KeyPathExpr : public Expr {
47444744
return getKind() != Kind::Invalid;
47454745
}
47464746

4747+
bool isResolved() const {
4748+
if (!getComponentType())
4749+
return false;
4750+
4751+
switch (getKind()) {
4752+
case Kind::Subscript:
4753+
case Kind::OptionalChain:
4754+
case Kind::OptionalWrap:
4755+
case Kind::OptionalForce:
4756+
case Kind::Property:
4757+
return true;
4758+
4759+
case Kind::UnresolvedSubscript:
4760+
case Kind::UnresolvedProperty:
4761+
case Kind::Invalid:
4762+
return false;
4763+
}
4764+
}
4765+
47474766
Expr *getIndexExpr() const {
47484767
switch (getKind()) {
47494768
case Kind::Subscript:

lib/Sema/CSApply.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -3986,6 +3986,20 @@ namespace {
39863986
if (E->getType()->hasError())
39873987
return E;
39883988

3989+
// If a component is already resolved, then all of them should be
3990+
// resolved, and we can let the expression be. This might happen when
3991+
// re-checking a failed system for diagnostics.
3992+
if (!E->getComponents().empty()
3993+
&& E->getComponents().front().isResolved()) {
3994+
assert([&]{
3995+
for (auto &c : E->getComponents())
3996+
if (!c.isResolved())
3997+
return false;
3998+
return true;
3999+
}());
4000+
return E;
4001+
}
4002+
39894003
SmallVector<KeyPathExpr::Component, 4> resolvedComponents;
39904004

39914005
// Resolve each of the components.

lib/Sema/CSGen.cpp

+19-4
Original file line numberDiff line numberDiff line change
@@ -2757,11 +2757,26 @@ namespace {
27572757
return ErrorType::get(CS.getASTContext());
27582758
}
27592759

2760-
// If the key path contained any syntactically invalid components, bail
2761-
// out.
2762-
for (auto &c : E->getComponents())
2763-
if (!c.isValid())
2760+
for (auto &c : E->getComponents()) {
2761+
// If the key path contained any syntactically invalid components, bail
2762+
// out.
2763+
if (!c.isValid()) {
27642764
return ErrorType::get(CS.getASTContext());
2765+
}
2766+
2767+
// If a component is already resolved, then all of them should be
2768+
// resolved, and we can let the expression be. This might happen when
2769+
// re-checking a failed system for diagnostics.
2770+
if (c.isResolved()) {
2771+
assert([&]{
2772+
for (auto &c : E->getComponents())
2773+
if (!c.isResolved())
2774+
return false;
2775+
return true;
2776+
}());
2777+
return E->getType();
2778+
}
2779+
}
27652780

27662781
// For native key paths, traverse the key path components to set up
27672782
// appropriate type relationships at each level.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %target-swift-frontend -typecheck -verify %s
2+
3+
// Ensure that key path exprs can tolerate being re-type-checked when necessary
4+
// to diagnose other errors in adjacent exprs.
5+
6+
struct P<T: K> { }
7+
8+
struct S {
9+
init<B>(_ a: P<B>) {
10+
fatalError()
11+
}
12+
}
13+
14+
protocol K { }
15+
16+
func + <Object>(lhs: KeyPath<A, Object>, rhs: String) -> P<Object> {
17+
fatalError()
18+
}
19+
20+
// expected-error@+1{{}}
21+
func + (lhs: KeyPath<A, String>, rhs: String) -> P<String> {
22+
fatalError()
23+
}
24+
25+
struct A {
26+
let id: String
27+
}
28+
29+
extension A: K {
30+
static let j = S(\A.id + "id")
31+
}

0 commit comments

Comments
 (0)