diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 8c766b12ffc9d..d4713caa7db47 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4114,8 +4114,10 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, if (auto *storage = dyn_cast(decl)) { // If this is an attempt to access read-only member via // writable key path, let's fail this choice early. + auto &ctx = getASTContext(); if (isReadOnlyKeyPathComponent(storage) && - keyPath == getASTContext().getWritableKeyPathDecl()) { + (keyPath == ctx.getWritableKeyPathDecl() || + keyPath == ctx.getReferenceWritableKeyPathDecl())) { result.addUnviable( candidate, MemberLookupResult::UR_WritableKeyPathOnReadOnlyMember); @@ -4126,7 +4128,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, // on the other hand if setter is mutating there is no point // of attempting `ReferenceWritableKeyPath` overload. if (storage->isSetterMutating() && - keyPath == getASTContext().getReferenceWritableKeyPathDecl()) { + keyPath == ctx.getReferenceWritableKeyPathDecl()) { result.addUnviable( candidate, MemberLookupResult::UR_ReferenceWritableKeyPathOnMutatingMember); diff --git a/test/Constraints/keypath_dynamic_member_lookup.swift b/test/Constraints/keypath_dynamic_member_lookup.swift index fb4f1bb899870..80ec2c3ade99a 100644 --- a/test/Constraints/keypath_dynamic_member_lookup.swift +++ b/test/Constraints/keypath_dynamic_member_lookup.swift @@ -250,3 +250,38 @@ func test_recursive_dynamic_lookup(_ lens: Lens>) { // CHECK-NEXT: keypath $KeyPath>, Lens>>, (root $Lens>; settable_property $Lens>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig : {{.*}}) _ = \Lens>.topLeft.x } + +@dynamicMemberLookup +struct RefWritableBox { + var obj: T + + init(_ obj: T) { + self.obj = obj + } + + subscript(dynamicMember member: KeyPath) -> U { + get { return obj[keyPath: member] } + } + + subscript(dynamicMember member: ReferenceWritableKeyPath) -> U { + get { return obj[keyPath: member] } + set { obj[keyPath: member] = newValue } + } +} + +func prefer_readonly_keypath_over_reference_writable() { + class C { + let foo: Int + + init(_ foo: Int) { + self.foo = foo + } + } + + var box = RefWritableBox(C(42)) + // expected-warning@-1 {{variable 'box' was never mutated; consider changing to 'let' constant}} + + // CHECK: function_ref RefWritableBox.subscript.getter + // CHECK-NEXT: function_ref @$s29keypath_dynamic_member_lookup14RefWritableBoxV0B6Memberqd__s7KeyPathCyxqd__G_tcluig + _ = box.foo +}