Skip to content

Commit 3339ea4

Browse files
committed
[CS] Fix invalid key path crasher
Previously we were bailing early on encountering an optional chain in the key path. However this could cause us to miss invalid components further down the line. Instead, set a flag and force the key path to be read-only if we encountered an optional chain. Resolves SR-12519.
1 parent 94d8ffe commit 3339ea4

File tree

2 files changed

+19
-7
lines changed

2 files changed

+19
-7
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7543,6 +7543,7 @@ ConstraintSystem::simplifyKeyPathConstraint(
75437543
} capability = Writable;
75447544

75457545
bool anyComponentsUnresolved = false;
7546+
bool didOptionalChain = false;
75467547

75477548
for (unsigned i : indices(keyPath->getComponents())) {
75487549
auto &component = keyPath->getComponents()[i];
@@ -7642,26 +7643,27 @@ ConstraintSystem::simplifyKeyPathConstraint(
76427643
}
76437644

76447645
case KeyPathExpr::Component::Kind::OptionalChain:
7645-
// Optional chains force the entire key path to be read-only.
7646-
capability = ReadOnly;
7647-
goto done;
7646+
didOptionalChain = true;
7647+
break;
76487648

76497649
case KeyPathExpr::Component::Kind::OptionalForce:
76507650
// Forcing an optional preserves its lvalue-ness.
76517651
break;
76527652

76537653
case KeyPathExpr::Component::Kind::OptionalWrap:
7654-
// An optional chain should already have forced the entire key path to
7655-
// be read-only.
7656-
assert(capability == ReadOnly);
7654+
// An optional chain should already have been recorded.
7655+
assert(didOptionalChain);
76577656
break;
76587657

76597658
case KeyPathExpr::Component::Kind::TupleElement:
76607659
llvm_unreachable("not implemented");
76617660
break;
76627661
}
76637662
}
7664-
done:
7663+
7664+
// Optional chains force the entire key path to be read-only.
7665+
if (didOptionalChain)
7666+
capability = ReadOnly;
76657667

76667668
// Resolve the type.
76677669
NominalTypeDecl *kpDecl;

test/expr/unary/keypath/keypath.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,16 @@ func test_keypath_with_method_refs() {
811811
let _ = \A.Type.faz.bar // expected-error {{key path cannot refer to static method 'faz()'}}
812812
}
813813

814+
// SR-12519: Compiler crash on invalid method reference in key path.
815+
protocol Zonk {
816+
func wargle()
817+
}
818+
typealias Blatz = (gloop: String, zoop: Zonk?)
819+
820+
func sr12519(fleep: [Blatz]) {
821+
fleep.compactMap(\.zoop?.wargle) // expected-error {{key path cannot refer to instance method 'wargle()'}}
822+
}
823+
814824
// SR-10467 - Argument type 'KeyPath<String, Int>' does not conform to expected type 'Any'
815825
func test_keypath_in_any_context() {
816826
func foo(_: Any) {}

0 commit comments

Comments
 (0)