Skip to content

Commit 5e4b371

Browse files
committed
If static keypath is declared in module built with Swift 6.0 compiler or older,
emit diagnostic that recommends rebuilding that module.
1 parent 8baf1e6 commit 5e4b371

File tree

5 files changed

+54
-14
lines changed

5 files changed

+54
-14
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,11 @@ WARNING(expr_deprecated_writable_keypath,Deprecation,
724724
"forming a writable keypath to property %0 that is read-only in this context "
725725
"is deprecated and will be removed in a future release",
726726
(const ValueDecl *))
727+
ERROR(static_keypath_older_compiler_version,none,
728+
"cannot form a keypath to a static property %0 of type %1",
729+
(const ValueDecl *, Type))
730+
NOTE(rebuild_module,none,
731+
"rebuild %0 to enable the feature", (const ModuleDecl *))
727732

728733
// Selector expressions.
729734
ERROR(expr_selector_no_objc_runtime,none,

include/swift/Sema/CSFix.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,6 +2023,9 @@ class TreatKeyPathSubscriptIndexAsHashable final : public ConstraintFix {
20232023

20242024
class AllowInvalidRefInKeyPath final : public ConstraintFix {
20252025
enum RefKind {
2026+
// Allow a reference to a static member as a key path component if it is
2027+
// declared in a module with built with Swift 6.0 compiler version or older.
2028+
StaticMember,
20262029
// Allow a reference to a declaration with mutating getter as
20272030
// a key path component.
20282031
MutatingGetter,
@@ -2038,15 +2041,20 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
20382041

20392042
ValueDecl *Member;
20402043
Type BaseType;
2044+
Identifier ModuleName;
20412045

20422046
AllowInvalidRefInKeyPath(ConstraintSystem &cs, Type baseType, RefKind kind,
2043-
ValueDecl *member, ConstraintLocator *locator)
2047+
ValueDecl *member, Identifier moduleName, ConstraintLocator *locator)
20442048
: ConstraintFix(cs, FixKind::AllowInvalidRefInKeyPath, locator),
2045-
Kind(kind), Member(member), BaseType(baseType) {}
2049+
Kind(kind), Member(member), BaseType(baseType), ModuleName(moduleName) {}
20462050

20472051
public:
20482052
std::string getName() const override {
20492053
switch (Kind) {
2054+
case RefKind::StaticMember:
2055+
return "allow reference to a static member as a key path component if "
2056+
"member is declared in a module built with Swift 6.0 compiler or "
2057+
"older.";
20502058
case RefKind::MutatingGetter:
20512059
return "allow reference to a member with mutating getter as a key "
20522060
"path component";
@@ -2077,7 +2085,7 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
20772085

20782086
private:
20792087
static AllowInvalidRefInKeyPath *create(ConstraintSystem &cs, Type baseType,
2080-
RefKind kind, ValueDecl *member,
2088+
RefKind kind, ValueDecl *member, Identifier moduleName,
20812089
ConstraintLocator *locator);
20822090
};
20832091

lib/Sema/CSDiagnostics.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4975,8 +4975,7 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
49754975
// If this is a reference to a static member by one of the key path
49764976
// components, let's provide a tailored diagnostic with fix-it.
49774977
if (locator->isInKeyPathComponent()) {
4978-
InvalidStaticMemberRefInKeyPath failure(getSolution(), BaseType, Member,
4979-
locator);
4978+
InvalidStaticMemberRefInKeyPath failure(getSolution(), BaseType, Member, Identifier(), locator);
49804979
return failure.diagnoseAsError();
49814980
}
49824981

@@ -6268,10 +6267,16 @@ SourceLoc InvalidMemberRefInKeyPath::getLoc() const {
62686267
}
62696268

62706269
bool InvalidStaticMemberRefInKeyPath::diagnoseAsError() {
6270+
if (!getModuleName().empty()) {
6271+
emitDiagnostic(diag::static_keypath_older_compiler_version, getMember(), getBaseType());
6272+
// emitDiagnosticAt(getMember(), diag::rebuild_module, getModuleName());
6273+
return true;
6274+
}
6275+
62716276
auto *KPE = getAsExpr<KeyPathExpr>(getRawAnchor());
62726277
auto rootTyRepr = KPE->getExplicitRootType();
62736278
auto isProtocol = getBaseType()->isExistentialType();
6274-
6279+
62756280
if (rootTyRepr && !isProtocol) {
62766281
emitDiagnostic(diag::expr_keypath_static_member, getMember(), getBaseType())
62776282
.fixItInsert(rootTyRepr->getEndLoc(), ".Type");

lib/Sema/CSDiagnostics.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,14 +1762,17 @@ class InvalidMemberRefInKeyPath : public FailureDiagnostic {
17621762
/// ```
17631763
class InvalidStaticMemberRefInKeyPath final : public InvalidMemberRefInKeyPath {
17641764
Type BaseType;
1765+
Identifier ModuleName;
17651766

17661767
public:
17671768
InvalidStaticMemberRefInKeyPath(const Solution &solution, Type baseType,
1768-
ValueDecl *member, ConstraintLocator *locator)
1769+
ValueDecl *member, Identifier moduleName, ConstraintLocator *locator)
17691770
: InvalidMemberRefInKeyPath(solution, member, locator),
1770-
BaseType(baseType->getRValueType()) {}
1771+
BaseType(baseType->getRValueType()), ModuleName(moduleName) {}
17711772

17721773
Type getBaseType() const { return BaseType; }
1774+
1775+
Identifier getModuleName() const { return ModuleName; }
17731776

17741777
bool diagnoseAsError() override;
17751778
};

lib/Sema/CSFix.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,6 +1206,10 @@ TreatKeyPathSubscriptIndexAsHashable::create(ConstraintSystem &cs, Type type,
12061206
bool AllowInvalidRefInKeyPath::diagnose(const Solution &solution,
12071207
bool asNote) const {
12081208
switch (Kind) {
1209+
case RefKind::StaticMember: {
1210+
InvalidStaticMemberRefInKeyPath failure(solution, BaseType, Member, ModuleName, getLocator());
1211+
return failure.diagnose(asNote);
1212+
}
12091213
case RefKind::EnumCase: {
12101214
InvalidEnumCaseRefInKeyPath failure(solution, Member, getLocator());
12111215
return failure.diagnose(asNote);
@@ -1257,36 +1261,51 @@ AllowInvalidRefInKeyPath::forRef(ConstraintSystem &cs, Type baseType,
12571261
// not currently allowed.
12581262
if (isa<FuncDecl>(member))
12591263
return AllowInvalidRefInKeyPath::create(cs, baseType, RefKind::Method,
1260-
member, locator);
1264+
member, Identifier(), locator);
12611265

12621266
// Referencing enum cases in key path is not currently allowed.
12631267
if (isa<EnumElementDecl>(member)) {
12641268
return AllowInvalidRefInKeyPath::create(cs, baseType, RefKind::EnumCase,
1265-
member, locator);
1269+
member, Identifier(), locator);
12661270
}
12671271

12681272
// Referencing initializers in key path is not currently allowed.
12691273
if (isa<ConstructorDecl>(member))
12701274
return AllowInvalidRefInKeyPath::create(cs, baseType, RefKind::Initializer,
1271-
member, locator);
1275+
member, Identifier(), locator);
1276+
1277+
// Referencing static members in key path is not currently allowed if they are
1278+
// declared in a module built with Swift 6.0 compiler version or older.
1279+
if (cs.shouldAttemptFixes()) {
1280+
auto &ctx = cs.getASTContext();
1281+
auto langVersion = ctx.LangOpts.EffectiveLanguageVersion;
1282+
auto moduleDecl = member->getDeclContext()
1283+
->getParentModule();
1284+
auto moduleName = moduleDecl->getExportAsName();
1285+
auto compatibilityVersion = moduleDecl
1286+
->getLanguageVersionBuiltWith();
1287+
if (member->isStatic() && (compatibilityVersion < langVersion))
1288+
return AllowInvalidRefInKeyPath::create(
1289+
cs, baseType, RefKind::StaticMember, member, moduleName, locator);
1290+
}
12721291

12731292
if (auto *storage = dyn_cast<AbstractStorageDecl>(member)) {
12741293
// Referencing members with mutating getters in key path is not
12751294
// currently allowed.
12761295
if (storage->isGetterMutating())
12771296
return AllowInvalidRefInKeyPath::create(
1278-
cs, baseType, RefKind::MutatingGetter, member, locator);
1297+
cs, baseType, RefKind::MutatingGetter, member, Identifier(), locator);
12791298
}
12801299

12811300
return nullptr;
12821301
}
12831302

12841303
AllowInvalidRefInKeyPath *
12851304
AllowInvalidRefInKeyPath::create(ConstraintSystem &cs, Type baseType,
1286-
RefKind kind, ValueDecl *member,
1305+
RefKind kind, ValueDecl *member, Identifier moduleName,
12871306
ConstraintLocator *locator) {
12881307
return new (cs.getAllocator())
1289-
AllowInvalidRefInKeyPath(cs, baseType, kind, member, locator);
1308+
AllowInvalidRefInKeyPath(cs, baseType, kind, member, moduleName, locator);
12901309
}
12911310

12921311
bool RemoveAddressOf::diagnose(const Solution &solution, bool asNote) const {

0 commit comments

Comments
 (0)