Skip to content

Support concrete type propagation into witness_method instructions only for directly inherited conformances for now #11708

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 31, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,12 +795,23 @@ getConformanceAndConcreteType(FullApplySite AI,
if (Requirement == Protocol) {
return std::make_tuple(Conformance, ConcreteType, ConcreteTypeDef);
}
if (Requirement->inheritsFrom(Protocol)) {
// If Requirement != Protocol, then the abstract conformance cannot be used
// as is and we need to create a proper conformance.
return std::make_tuple(Conformance.getInherited(Protocol), ConcreteType,
ConcreteTypeDef);
}
// If Requirement != Protocol, then the abstract conformance cannot be
// used as is and we need to create a proper conformance.
// FIXME: We can handle only direct inheritance at the moment due to some
// limitations of the init_existential_* instructions representation.
// Once these instructions start using generic signatures instead of
// conformances lists, it should be fairly easy to support the indirect
// inheritance here by something like:
// Substitution Sub(ConcreteType, Conformances);
// IE->getGenericSignature()
// ->getSubstitutionMap({Sub}).lookupConformance(GP00, Protocol);
auto InheritedProtocols = Requirement->getInheritedProtocols();
if (std::find(InheritedProtocols.begin(), InheritedProtocols.end(),
Protocol) == InheritedProtocols.end())
return None;
// Requirement is directly inherited from Protocol.
return std::make_tuple(Conformance.getInherited(Protocol), ConcreteType,
ConcreteTypeDef);
}

llvm_unreachable("couldn't find matching conformance in substitution?");
Expand Down
17 changes: 16 additions & 1 deletion test/SILOptimizer/devirt_protocol_method_invocations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ protocol PPP {
protocol QQQ : PPP {
}

struct S : QQQ {}
protocol RRR : QQQ {
}

struct S : RRR {}

extension QQQ {
@_semantics("optimize.sil.never")
Expand All @@ -25,6 +28,18 @@ public func testInheritedConformance() {
(S() as QQQ).f()
}

// Test that a witness_method instructions is not devirtualized yet, because
// it uses indirect inheritance.
// This test used to crash the compiler because it uses inherited conformances.
// CHECK-LABEL: sil @_T034devirt_protocol_method_invocations34testIndirectlyInheritedConformanceyyF : $@convention(thin) () -> ()
// CHECK: witness_method
// CHECK: apply
// CHECK: // end sil function '_T034devirt_protocol_method_invocations34testIndirectlyInheritedConformanceyyF'
public func testIndirectlyInheritedConformance() {
(S() as RRR).f()
}


public protocol Foo {
func foo(_ x:Int) -> Int
}
Expand Down