Skip to content

Commit b6b5725

Browse files
authored
Merge pull request #24454 from xedin/rdar-50376224
[ConstraintSystem] Detect and fix invalid refs in dynamic key path me…
2 parents 344fe76 + 21216d8 commit b6b5725

File tree

8 files changed

+60
-18
lines changed

8 files changed

+60
-18
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -473,13 +473,15 @@ ERROR(expr_keypath_type_of_property,none,
473473
ERROR(expr_keypath_generic_type,none,
474474
"key path cannot refer to generic type %0", (DeclName))
475475
ERROR(expr_keypath_not_property,none,
476-
"key path cannot refer to %0 %1", (DescriptiveDeclKind, DeclName))
476+
"%select{key path|dynamic key path member lookup}2 cannot refer to %0 %1",
477+
(DescriptiveDeclKind, DeclName, bool))
477478
ERROR(expr_keypath_mutating_getter,none,
478-
"key path cannot refer to %0, which has a mutating getter",
479-
(DeclName))
479+
"%select{key path|dynamic key path member lookup}1 cannot refer to %0, "
480+
"which has a mutating getter",
481+
(DeclName, bool))
480482
ERROR(expr_keypath_static_member,none,
481-
"key path cannot refer to static member %0",
482-
(DeclName))
483+
"%select{key path|dynamic key path member lookup}1 cannot refer to static member %0",
484+
(DeclName, bool))
483485
ERROR(expr_keypath_empty,none,
484486
"empty key path does not refer to a property", ())
485487
ERROR(expr_unsupported_objc_key_path_component,none,

lib/Sema/CSDiagnostics.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,17 +2532,19 @@ SourceLoc InvalidMemberRefInKeyPath::getLoc() const {
25322532
}
25332533

25342534
bool InvalidStaticMemberRefInKeyPath::diagnoseAsError() {
2535-
emitDiagnostic(getLoc(), diag::expr_keypath_static_member, getName());
2535+
emitDiagnostic(getLoc(), diag::expr_keypath_static_member, getName(),
2536+
isForKeyPathDynamicMemberLookup());
25362537
return true;
25372538
}
25382539

25392540
bool InvalidMemberWithMutatingGetterInKeyPath::diagnoseAsError() {
2540-
emitDiagnostic(getLoc(), diag::expr_keypath_mutating_getter, getName());
2541+
emitDiagnostic(getLoc(), diag::expr_keypath_mutating_getter, getName(),
2542+
isForKeyPathDynamicMemberLookup());
25412543
return true;
25422544
}
25432545

25442546
bool InvalidMethodRefInKeyPath::diagnoseAsError() {
25452547
emitDiagnostic(getLoc(), diag::expr_keypath_not_property, getKind(),
2546-
getName());
2548+
getName(), isForKeyPathDynamicMemberLookup());
25472549
return true;
25482550
}

lib/Sema/CSDiagnostics.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,8 @@ class InvalidMemberRefInKeyPath : public FailureDiagnostic {
10391039
ConstraintLocator *locator)
10401040
: FailureDiagnostic(root, cs, locator), Member(member) {
10411041
assert(member->hasName());
1042-
assert(locator->isForKeyPathComponent());
1042+
assert(locator->isForKeyPathComponent() ||
1043+
locator->isForKeyPathDynamicMemberLookup());
10431044
}
10441045

10451046
DescriptiveDeclKind getKind() const { return Member->getDescriptiveKind(); }
@@ -1051,6 +1052,10 @@ class InvalidMemberRefInKeyPath : public FailureDiagnostic {
10511052
protected:
10521053
/// Compute location of the failure for diagnostic.
10531054
SourceLoc getLoc() const;
1055+
1056+
bool isForKeyPathDynamicMemberLookup() const {
1057+
return getLocator()->isForKeyPathDynamicMemberLookup();
1058+
}
10541059
};
10551060

10561061
/// Diagnose an attempt to reference a static member as a key path component

lib/Sema/CSSimplify.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3710,11 +3710,6 @@ bool swift::hasDynamicMemberLookupAttribute(Type type) {
37103710
return ::hasDynamicMemberLookupAttribute(type, DynamicMemberLookupCache);
37113711
}
37123712

3713-
static bool isKeyPathDynamicMemberLookup(ConstraintLocator *locator) {
3714-
auto path = locator ? locator->getPath() : None;
3715-
return !path.empty() && path.back().isKeyPathDynamicMember();
3716-
}
3717-
37183713
/// Given a ValueMember, UnresolvedValueMember, or TypeMember constraint,
37193714
/// perform a lookup into the specified base type to find a candidate list.
37203715
/// The list returned includes the viable candidates as well as the unviable
@@ -3753,7 +3748,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
37533748
// is a single argument with `keypath:` label or `\.` syntax is used.
37543749
if (memberName.isSimpleName() &&
37553750
memberName.getBaseName().getKind() == DeclBaseName::Kind::Subscript &&
3756-
!isKeyPathDynamicMemberLookup(memberLocator)) {
3751+
!(memberLocator && memberLocator->isForKeyPathDynamicMemberLookup())) {
37573752
if (baseTy->isAnyObject()) {
37583753
result.addUnviable(
37593754
OverloadChoice(baseTy, OverloadChoiceKind::KeyPathApplication),
@@ -4019,7 +4014,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
40194014
// based dynamic member lookup. Since it's unknown upfront
40204015
// what kind of declaration lookup is going to find, let's
40214016
// double check here that given keypath is appropriate for it.
4022-
if (isKeyPathDynamicMemberLookup(memberLocator)) {
4017+
if (memberLocator && memberLocator->isForKeyPathDynamicMemberLookup()) {
40234018
auto path = memberLocator->getPath();
40244019
auto *keyPath = path.back().getKeyPath();
40254020
if (auto *storage = dyn_cast<AbstractStorageDecl>(decl)) {
@@ -4416,10 +4411,17 @@ fixMemberRef(ConstraintSystem &cs, Type baseTy,
44164411
// Not all of the choices handled here are going
44174412
// to refer to a declaration.
44184413
if (choice.isDecl()) {
4419-
if (auto *CD = dyn_cast<ConstructorDecl>(choice.getDecl())) {
4414+
auto *decl = choice.getDecl();
4415+
4416+
if (auto *CD = dyn_cast<ConstructorDecl>(decl)) {
44204417
if (auto *fix = validateInitializerRef(cs, CD, locator))
44214418
return fix;
44224419
}
4420+
4421+
if (locator->isForKeyPathDynamicMemberLookup()) {
4422+
if (auto *fix = AllowInvalidRefInKeyPath::forRef(cs, decl, locator))
4423+
return fix;
4424+
}
44234425
}
44244426

44254427
if (reason) {

lib/Sema/ConstraintLocator.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ bool ConstraintLocator::isKeyPathSubscriptComponent() const {
159159
});
160160
}
161161

162+
bool ConstraintLocator::isForKeyPathDynamicMemberLookup() const {
163+
auto path = getPath();
164+
return !path.empty() && path.back().isKeyPathDynamicMember();
165+
}
166+
162167
bool ConstraintLocator::isForKeyPathComponent() const {
163168
return llvm::any_of(getPath(), [&](const LocatorPathElt &elt) {
164169
return elt.isKeyPathComponent();

lib/Sema/ConstraintLocator.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,10 @@ class ConstraintLocator : public llvm::FoldingSetNode {
560560
/// of the key path at some index.
561561
bool isKeyPathSubscriptComponent() const;
562562

563+
/// Determine whether this locator points to the member found
564+
/// via key path dynamic member lookup.
565+
bool isForKeyPathDynamicMemberLookup() const;
566+
563567
/// Determine whether this locator points to one of the key path
564568
/// components.
565569
bool isForKeyPathComponent() const;

lib/Sema/TypeCheckExprObjC.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,8 @@ Optional<Type> TypeChecker::checkObjCKeyPathExpr(DeclContext *dc,
395395

396396
// Declarations that cannot be part of a key-path.
397397
diagnose(componentNameLoc, diag::expr_keypath_not_property,
398-
found->getDescriptiveKind(), found->getFullName());
398+
found->getDescriptiveKind(), found->getFullName(),
399+
/*isForDynamicKeyPathMemberLookup=*/false);
399400
isInvalid = true;
400401
break;
401402
}

test/attr/attr_dynamic_member_lookup.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,3 +667,24 @@ func test_chain_of_recursive_lookups(_ lens: Lens<Lens<Lens<Point>>>) {
667667
_ = \Lens<Lens<Point>>.x
668668
_ = \Lens<Lens<Point>>.obj.x
669669
}
670+
671+
// KeyPath Dynamic Member Lookup can't refer to methods, mutating setters and static members
672+
// because of the KeyPath limitations
673+
func invalid_refs_through_dynamic_lookup() {
674+
struct S {
675+
static var foo: Int = 42
676+
func bar() -> Q { return Q() }
677+
static func baz(_: String) -> Int { return 0 }
678+
}
679+
680+
struct Q {
681+
var faz: Int = 0
682+
}
683+
684+
func test(_ lens: A<S>) {
685+
_ = lens.foo // expected-error {{dynamic key path member lookup cannot refer to static member 'foo'}}
686+
_ = lens.bar() // expected-error {{dynamic key path member lookup cannot refer to instance method 'bar()'}}
687+
_ = lens.bar().faz + 1 // expected-error {{dynamic key path member lookup cannot refer to instance method 'bar()'}}
688+
_ = lens.baz("hello") // expected-error {{dynamic key path member lookup cannot refer to static method 'baz'}}
689+
}
690+
}

0 commit comments

Comments
 (0)