Skip to content

Commit bffa6b1

Browse files
committed
[sil-combine] Properly form conformances when propagating a concrete type into an existential.
This fixes an optimization bug that resulted in an IRGen crash. rdar://26286278
1 parent ca53873 commit bffa6b1

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,9 +770,17 @@ getConformanceAndConcreteType(FullApplySite AI,
770770
// Find the conformance for the protocol we're interested in.
771771
for (auto Conformance : Conformances) {
772772
auto Requirement = Conformance.getRequirement();
773-
if (Requirement == Protocol || Requirement->inheritsFrom(Protocol)) {
773+
if (Requirement == Protocol) {
774774
return std::make_pair(Conformance, ConcreteType);
775775
}
776+
if (Requirement->inheritsFrom(Protocol)) {
777+
// If Requirement != Protocol, then the abstract conformance cannot be used
778+
// as is and we need to create a proper conformance.
779+
return std::make_pair(Conformance.isAbstract()
780+
? ProtocolConformanceRef(Protocol)
781+
: Conformance,
782+
ConcreteType);
783+
}
776784
}
777785

778786
llvm_unreachable("couldn't find matching conformance in substitution?");

test/SILOptimizer/devirt_protocol_method_invocations.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,47 @@ public func testExMetatype() -> Int {
169169
return type.size
170170
}
171171

172+
// IRGen used to crash on the testPropagationOfConcreteTypeIntoExistential method.
173+
// rdar://26286278
174+
175+
protocol MathP {
176+
var sum: Int32 { get nonmutating set }
177+
func done()
178+
}
179+
180+
extension MathP {
181+
func plus() -> Self {
182+
sum += 1
183+
return self
184+
}
185+
186+
func minus() {
187+
sum -= 1
188+
if sum == 0 {
189+
done()
190+
}
191+
}
192+
}
193+
194+
protocol MathA : MathP {}
195+
196+
public final class V {
197+
var a: MathA
198+
199+
init(a: MathA) {
200+
self.a = a
201+
}
202+
}
203+
204+
// Check that all witness_method invocations are devirtualized.
205+
// CHECK-LABEL: sil @_TTSf4g_d___TF34devirt_protocol_method_invocations44testPropagationOfConcreteTypeIntoExistentialFT1vCS_1V1xVs5Int32_T_
206+
// CHECK-NOT: witness_method
207+
// CHECK-NOT: class_method
208+
// CHECK: return
209+
public func testPropagationOfConcreteTypeIntoExistential(v: V, x: Int32) {
210+
let y = v.a.plus()
211+
defer {
212+
y.minus()
213+
}
214+
}
215+

0 commit comments

Comments
 (0)