Skip to content

Commit d9976bd

Browse files
committed
[SILOptimizer] fix crash in key path projector
When a computed property returns a generic, the accessor's function type may involve a type parameter that needs to be resolved using the key path instruction's substitution map.
1 parent b2ab82b commit d9976bd

File tree

2 files changed

+40
-7
lines changed

2 files changed

+40
-7
lines changed

lib/SILOptimizer/Utils/KeyPathProjector.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,9 @@ class GettablePropertyProjector : public ComponentProjector {
208208
// The callback expects a memory address it can read from,
209209
// so allocate a buffer.
210210
auto &function = builder.getFunction();
211-
SILType type = function.getLoweredType(component.getComponentType());
211+
auto substType = component.getComponentType().subst(keyPath->getSubstitutions(),
212+
None);
213+
SILType type = function.getLoweredType(substType);
212214
auto addr = builder.createAllocStack(loc, type);
213215

214216
assertHasNoContext();
@@ -283,7 +285,9 @@ class SettablePropertyProjector : public GettablePropertyProjector {
283285
// The callback expects a memory address it can write to,
284286
// so allocate a writeback buffer.
285287
auto &function = builder.getFunction();
286-
SILType type = function.getLoweredType(component.getComponentType());
288+
auto substType = component.getComponentType().subst(keyPath->getSubstitutions(),
289+
None);
290+
SILType type = function.getLoweredType(substType);
287291
auto addr = builder.createAllocStack(loc, type);
288292

289293
assertHasNoContext();
@@ -315,10 +319,12 @@ class SettablePropertyProjector : public GettablePropertyProjector {
315319

316320
class OptionalWrapProjector : public ComponentProjector {
317321
public:
318-
OptionalWrapProjector(const KeyPathPatternComponent &component,
322+
OptionalWrapProjector(KeyPathInst *kpInst,
323+
const KeyPathPatternComponent &component,
319324
std::unique_ptr<KeyPathProjector> parent,
320325
SILLocation loc, SILBuilder &builder)
321-
: ComponentProjector(component, std::move(parent), loc, builder) {}
326+
: ComponentProjector(component, std::move(parent), loc, builder),
327+
keyPath(kpInst) {}
322328

323329
void project(AccessType accessType,
324330
std::function<void(SILValue addr)> callback) override {
@@ -328,7 +334,9 @@ class OptionalWrapProjector : public ComponentProjector {
328334

329335
parent->project(AccessType::Get, [&](SILValue parentValue) {
330336
auto &function = builder.getFunction();
331-
SILType optType = function.getLoweredType(component.getComponentType());
337+
auto substType = component.getComponentType().subst(keyPath->getSubstitutions(),
338+
None);
339+
SILType optType = function.getLoweredType(substType);
332340
SILType objType = optType.getOptionalObjectType().getAddressType();
333341

334342
assert(objType && "optional wrap must return an optional");
@@ -352,6 +360,9 @@ class OptionalWrapProjector : public ComponentProjector {
352360
builder.createDeallocStack(loc, optAddr);
353361
});
354362
}
363+
364+
private:
365+
KeyPathInst *keyPath;
355366
};
356367

357368
class OptionalForceProjector : public ComponentProjector {
@@ -531,7 +542,8 @@ class CompleteKeyPathProjector : public KeyPathProjector {
531542
// If we're reading an optional chain, create an optional result.
532543
auto resultCanType = components.back().getComponentType();
533544
auto &function = builder.getFunction();
534-
auto optType = function.getLoweredType(resultCanType);
545+
auto substType = resultCanType.subst(keyPath->getSubstitutions(), None);
546+
auto optType = function.getLoweredType(substType);
535547

536548
assert(optType.getOptionalObjectType() &&
537549
"Optional-chained key path should result in an optional");
@@ -608,7 +620,7 @@ class CompleteKeyPathProjector : public KeyPathProjector {
608620
break;
609621
case KeyPathPatternComponent::Kind::OptionalWrap:
610622
projector = std::make_unique<OptionalWrapProjector>
611-
(comp, std::move(parent), loc, builder);
623+
(keyPath, comp, std::move(parent), loc, builder);
612624
break;
613625
case KeyPathPatternComponent::Kind::OptionalForce:
614626
projector = std::make_unique<OptionalForceProjector>

test/SILOptimizer/optimize_keypath.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ protocol P {
1616
struct GenStruct<T : P> : P {
1717
var st: T
1818
var computed: Int { get { st.computed } set { st.computed = newValue } }
19+
20+
var computedGeneric: T { get { st} set { st = newValue} }
1921

2022
init(_ st: T) { self.st = st }
2123

@@ -581,6 +583,20 @@ func testGetComplex(_ s: SimpleClass) -> Int {
581583
return s[keyPath: kp]
582584
}
583585

586+
// allow exactly one unoptimzedkey path instruction, in this function
587+
// CHECK-ALL: sil {{.*}}makeKeyPathInGenericContext
588+
// CHECK-ALL: = keypath
589+
func makeKeyPathInGenericContext<T: P>(of: T.Type) -> WritableKeyPath<GenStruct<T>, T> {
590+
\.computedGeneric
591+
}
592+
593+
// CHECK-ALL-NOT: = keypath
594+
595+
func testGenericResult(_ s: inout GenStruct<SimpleStruct>) {
596+
let kp = makeKeyPathInGenericContext(of: SimpleStruct.self)
597+
s[keyPath: kp].i += 1
598+
}
599+
584600
// CHECK-LABEL: sil {{.*}}testit
585601
func testit() {
586602
// CHECK-OUTPUT: GenStructRead: 27
@@ -680,6 +696,11 @@ func testit() {
680696

681697
// CHECK-OUTPUT: testGetComplex: 1
682698
print("testGetComplex: \(testGetComplex(c4))")
699+
700+
// CHECK-OUTPUT: testGenericResult: 2
701+
var s5 = GenStruct(SimpleStruct(i: 1))
702+
testGenericResult(&s5)
703+
print("testGenericResult: \(s5.st.i)")
683704
}
684705

685706
testit()

0 commit comments

Comments
 (0)