Skip to content

Commit 7ee89cd

Browse files
authored
Merge pull request #17780 from slavapestov/keypath-availability-check-4.2
Sema: Check availability of key path components [4.2]
2 parents 68b5805 + 3d8493b commit 7ee89cd

File tree

4 files changed

+103
-2
lines changed

4 files changed

+103
-2
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6949,13 +6949,18 @@ static bool diagnoseKeyPathComponents(ConstraintSystem &CS, KeyPathExpr *KPE,
69496949

69506950
// Drop non-property, non-type candidates.
69516951
if (!isa<VarDecl>(result.getValueDecl()) &&
6952-
!isa<TypeDecl>(result.getValueDecl()))
6952+
!isa<TypeDecl>(result.getValueDecl()) &&
6953+
!isa<SubscriptDecl>(result.getValueDecl()))
69536954
return false;
69546955

69556956
return true;
69566957
});
69576958
}
69586959

6960+
// If all results were unavailable, fail.
6961+
if (!lookup)
6962+
break;
6963+
69596964
// If we *still* have more than one result, fail.
69606965
if (lookup.size() > 1) {
69616966
// Don't diagnose ambiguities if the results are from typo correction.

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2306,6 +2306,9 @@ class AvailabilityWalker : public ASTWalker {
23062306
maybeDiagStorageAccess(S->getDecl().getDecl(), S->getSourceRange(), DC);
23072307
}
23082308
}
2309+
if (auto KP = dyn_cast<KeyPathExpr>(E)) {
2310+
maybeDiagKeyPath(KP);
2311+
}
23092312
if (auto A = dyn_cast<AssignExpr>(E)) {
23102313
walkAssignExpr(A);
23112314
return skipChildren();
@@ -2399,7 +2402,32 @@ class AvailabilityWalker : public ASTWalker {
23992402
// Diagnose for appropriate accessors, given the access context.
24002403
maybeDiagStorageAccess(D, E->getSourceRange(), DC);
24012404
}
2402-
2405+
2406+
/// Walk a keypath expression, checking all of its components for
2407+
/// availability.
2408+
void maybeDiagKeyPath(KeyPathExpr *KP) {
2409+
for (auto &component : KP->getComponents()) {
2410+
switch (component.getKind()) {
2411+
case KeyPathExpr::Component::Kind::Property:
2412+
case KeyPathExpr::Component::Kind::Subscript: {
2413+
auto *decl = component.getDeclRef().getDecl();
2414+
auto loc = component.getLoc();
2415+
SourceRange range(loc, loc);
2416+
diagAvailability(decl, range, nullptr);
2417+
break;
2418+
}
2419+
2420+
case KeyPathExpr::Component::Kind::Invalid:
2421+
case KeyPathExpr::Component::Kind::UnresolvedProperty:
2422+
case KeyPathExpr::Component::Kind::UnresolvedSubscript:
2423+
case KeyPathExpr::Component::Kind::OptionalChain:
2424+
case KeyPathExpr::Component::Kind::OptionalWrap:
2425+
case KeyPathExpr::Component::Kind::OptionalForce:
2426+
break;
2427+
}
2428+
}
2429+
}
2430+
24032431
/// Walk an inout expression, checking for availability.
24042432
void walkInOutExpr(InOutExpr *E) {
24052433
walkInContext(E, E->getSubExpr(), MemberAccessContext::InOut);

test/attr/attr_inlinable.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,13 @@ public struct PublicFixedStructWithInit {
251251
var x = internalGlobal // expected-error {{let 'internalGlobal' is internal and cannot be referenced from a property initializer in a '@_fixed_layout' type}}
252252
var y = publicGlobal // OK
253253
}
254+
255+
public struct KeypathStruct {
256+
var x: Int
257+
// expected-note@-1 {{var 'x' is not '@usableFromInline' or public}}
258+
259+
@inlinable public func usesKeypath() {
260+
_ = \KeypathStruct.x
261+
// expected-error@-1 {{var 'x' is internal and cannot be referenced from an '@inlinable' function}}
262+
}
263+
}

test/expr/unary/keypath/keypath.swift

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,29 @@ struct C<T> {
4444
subscript<X>(noHashableConstraint sub: X) -> X { get { return sub } set { } }
4545
}
4646

47+
struct Unavailable {
48+
@available(*, unavailable)
49+
var unavailableProperty: Int
50+
// expected-note@-1 {{'unavailableProperty' has been explicitly marked unavailable here}}
51+
52+
@available(*, unavailable)
53+
subscript(x: Sub) -> Int { get { } set { } }
54+
// expected-note@-1 {{'subscript' has been explicitly marked unavailable here}}
55+
}
56+
57+
struct Deprecated {
58+
@available(*, deprecated)
59+
var deprecatedProperty: Int
60+
61+
@available(*, deprecated)
62+
subscript(x: Sub) -> Int { get { } set { } }
63+
}
64+
65+
@available(*, deprecated)
66+
func getDeprecatedSub() -> Sub {
67+
return Sub()
68+
}
69+
4770
extension Array where Element == A {
4871
var property: Prop { fatalError() }
4972
}
@@ -178,6 +201,14 @@ func testKeyPath(sub: Sub, optSub: OptSub,
178201
let _ = \C<Int>.[sub]
179202
let _ = \C<Int>.[noHashableConstraint: sub]
180203
let _ = \C<Int>.[noHashableConstraint: nonHashableSub] // expected-error{{subscript index of type 'NonHashableSub' in a key path must be Hashable}}
204+
205+
let _ = \Unavailable.unavailableProperty // expected-error {{'unavailableProperty' is unavailable}}
206+
let _ = \Unavailable.[sub] // expected-error {{'subscript' is unavailable}}
207+
208+
let _ = \Deprecated.deprecatedProperty // expected-warning {{'deprecatedProperty' is deprecated}}
209+
let _ = \Deprecated.[sub] // expected-warning {{'subscript' is deprecated}}
210+
211+
let _ = \A.[getDeprecatedSub()] // expected-warning {{'getDeprecatedSub()' is deprecated}}
181212
}
182213

183214
func testKeyPathInGenericContext<H: Hashable, X>(hashable: H, anything: X) {
@@ -471,6 +502,33 @@ func testImplicitConversionInSubscriptIndex() {
471502
_ = \BassSubscript.["hello"] // expected-error{{must be Hashable}}
472503
}
473504

505+
// Crash in diagnostics
506+
struct AmbiguousSubscript {
507+
subscript(sub: Sub) -> Int { get { } set { } }
508+
// expected-note@-1 {{'subscript' declared here}}
509+
510+
subscript(y y: Sub) -> Int { get { } set { } }
511+
// expected-note@-1 {{'subscript(y:)' declared here}}
512+
}
513+
514+
func useAmbiguousSubscript(_ sub: Sub) {
515+
let _: PartialKeyPath<AmbiguousSubscript> = \.[sub]
516+
// expected-error@-1 {{ambiguous reference to member 'subscript'}}
517+
}
518+
519+
struct BothUnavailableSubscript {
520+
@available(*, unavailable)
521+
subscript(sub: Sub) -> Int { get { } set { } }
522+
523+
@available(*, unavailable)
524+
subscript(y y: Sub) -> Int { get { } set { } }
525+
}
526+
527+
func useBothUnavailableSubscript(_ sub: Sub) {
528+
let _: PartialKeyPath<BothUnavailableSubscript> = \.[sub]
529+
// expected-error@-1 {{type of expression is ambiguous without more context}}
530+
}
531+
474532
// SR-6106
475533
func sr6106() {
476534
class B {}

0 commit comments

Comments
 (0)