Skip to content

Commit 03ea5dc

Browse files
committed
[ConstraintSystem] Detect and fix use of static members in a key path in the solver
Previously it was possible to create an invalid solution where static members would be referenced in a key path, which is not currently supported and would only be diagnosed while applying such solution to AST e.g. ```swift struct S { static var foo: Int = 42 } _ = \S.Type.foo ```
1 parent 78b4ab3 commit 03ea5dc

File tree

4 files changed

+52
-5
lines changed

4 files changed

+52
-5
lines changed

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4572,10 +4572,8 @@ namespace {
45724572
}
45734573

45744574
// Key paths don't currently support static members.
4575-
if (varDecl->isStatic()) {
4576-
cs.TC.diagnose(componentLoc, diag::expr_keypath_static_member,
4577-
property->getFullName());
4578-
}
4575+
// There is a fix which diagnoses such situation already.
4576+
assert(!varDecl->isStatic());
45794577
}
45804578

45814579
cs.TC.requestMemberLayout(property);

lib/Sema/CSFix.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,3 +422,14 @@ TreatKeyPathSubscriptIndexAsHashable::create(ConstraintSystem &cs, Type type,
422422
return new (cs.getAllocator())
423423
TreatKeyPathSubscriptIndexAsHashable(cs, type, locator);
424424
}
425+
426+
bool AllowStaticMemberRefInKeyPath::diagnose(Expr *root, bool asNote) const {
427+
return false;
428+
}
429+
430+
AllowStaticMemberRefInKeyPath *
431+
AllowStaticMemberRefInKeyPath::create(ConstraintSystem &cs, ValueDecl *member,
432+
ConstraintLocator *locator) {
433+
return new (cs.getAllocator())
434+
AllowStaticMemberRefInKeyPath(cs, member, locator);
435+
}

lib/Sema/CSFix.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,13 @@ enum class FixKind : uint8_t {
139139

140140
/// Allow KeyPaths to use AnyObject as root type
141141
AllowAnyObjectKeyPathRoot,
142-
142+
143143
/// Using subscript references in the keypath requires that each
144144
/// of the index arguments to be Hashable.
145145
TreatKeyPathSubscriptIndexAsHashable,
146+
147+
/// Allow a reference to a static member as a key path component.
148+
AllowStaticMemberRefInKeyPath,
146149
};
147150

148151
class ConstraintFix {
@@ -780,6 +783,25 @@ class TreatKeyPathSubscriptIndexAsHashable final : public ConstraintFix {
780783
create(ConstraintSystem &cs, Type type, ConstraintLocator *locator);
781784
};
782785

786+
class AllowStaticMemberRefInKeyPath final : public ConstraintFix {
787+
ValueDecl *Member;
788+
789+
AllowStaticMemberRefInKeyPath(ConstraintSystem &cs, ValueDecl *member,
790+
ConstraintLocator *locator)
791+
: ConstraintFix(cs, FixKind::AllowStaticMemberRefInKeyPath, locator),
792+
Member(member) {}
793+
794+
public:
795+
std::string getName() const override {
796+
return "allow reference to a static member as a key path component";
797+
}
798+
799+
bool diagnose(Expr *root, bool asNote = false) const override;
800+
801+
static AllowStaticMemberRefInKeyPath *
802+
create(ConstraintSystem &cs, ValueDecl *member, ConstraintLocator *locator);
803+
};
804+
783805
} // end namespace constraints
784806
} // end namespace swift
785807

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5015,11 +5015,26 @@ ConstraintSystem::simplifyKeyPathConstraint(Type keyPathTy,
50155015
if (!choices[i].isDecl()) {
50165016
return SolutionKind::Error;
50175017
}
5018+
50185019
auto storage = dyn_cast<AbstractStorageDecl>(choices[i].getDecl());
50195020
if (!storage) {
50205021
return SolutionKind::Error;
50215022
}
50225023

5024+
// Referencing static members in key path is not currently allowed.
5025+
if (storage->isStatic()) {
5026+
if (!shouldAttemptFixes())
5027+
return SolutionKind::Error;
5028+
5029+
auto componentLoc =
5030+
locator.withPathElement(LocatorPathElt::getKeyPathComponent(i));
5031+
auto *fix = AllowStaticMemberRefInKeyPath::create(
5032+
*this, choices[i].getDecl(), getConstraintLocator(componentLoc));
5033+
5034+
if (recordFix(fix))
5035+
return SolutionKind::Error;
5036+
}
5037+
50235038
if (isReadOnlyKeyPathComponent(storage)) {
50245039
capability = ReadOnly;
50255040
continue;
@@ -6314,6 +6329,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
63146329
case FixKind::AllowInaccessibleMember:
63156330
case FixKind::AllowAnyObjectKeyPathRoot:
63166331
case FixKind::TreatKeyPathSubscriptIndexAsHashable:
6332+
case FixKind::AllowStaticMemberRefInKeyPath:
63176333
llvm_unreachable("handled elsewhere");
63186334
}
63196335

0 commit comments

Comments
 (0)