@@ -3917,6 +3917,62 @@ static void diagnoseUnintendedOptionalBehavior(TypeChecker &TC, const Expr *E,
3917
3917
const_cast <Expr *>(E)->walk (Walker);
3918
3918
}
3919
3919
3920
+ static void diagnoseDeprecatedWritableKeyPath (TypeChecker &TC, const Expr *E,
3921
+ const DeclContext *DC) {
3922
+ if (!E || isa<ErrorExpr>(E) || !E->getType ())
3923
+ return ;
3924
+
3925
+ class DeprecatedWritableKeyPathWalker : public ASTWalker {
3926
+ TypeChecker &TC;
3927
+ const DeclContext *DC;
3928
+
3929
+ void visitKeyPathApplicationExpr (KeyPathApplicationExpr *E) {
3930
+ if (E->hasLValueAccessKind () &&
3931
+ E->getLValueAccessKind () == AccessKind::Read)
3932
+ return ;
3933
+
3934
+ if (auto *keyPathExpr = dyn_cast<KeyPathExpr>(E->getKeyPath ())) {
3935
+ auto *decl = keyPathExpr->getType ()->getNominalOrBoundGenericNominal ();
3936
+ if (decl != TC.Context .getWritableKeyPathDecl () &&
3937
+ decl != TC.Context .getReferenceWritableKeyPathDecl ())
3938
+ return ;
3939
+
3940
+ assert (keyPathExpr->getComponents ().size () > 0 );
3941
+ auto &component = keyPathExpr->getComponents ().back ();
3942
+ if (component.getKind () == KeyPathExpr::Component::Kind::Property) {
3943
+ auto *storage =
3944
+ cast<AbstractStorageDecl>(component.getDeclRef ().getDecl ());
3945
+ if (!storage->isSettable (nullptr ) ||
3946
+ !storage->isSetterAccessibleFrom (DC)) {
3947
+ TC.diagnose (keyPathExpr->getLoc (),
3948
+ swift::diag::expr_deprecated_writable_keypath,
3949
+ storage->getFullName ());
3950
+ }
3951
+ }
3952
+ }
3953
+ }
3954
+
3955
+ std::pair<bool , Expr *> walkToExprPre (Expr *E) override {
3956
+ if (!E || isa<ErrorExpr>(E) || !E->getType ())
3957
+ return {false , E};
3958
+
3959
+ if (auto *KPAE = dyn_cast<KeyPathApplicationExpr>(E)) {
3960
+ visitKeyPathApplicationExpr (KPAE);
3961
+ return {true , E};
3962
+ }
3963
+
3964
+ return {true , E};
3965
+ }
3966
+
3967
+ public:
3968
+ DeprecatedWritableKeyPathWalker (TypeChecker &TC, const DeclContext *DC)
3969
+ : TC(TC), DC(DC) {}
3970
+ };
3971
+
3972
+ DeprecatedWritableKeyPathWalker Walker (TC, DC);
3973
+ const_cast <Expr *>(E)->walk (Walker);
3974
+ }
3975
+
3920
3976
// ===----------------------------------------------------------------------===//
3921
3977
// High-level entry points.
3922
3978
// ===----------------------------------------------------------------------===//
@@ -3930,6 +3986,8 @@ void swift::performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E,
3930
3986
diagRecursivePropertyAccess (TC, E, DC);
3931
3987
diagnoseImplicitSelfUseInClosure (TC, E, DC);
3932
3988
diagnoseUnintendedOptionalBehavior (TC, E, DC);
3989
+ if (!TC.Context .isSwiftVersionAtLeast (5 ))
3990
+ diagnoseDeprecatedWritableKeyPath (TC, E, DC);
3933
3991
if (!TC.getLangOpts ().DisableAvailabilityChecking )
3934
3992
diagAvailability (TC, E, const_cast <DeclContext*>(DC));
3935
3993
if (TC.Context .LangOpts .EnableObjCInterop )
0 commit comments