Merge pull request #17791 from slavapestov/index-keypaths-4.2
IDE: Index references from keypaths [4.2]
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index 3b72b27..c732fad 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -6949,13 +6949,18 @@
// Drop non-property, non-type candidates.
if (!isa<VarDecl>(result.getValueDecl()) &&
- !isa<TypeDecl>(result.getValueDecl()))
+ !isa<TypeDecl>(result.getValueDecl()) &&
+ !isa<SubscriptDecl>(result.getValueDecl()))
return false;
return true;
});
}
+ // If all results were unavailable, fail.
+ if (!lookup)
+ break;
+
// If we *still* have more than one result, fail.
if (lookup.size() > 1) {
// Don't diagnose ambiguities if the results are from typo correction.
diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp
index 07f653a..3e7cf92 100644
--- a/lib/Sema/TypeCheckAvailability.cpp
+++ b/lib/Sema/TypeCheckAvailability.cpp
@@ -2306,6 +2306,9 @@
maybeDiagStorageAccess(S->getDecl().getDecl(), S->getSourceRange(), DC);
}
}
+ if (auto KP = dyn_cast<KeyPathExpr>(E)) {
+ maybeDiagKeyPath(KP);
+ }
if (auto A = dyn_cast<AssignExpr>(E)) {
walkAssignExpr(A);
return skipChildren();
@@ -2399,7 +2402,32 @@
// Diagnose for appropriate accessors, given the access context.
maybeDiagStorageAccess(D, E->getSourceRange(), DC);
}
-
+
+ /// Walk a keypath expression, checking all of its components for
+ /// availability.
+ void maybeDiagKeyPath(KeyPathExpr *KP) {
+ for (auto &component : KP->getComponents()) {
+ switch (component.getKind()) {
+ case KeyPathExpr::Component::Kind::Property:
+ case KeyPathExpr::Component::Kind::Subscript: {
+ auto *decl = component.getDeclRef().getDecl();
+ auto loc = component.getLoc();
+ SourceRange range(loc, loc);
+ diagAvailability(decl, range, nullptr);
+ break;
+ }
+
+ case KeyPathExpr::Component::Kind::Invalid:
+ case KeyPathExpr::Component::Kind::UnresolvedProperty:
+ case KeyPathExpr::Component::Kind::UnresolvedSubscript:
+ case KeyPathExpr::Component::Kind::OptionalChain:
+ case KeyPathExpr::Component::Kind::OptionalWrap:
+ case KeyPathExpr::Component::Kind::OptionalForce:
+ break;
+ }
+ }
+ }
+
/// Walk an inout expression, checking for availability.
void walkInOutExpr(InOutExpr *E) {
walkInContext(E, E->getSubExpr(), MemberAccessContext::InOut);
diff --git a/test/attr/attr_inlinable.swift b/test/attr/attr_inlinable.swift
index efea113..d4428c7 100644
--- a/test/attr/attr_inlinable.swift
+++ b/test/attr/attr_inlinable.swift
@@ -251,3 +251,13 @@
var x = internalGlobal // expected-error {{let 'internalGlobal' is internal and cannot be referenced from a property initializer in a '@_fixed_layout' type}}
var y = publicGlobal // OK
}
+
+public struct KeypathStruct {
+ var x: Int
+ // expected-note@-1 {{var 'x' is not '@usableFromInline' or public}}
+
+ @inlinable public func usesKeypath() {
+ _ = \KeypathStruct.x
+ // expected-error@-1 {{var 'x' is internal and cannot be referenced from an '@inlinable' function}}
+ }
+}
diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift
index a6307b2..ade6166 100644
--- a/test/expr/unary/keypath/keypath.swift
+++ b/test/expr/unary/keypath/keypath.swift
@@ -44,6 +44,29 @@
subscript<X>(noHashableConstraint sub: X) -> X { get { return sub } set { } }
}
+struct Unavailable {
+ @available(*, unavailable)
+ var unavailableProperty: Int
+ // expected-note@-1 {{'unavailableProperty' has been explicitly marked unavailable here}}
+
+ @available(*, unavailable)
+ subscript(x: Sub) -> Int { get { } set { } }
+ // expected-note@-1 {{'subscript' has been explicitly marked unavailable here}}
+}
+
+struct Deprecated {
+ @available(*, deprecated)
+ var deprecatedProperty: Int
+
+ @available(*, deprecated)
+ subscript(x: Sub) -> Int { get { } set { } }
+}
+
+@available(*, deprecated)
+func getDeprecatedSub() -> Sub {
+ return Sub()
+}
+
extension Array where Element == A {
var property: Prop { fatalError() }
}
@@ -178,6 +201,14 @@
let _ = \C<Int>.[sub]
let _ = \C<Int>.[noHashableConstraint: sub]
let _ = \C<Int>.[noHashableConstraint: nonHashableSub] // expected-error{{subscript index of type 'NonHashableSub' in a key path must be Hashable}}
+
+ let _ = \Unavailable.unavailableProperty // expected-error {{'unavailableProperty' is unavailable}}
+ let _ = \Unavailable.[sub] // expected-error {{'subscript' is unavailable}}
+
+ let _ = \Deprecated.deprecatedProperty // expected-warning {{'deprecatedProperty' is deprecated}}
+ let _ = \Deprecated.[sub] // expected-warning {{'subscript' is deprecated}}
+
+ let _ = \A.[getDeprecatedSub()] // expected-warning {{'getDeprecatedSub()' is deprecated}}
}
func testKeyPathInGenericContext<H: Hashable, X>(hashable: H, anything: X) {
@@ -471,6 +502,33 @@
_ = \BassSubscript.["hello"] // expected-error{{must be Hashable}}
}
+// Crash in diagnostics
+struct AmbiguousSubscript {
+ subscript(sub: Sub) -> Int { get { } set { } }
+ // expected-note@-1 {{'subscript' declared here}}
+
+ subscript(y y: Sub) -> Int { get { } set { } }
+ // expected-note@-1 {{'subscript(y:)' declared here}}
+}
+
+func useAmbiguousSubscript(_ sub: Sub) {
+ let _: PartialKeyPath<AmbiguousSubscript> = \.[sub]
+ // expected-error@-1 {{ambiguous reference to member 'subscript'}}
+}
+
+struct BothUnavailableSubscript {
+ @available(*, unavailable)
+ subscript(sub: Sub) -> Int { get { } set { } }
+
+ @available(*, unavailable)
+ subscript(y y: Sub) -> Int { get { } set { } }
+}
+
+func useBothUnavailableSubscript(_ sub: Sub) {
+ let _: PartialKeyPath<BothUnavailableSubscript> = \.[sub]
+ // expected-error@-1 {{type of expression is ambiguous without more context}}
+}
+
// SR-6106
func sr6106() {
class B {}