Skip to content

Commit cf4fc9f

Browse files
authored
Merge pull request swiftlang#39541 from hamishknight/dynamic-programming
2 parents ee50783 + b331a45 commit cf4fc9f

File tree

6 files changed

+59
-31
lines changed

6 files changed

+59
-31
lines changed

include/swift/Sema/OverloadChoice.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,12 @@ class OverloadChoice {
274274
return BaseAndDeclKind.getInt() == IsFallbackDeclViaUnwrappedOptional;
275275
}
276276

277+
/// Whether this choice is for any kind of dynamic member lookup.
278+
bool isAnyDynamicMemberLookup() const {
279+
return getKind() == OverloadChoiceKind::DynamicMemberLookup ||
280+
isKeyPathDynamicMemberLookup();
281+
}
282+
277283
/// Get the name of the overload choice.
278284
DeclName getName() const;
279285

lib/Sema/CSApply.cpp

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3314,10 +3314,7 @@ namespace {
33143314
}
33153315

33163316
Type getTypeOfDynamicMemberIndex(const SelectedOverload &overload) {
3317-
assert(overload.choice.getKind() ==
3318-
OverloadChoiceKind::DynamicMemberLookup ||
3319-
overload.choice.getKind() ==
3320-
OverloadChoiceKind::KeyPathDynamicMemberLookup);
3317+
assert(overload.choice.isAnyDynamicMemberLookup());
33213318

33223319
auto declTy = solution.simplifyType(overload.openedFullType);
33233320
auto subscriptTy = declTy->castTo<FunctionType>()->getResult();
@@ -3438,8 +3435,7 @@ namespace {
34383435
return nullptr;
34393436
}
34403437

3441-
if (overload->choice.getKind() ==
3442-
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
3438+
if (overload->choice.isKeyPathDynamicMemberLookup()) {
34433439
return buildDynamicMemberLookupRef(
34443440
expr, expr->getBase(), expr->getArgs()->getStartLoc(), SourceLoc(),
34453441
*overload, memberLocator);
@@ -4803,11 +4799,7 @@ namespace {
48034799
continue;
48044800
}
48054801

4806-
isDynamicMember =
4807-
foundDecl->choice.getKind() ==
4808-
OverloadChoiceKind::DynamicMemberLookup ||
4809-
foundDecl->choice.getKind() ==
4810-
OverloadChoiceKind::KeyPathDynamicMemberLookup;
4802+
isDynamicMember = foundDecl->choice.isAnyDynamicMemberLookup();
48114803

48124804
// If this was a @dynamicMemberLookup property, then we actually
48134805
// form a subscript reference, so switch the kind.
@@ -5087,17 +5079,10 @@ namespace {
50875079
// through the subscript(dynamicMember:) member, restore the
50885080
// openedType and origComponent to its full reference as if the user
50895081
// wrote out the subscript manually.
5090-
bool forDynamicLookup =
5091-
overload.choice.getKind() ==
5092-
OverloadChoiceKind::DynamicMemberLookup ||
5093-
overload.choice.getKind() ==
5094-
OverloadChoiceKind::KeyPathDynamicMemberLookup;
5095-
5096-
if (forDynamicLookup) {
5082+
if (overload.choice.isAnyDynamicMemberLookup()) {
50975083
auto indexType = getTypeOfDynamicMemberIndex(overload);
50985084
Expr *argExpr = nullptr;
5099-
if (overload.choice.getKind() ==
5100-
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
5085+
if (overload.choice.isKeyPathDynamicMemberLookup()) {
51015086
argExpr = buildKeyPathDynamicMemberArgExpr(
51025087
indexType->castTo<BoundGenericType>(), componentLoc, memberLoc);
51035088
} else {
@@ -5150,7 +5135,7 @@ namespace {
51505135
ctx, ref, args, resolvedTy, ctx.AllocateCopy(conformances));
51515136
components.push_back(comp);
51525137

5153-
if (shouldForceUnwrapResult(overload.choice, locator))
5138+
if (shouldForceUnwrapResult(overload.choice, memberLoc))
51545139
buildKeyPathOptionalForceComponent(components);
51555140
}
51565141

lib/Sema/CSDiagnostics.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,13 +1614,13 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() {
16141614
}
16151615
}
16161616

1617-
if (auto resolvedOverload = getOverloadChoiceIfAvailable(getLocator())) {
1617+
if (auto resolvedOverload =
1618+
getCalleeOverloadChoiceIfAvailable(getLocator())) {
16181619
if (resolvedOverload->choice.getKind() ==
16191620
OverloadChoiceKind::DynamicMemberLookup)
16201621
subElementDiagID = diag::assignment_dynamic_property_has_immutable_base;
16211622

1622-
if (resolvedOverload->choice.getKind() ==
1623-
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
1623+
if (resolvedOverload->choice.isKeyPathDynamicMemberLookup()) {
16241624
if (!getType(member->getBase(), /*wantRValue=*/false)->hasLValueType())
16251625
subElementDiagID =
16261626
diag::assignment_dynamic_property_has_immutable_base;

lib/Sema/CSSolver.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,8 +1606,7 @@ ConstraintSystem::filterDisjunction(
16061606
// be attempted in-place because that would also try to operate on that
16071607
// constraint, so instead let's keep the disjunction, but disable all
16081608
// unviable choices.
1609-
if (choice->getOverloadChoice().getKind() ==
1610-
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
1609+
if (choice->getOverloadChoice().isKeyPathDynamicMemberLookup()) {
16111610
// Early simplification of the "keypath dynamic member lookup" choice
16121611
// is impossible because it requires constraints associated with
16131612
// subscript index expression to be present.

test/Constraints/keypath_dynamic_member_lookup.swift

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,13 @@ struct SR_11893 {
402402
subscript(dynamicMember kp: KeyPath<SR_11893_Base, Int>) -> Void { () }
403403
}
404404

405-
// CHECK-LABEL: sil hidden @$s29keypath_dynamic_member_lookup13testIUOUnwrapyyAA8SR_11893VF : $@convention(thin) (SR_11893) -> ()
406-
func testIUOUnwrap(_ x: SR_11893) {
405+
@dynamicMemberLookup
406+
struct SR_15249 {
407+
subscript(dynamicMember kp: KeyPath<SR_11893_Base, Int>) -> Int! { 0 }
408+
}
409+
410+
// CHECK-LABEL: sil hidden @$s29keypath_dynamic_member_lookup13testIUOUnwrapyyAA8SR_11893V_AA0G6_15249VtF
411+
func testIUOUnwrap(_ x: SR_11893, _ y: SR_15249) {
407412
// CHECK: keypath $KeyPath<SR_11893_Base, Int>, (root $SR_11893_Base; stored_property #SR_11893_Base.i : $Optional<Int>; optional_force : $Int)
408413
x.i
409414

@@ -417,6 +422,39 @@ func testIUOUnwrap(_ x: SR_11893) {
417422
// CHECK: [[INNER_SUB_KP:%[0-9]+]] = keypath $KeyPath<SR_11893_Base, Int>, (root $SR_11893_Base; gettable_property $Optional<Int>, id @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicig : $@convention(method) (Int, SR_11893_Base) -> Optional<Int>, getter @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicipACTK : $@convention(thin) (@in_guaranteed SR_11893_Base, UnsafeRawPointer) -> @out Optional<Int>, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sSiTh : $@convention(thin) (UnsafeRawPointer) -> Int; optional_force : $Int)
418423
// CHECK: keypath $KeyPath<SR_11893, ()>, (root $SR_11893; gettable_property $(), id @$s29keypath_dynamic_member_lookup8SR_11893V0B6Memberys7KeyPathCyAA0E11_11893_BaseVSiG_tcig : $@convention(method) (@guaranteed KeyPath<SR_11893_Base, Int>, SR_11893) -> (), getter @$s29keypath_dynamic_member_lookup8SR_11893V0B6Memberys7KeyPathCyAA0E11_11893_BaseVSiG_tcipACTK : $@convention(thin) (@in_guaranteed SR_11893, UnsafeRawPointer) -> @out (), indices [%$0 : $KeyPath<SR_11893_Base, Int> : $KeyPath<SR_11893_Base, Int>], indices_equals @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[INNER_SUB_KP]])
419424
_ = \SR_11893.[5]
425+
426+
// SR-15249: Make sure we can handle IUO unwraps in both the inner and outer
427+
// key-paths.
428+
429+
// CHECK: [[INNER_KP2:%[0-9]+]] = keypath $KeyPath<SR_11893_Base, Int>, (root $SR_11893_Base; stored_property #SR_11893_Base.i : $Optional<Int>; optional_force : $Int)
430+
// CHECK: keypath $KeyPath<SR_15249, Optional<Int>>, (root $SR_15249; gettable_property $Optional<Int>, id @$s29keypath_dynamic_member_lookup8SR_15249V0B6MemberSiSgs7KeyPathCyAA0E11_11893_BaseVSiG_tcig : $@convention(method) (@guaranteed KeyPath<SR_11893_Base, Int>, SR_15249) -> Optional<Int>, getter @$s29keypath_dynamic_member_lookup8SR_15249V0B6MemberSiSgs7KeyPathCyAA0E11_11893_BaseVSiG_tcipACTK : $@convention(thin) (@in_guaranteed SR_15249, UnsafeRawPointer) -> @out Optional<Int>, indices [%$0 : $KeyPath<SR_11893_Base, Int> : $KeyPath<SR_11893_Base, Int>], indices_equals @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[INNER_KP2]])
431+
_ = \SR_15249.i
432+
433+
// CHECK: [[INNER_KP3:%[0-9]+]] = keypath $KeyPath<SR_11893_Base, Int>, (root $SR_11893_Base; stored_property #SR_11893_Base.i : $Optional<Int>; optional_force : $Int)
434+
// CHECK: keypath $KeyPath<SR_15249, Int>, (root $SR_15249; gettable_property $Optional<Int>, id @$s29keypath_dynamic_member_lookup8SR_15249V0B6MemberSiSgs7KeyPathCyAA0E11_11893_BaseVSiG_tcig : $@convention(method) (@guaranteed KeyPath<SR_11893_Base, Int>, SR_15249) -> Optional<Int>, getter @$s29keypath_dynamic_member_lookup8SR_15249V0B6MemberSiSgs7KeyPathCyAA0E11_11893_BaseVSiG_tcipACTK : $@convention(thin) (@in_guaranteed SR_15249, UnsafeRawPointer) -> @out Optional<Int>, indices [%$0 : $KeyPath<SR_11893_Base, Int> : $KeyPath<SR_11893_Base, Int>], indices_equals @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTh : $@convention(thin) (UnsafeRawPointer) -> Int; optional_force : $Int) ([[INNER_KP3]])
435+
let _: KeyPath<SR_15249, Int> = \SR_15249.i
436+
437+
// CHECK: [[INNER_KP4:%[0-9]+]] = keypath $KeyPath<SR_11893_Base, Int>, (root $SR_11893_Base; gettable_property $Optional<Int>, id @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicig : $@convention(method) (Int, SR_11893_Base) -> Optional<Int>, getter @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicipACTK : $@convention(thin) (@in_guaranteed SR_11893_Base, UnsafeRawPointer) -> @out Optional<Int>, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sSiTh : $@convention(thin) (UnsafeRawPointer) -> Int; optional_force : $Int)
438+
// CHECK: keypath $KeyPath<SR_15249, Optional<Int>>, (root $SR_15249; gettable_property $Optional<Int>, id @$s29keypath_dynamic_member_lookup8SR_15249V0B6MemberSiSgs7KeyPathCyAA0E11_11893_BaseVSiG_tcig : $@convention(method) (@guaranteed KeyPath<SR_11893_Base, Int>, SR_15249) -> Optional<Int>, getter @$s29keypath_dynamic_member_lookup8SR_15249V0B6MemberSiSgs7KeyPathCyAA0E11_11893_BaseVSiG_tcipACTK : $@convention(thin) (@in_guaranteed SR_15249, UnsafeRawPointer) -> @out Optional<Int>, indices [%$0 : $KeyPath<SR_11893_Base, Int> : $KeyPath<SR_11893_Base, Int>], indices_equals @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[INNER_KP4]])
439+
_ = \SR_15249.[0]
440+
441+
// CHECK: [[INNER_KP5:%[0-9]+]] = keypath $KeyPath<SR_11893_Base, Int>, (root $SR_11893_Base; gettable_property $Optional<Int>, id @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicig : $@convention(method) (Int, SR_11893_Base) -> Optional<Int>, getter @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicipACTK : $@convention(thin) (@in_guaranteed SR_11893_Base, UnsafeRawPointer) -> @out Optional<Int>, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sSiTh : $@convention(thin) (UnsafeRawPointer) -> Int; optional_force : $Int)
442+
// CHECK: keypath $KeyPath<SR_15249, Int>, (root $SR_15249; gettable_property $Optional<Int>, id @$s29keypath_dynamic_member_lookup8SR_15249V0B6MemberSiSgs7KeyPathCyAA0E11_11893_BaseVSiG_tcig : $@convention(method) (@guaranteed KeyPath<SR_11893_Base, Int>, SR_15249) -> Optional<Int>, getter @$s29keypath_dynamic_member_lookup8SR_15249V0B6MemberSiSgs7KeyPathCyAA0E11_11893_BaseVSiG_tcipACTK : $@convention(thin) (@in_guaranteed SR_15249, UnsafeRawPointer) -> @out Optional<Int>, indices [%$0 : $KeyPath<SR_11893_Base, Int> : $KeyPath<SR_11893_Base, Int>], indices_equals @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTh : $@convention(thin) (UnsafeRawPointer) -> Int; optional_force : $Int) ([[INNER_KP5]])
443+
let _: KeyPath<SR_15249, Int> = \SR_15249.[0]
444+
445+
// CHECK: [[INNER_KP6:%[0-9]+]] = keypath $KeyPath<SR_11893_Base, Int>, (root $SR_11893_Base; stored_property #SR_11893_Base.i : $Optional<Int>; optional_force : $Int)
446+
// CHECK: [[YI_OPT:%[0-9]+]] = apply {{%[0-9]+}}([[INNER_KP6]], {{%[0-9]+}}) : $@convention(method) (@guaranteed KeyPath<SR_11893_Base, Int>, SR_15249) -> Optional<Int>
447+
// CHECK: switch_enum [[YI_OPT]]
448+
// CHECK: unreachable
449+
// CHECK: bb{{[0-9]+}}(%{{[0-9]+}} : $Int)
450+
let _: Int = y.i
451+
452+
// CHECK: [[INNER_KP7:%[0-9]+]] = keypath $KeyPath<SR_11893_Base, Int>, (root $SR_11893_Base; gettable_property $Optional<Int>, id @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicig : $@convention(method) (Int, SR_11893_Base) -> Optional<Int>, getter @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicipACTK : $@convention(thin) (@in_guaranteed SR_11893_Base, UnsafeRawPointer) -> @out Optional<Int>, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sSiTh : $@convention(thin) (UnsafeRawPointer) -> Int; optional_force : $Int)
453+
// CHECK: [[Y0_OPT:%[0-9]+]] = apply {{%[0-9]+}}([[INNER_KP7]], {{%[0-9]+}}) : $@convention(method) (@guaranteed KeyPath<SR_11893_Base, Int>, SR_15249) -> Optional<Int>
454+
// CHECK: switch_enum [[Y0_OPT]]
455+
// CHECK: unreachable
456+
// CHECK: bb{{[0-9]+}}(%{{[0-9]+}} : $Int)
457+
let _: Int = y[0]
420458
}
421459

422460
// SR-11896: Make sure the outer key path reflects the mutability of the 'dynamicMember:' subscript.

test/attr/attr_dynamic_member_lookup.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ struct NonMutSettable {
3636

3737
func test(a: Gettable, b: Settable, c: MutGettable, d: NonMutSettable) {
3838
global = a.wyverns
39-
a.flavor = global // expected-error {{cannot assign to property: 'a' is a 'let' constant}}
39+
a.flavor = global // expected-error {{cannot assign through dynamic lookup property: 'a' is a 'let' constant}}
4040

4141
global = b.flavor
42-
b.universal = global // expected-error {{cannot assign to property: 'b' is a 'let' constant}}
42+
b.universal = global // expected-error {{cannot assign through dynamic lookup property: 'b' is a 'let' constant}}
4343
b.thing += 1 // expected-error {{left side of mutating operator isn't mutable: 'b' is a 'let' constant}}
4444

4545
var bm = b
@@ -318,7 +318,7 @@ class DerivedClassWithSetter : BaseClass {
318318
func testOverrideSubscript(a: BaseClass, b: DerivedClassWithSetter) {
319319
let x = a.frotz + b.garbalaz
320320
b.baranozo = x
321-
a.balboza = 12 // expected-error {{cannot assign to property}}
321+
a.balboza = 12 // expected-error {{cannot assign through dynamic lookup property: 'a' is a 'let' constant}}
322322
}
323323

324324
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)