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 {}