Skip to content

Commit 80d58b7

Browse files
authored
Merge pull request #24474 from xedin/rdar-50376224-5.1
[5.1][ConstraintSystem] Detect and fix invalid refs in dynamic key path me…
2 parents 55b95e1 + 6892650 commit 80d58b7

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
@@ -477,13 +477,15 @@ ERROR(expr_keypath_type_of_property,none,
477477
ERROR(expr_keypath_generic_type,none,
478478
"key path cannot refer to generic type %0", (DeclName))
479479
ERROR(expr_keypath_not_property,none,
480-
"key path cannot refer to %0 %1", (DescriptiveDeclKind, DeclName))
480+
"%select{key path|dynamic key path member lookup}2 cannot refer to %0 %1",
481+
(DescriptiveDeclKind, DeclName, bool))
481482
ERROR(expr_keypath_mutating_getter,none,
482-
"key path cannot refer to %0, which has a mutating getter",
483-
(DeclName))
483+
"%select{key path|dynamic key path member lookup}1 cannot refer to %0, "
484+
"which has a mutating getter",
485+
(DeclName, bool))
484486
ERROR(expr_keypath_static_member,none,
485-
"key path cannot refer to static member %0",
486-
(DeclName))
487+
"%select{key path|dynamic key path member lookup}1 cannot refer to static member %0",
488+
(DeclName, bool))
487489
ERROR(expr_keypath_empty,none,
488490
"empty key path does not refer to a property", ())
489491
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
@@ -2517,17 +2517,19 @@ SourceLoc InvalidMemberRefInKeyPath::getLoc() const {
25172517
}
25182518

25192519
bool InvalidStaticMemberRefInKeyPath::diagnoseAsError() {
2520-
emitDiagnostic(getLoc(), diag::expr_keypath_static_member, getName());
2520+
emitDiagnostic(getLoc(), diag::expr_keypath_static_member, getName(),
2521+
isForKeyPathDynamicMemberLookup());
25212522
return true;
25222523
}
25232524

25242525
bool InvalidMemberWithMutatingGetterInKeyPath::diagnoseAsError() {
2525-
emitDiagnostic(getLoc(), diag::expr_keypath_mutating_getter, getName());
2526+
emitDiagnostic(getLoc(), diag::expr_keypath_mutating_getter, getName(),
2527+
isForKeyPathDynamicMemberLookup());
25262528
return true;
25272529
}
25282530

25292531
bool InvalidMethodRefInKeyPath::diagnoseAsError() {
25302532
emitDiagnostic(getLoc(), diag::expr_keypath_not_property, getKind(),
2531-
getName());
2533+
getName(), isForKeyPathDynamicMemberLookup());
25322534
return true;
25332535
}

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
@@ -3664,11 +3664,6 @@ bool swift::hasDynamicMemberLookupAttribute(Type type) {
36643664
return ::hasDynamicMemberLookupAttribute(type, DynamicMemberLookupCache);
36653665
}
36663666

3667-
static bool isKeyPathDynamicMemberLookup(ConstraintLocator *locator) {
3668-
auto path = locator ? locator->getPath() : None;
3669-
return !path.empty() && path.back().isKeyPathDynamicMember();
3670-
}
3671-
36723667
/// Given a ValueMember, UnresolvedValueMember, or TypeMember constraint,
36733668
/// perform a lookup into the specified base type to find a candidate list.
36743669
/// The list returned includes the viable candidates as well as the unviable
@@ -3707,7 +3702,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
37073702
// is a single argument with `keypath:` label or `\.` syntax is used.
37083703
if (memberName.isSimpleName() &&
37093704
memberName.getBaseName().getKind() == DeclBaseName::Kind::Subscript &&
3710-
!isKeyPathDynamicMemberLookup(memberLocator)) {
3705+
!(memberLocator && memberLocator->isForKeyPathDynamicMemberLookup())) {
37113706
if (baseTy->isAnyObject()) {
37123707
result.addUnviable(
37133708
OverloadChoice(baseTy, OverloadChoiceKind::KeyPathApplication),
@@ -3973,7 +3968,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
39733968
// based dynamic member lookup. Since it's unknown upfront
39743969
// what kind of declaration lookup is going to find, let's
39753970
// double check here that given keypath is appropriate for it.
3976-
if (isKeyPathDynamicMemberLookup(memberLocator)) {
3971+
if (memberLocator && memberLocator->isForKeyPathDynamicMemberLookup()) {
39773972
auto path = memberLocator->getPath();
39783973
auto *keyPath = path.back().getKeyPath();
39793974
if (auto *storage = dyn_cast<AbstractStorageDecl>(decl)) {
@@ -4370,10 +4365,17 @@ fixMemberRef(ConstraintSystem &cs, Type baseTy,
43704365
// Not all of the choices handled here are going
43714366
// to refer to a declaration.
43724367
if (choice.isDecl()) {
4373-
if (auto *CD = dyn_cast<ConstructorDecl>(choice.getDecl())) {
4368+
auto *decl = choice.getDecl();
4369+
4370+
if (auto *CD = dyn_cast<ConstructorDecl>(decl)) {
43744371
if (auto *fix = validateInitializerRef(cs, CD, locator))
43754372
return fix;
43764373
}
4374+
4375+
if (locator->isForKeyPathDynamicMemberLookup()) {
4376+
if (auto *fix = AllowInvalidRefInKeyPath::forRef(cs, decl, locator))
4377+
return fix;
4378+
}
43774379
}
43784380

43794381
if (reason) {

lib/Sema/ConstraintLocator.cpp

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

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

lib/Sema/ConstraintLocator.h

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

559+
/// Determine whether this locator points to the member found
560+
/// via key path dynamic member lookup.
561+
bool isForKeyPathDynamicMemberLookup() const;
562+
559563
/// Determine whether this locator points to one of the key path
560564
/// components.
561565
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)