mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge remote-tracking branch 'origin/master' into master-next
This commit is contained in:
@@ -466,10 +466,15 @@ namespace {
|
||||
/// spelling of the protocol type, as well as the locality in the file), but it
|
||||
/// does work.
|
||||
class InheritedProtocolCollector {
|
||||
static const StringLiteral DummyProtocolName;
|
||||
|
||||
/// Protocols that will be included by the ASTPrinter without any extra work.
|
||||
SmallVector<ProtocolDecl *, 8> IncludedProtocols;
|
||||
/// Protocols that will not be printed by the ASTPrinter.
|
||||
SmallVector<ProtocolDecl *, 8> ExtraProtocols;
|
||||
/// Protocols that can be printed, but whose conformances are constrained with
|
||||
/// something that \e can't be printed.
|
||||
SmallVector<const ProtocolType *, 8> ConditionalConformanceProtocols;
|
||||
|
||||
/// For each type in \p directlyInherited, classify the protocols it refers to
|
||||
/// as included for printing or not, and record them in the appropriate
|
||||
@@ -492,6 +497,23 @@ class InheritedProtocolCollector {
|
||||
}
|
||||
}
|
||||
|
||||
/// For each type in \p directlyInherited, record any protocols that we would
|
||||
/// have printed in ConditionalConformanceProtocols.
|
||||
void recordConditionalConformances(ArrayRef<TypeLoc> directlyInherited) {
|
||||
for (TypeLoc inherited : directlyInherited) {
|
||||
Type inheritedTy = inherited.getType();
|
||||
if (!inheritedTy || !inheritedTy->isExistentialType())
|
||||
continue;
|
||||
|
||||
ExistentialLayout layout = inheritedTy->getExistentialLayout();
|
||||
for (ProtocolType *protoTy : layout.getProtocols())
|
||||
if (isPublicOrUsableFromInline(protoTy))
|
||||
ConditionalConformanceProtocols.push_back(protoTy);
|
||||
// FIXME: This ignores layout constraints, but currently we don't support
|
||||
// any of those besides 'AnyObject'.
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
using PerTypeMap = llvm::MapVector<const NominalTypeDecl *,
|
||||
InheritedProtocolCollector>;
|
||||
@@ -530,6 +552,21 @@ public:
|
||||
collectProtocols(map, member);
|
||||
}
|
||||
|
||||
/// If \p D is an extension providing conditional conformances, record those
|
||||
/// in \p map.
|
||||
///
|
||||
/// \sa recordConditionalConformances
|
||||
static void collectSkippedConditionalConformances(PerTypeMap &map,
|
||||
const Decl *D) {
|
||||
auto *extension = dyn_cast<ExtensionDecl>(D);
|
||||
if (!extension || !extension->isConstrainedExtension())
|
||||
return;
|
||||
|
||||
const NominalTypeDecl *nominal = extension->getExtendedNominal();
|
||||
map[nominal].recordConditionalConformances(extension->getInherited());
|
||||
// No recursion here because extensions are never nested.
|
||||
}
|
||||
|
||||
/// If there were any public protocols that need to be printed (i.e. they
|
||||
/// weren't conformed to explicitly or inherited by another printed protocol),
|
||||
/// do so now by printing a dummy extension on \p nominal to \p out.
|
||||
@@ -580,7 +617,40 @@ public:
|
||||
}, [&out] { out << ", "; });
|
||||
out << " {}\n";
|
||||
}
|
||||
|
||||
/// If there were any conditional conformances that couldn't be printed,
|
||||
/// make a dummy extension that conforms to all of them, constrained by a
|
||||
/// fake protocol.
|
||||
bool printInaccessibleConformanceExtensionIfNeeded(
|
||||
raw_ostream &out, const PrintOptions &printOptions,
|
||||
const NominalTypeDecl *nominal) const {
|
||||
if (ConditionalConformanceProtocols.empty())
|
||||
return false;
|
||||
assert(nominal->isGenericContext());
|
||||
|
||||
out << "extension ";
|
||||
nominal->getDeclaredType().print(out, printOptions);
|
||||
out << " : ";
|
||||
swift::interleave(ConditionalConformanceProtocols,
|
||||
[&out, &printOptions](const ProtocolType *protoTy) {
|
||||
protoTy->print(out, printOptions);
|
||||
}, [&out] { out << ", "; });
|
||||
out << " where "
|
||||
<< nominal->getGenericParamsOfContext()->getParams().front()->getName()
|
||||
<< " : " << DummyProtocolName << " {}\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Print a fake protocol declaration for use by
|
||||
/// #printInaccessibleConformanceExtensionIfNeeded.
|
||||
static void printDummyProtocolDeclaration(raw_ostream &out) {
|
||||
out << "\n@usableFromInline\ninternal protocol " << DummyProtocolName
|
||||
<< " {}\n";
|
||||
}
|
||||
};
|
||||
|
||||
const StringLiteral InheritedProtocolCollector::DummyProtocolName =
|
||||
"_ConstraintThatIsNotPartOfTheAPIOfThisLibrary";
|
||||
} // end anonymous namespace
|
||||
|
||||
bool swift::emitParseableInterface(raw_ostream &out,
|
||||
@@ -597,8 +667,12 @@ bool swift::emitParseableInterface(raw_ostream &out,
|
||||
SmallVector<Decl *, 16> topLevelDecls;
|
||||
M->getTopLevelDecls(topLevelDecls);
|
||||
for (const Decl *D : topLevelDecls) {
|
||||
if (!D->shouldPrintInContext(printOptions))
|
||||
if (!D->shouldPrintInContext(printOptions) ||
|
||||
!printOptions.CurrentPrintabilityChecker->shouldPrint(D, printOptions)){
|
||||
InheritedProtocolCollector::collectSkippedConditionalConformances(
|
||||
inheritedProtocolMap, D);
|
||||
continue;
|
||||
}
|
||||
|
||||
D->print(out, printOptions);
|
||||
out << "\n";
|
||||
@@ -607,11 +681,18 @@ bool swift::emitParseableInterface(raw_ostream &out,
|
||||
}
|
||||
|
||||
// Print dummy extensions for any protocols that were indirectly conformed to.
|
||||
bool needDummyProtocolDeclaration = false;
|
||||
for (const auto &nominalAndCollector : inheritedProtocolMap) {
|
||||
const NominalTypeDecl *nominal = nominalAndCollector.first;
|
||||
const InheritedProtocolCollector &collector = nominalAndCollector.second;
|
||||
collector.printSynthesizedExtensionIfNeeded(out, printOptions,
|
||||
nominalAndCollector.first);
|
||||
collector.printSynthesizedExtensionIfNeeded(out, printOptions, nominal);
|
||||
needDummyProtocolDeclaration |=
|
||||
collector.printInaccessibleConformanceExtensionIfNeeded(out,
|
||||
printOptions,
|
||||
nominal);
|
||||
}
|
||||
if (needDummyProtocolDeclaration)
|
||||
InheritedProtocolCollector::printDummyProtocolDeclaration(out);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -823,11 +823,13 @@ public:
|
||||
genVTable.emitVTable();
|
||||
}
|
||||
|
||||
// Build a default witness table if this is a protocol.
|
||||
// Build a default witness table if this is a protocol that needs one.
|
||||
if (auto protocol = dyn_cast<ProtocolDecl>(theType)) {
|
||||
if (!protocol->isObjC() &&
|
||||
protocol->isResilient())
|
||||
if (!protocol->isObjC() && protocol->isResilient()) {
|
||||
auto *SF = protocol->getParentSourceFile();
|
||||
if (!SF || SF->Kind != SourceFileKind::Interface)
|
||||
SGM.emitDefaultWitnessTable(protocol);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3155,6 +3155,7 @@ public:
|
||||
if (!PD->hasValidSignature())
|
||||
return;
|
||||
|
||||
auto *SF = PD->getParentSourceFile();
|
||||
{
|
||||
// Check for circular inheritance within the protocol.
|
||||
SmallVector<ProtocolDecl *, 8> path;
|
||||
@@ -3162,7 +3163,7 @@ public:
|
||||
checkCircularity(TC, PD, diag::circular_protocol_def,
|
||||
DescriptiveDeclKind::Protocol, path);
|
||||
|
||||
if (auto *SF = PD->getParentSourceFile()) {
|
||||
if (SF) {
|
||||
if (auto *tracker = SF->getReferencedNameTracker()) {
|
||||
bool isNonPrivate =
|
||||
(PD->getFormalAccess() > AccessLevel::FilePrivate);
|
||||
@@ -3184,6 +3185,7 @@ public:
|
||||
|
||||
TC.checkDeclCircularity(PD);
|
||||
if (PD->isResilient())
|
||||
if (!SF || SF->Kind != SourceFileKind::Interface)
|
||||
TC.inferDefaultWitnesses(PD);
|
||||
|
||||
if (TC.Context.LangOpts.DebugGenericSignatures) {
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
// swift-module-flags:
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend -emit-module -enable-resilience -o %t/Conformances.swiftmodule %s
|
||||
// RUN: %target-swift-frontend -emit-module-path %t/Conformances.swiftmodule -enable-resilience -emit-sil -o %t/Conformances.sil %s
|
||||
// RUN: %FileCheck -check-prefix CHECK-MODULE %s < %t/Conformances.sil
|
||||
// RUN: %FileCheck -check-prefix NEGATIVE-MODULE %s < %t/Conformances.sil
|
||||
// RUN: %target-swift-frontend -emit-sil -I %t %S/Inputs/ConformancesUser.swift -O | %FileCheck %s
|
||||
|
||||
public protocol MyProto {
|
||||
@@ -11,6 +13,15 @@ public protocol MyProto {
|
||||
var prop: Int { get set }
|
||||
subscript(index: Int) -> Int { get set }
|
||||
}
|
||||
extension MyProto {
|
||||
public func method() {}
|
||||
}
|
||||
|
||||
// Make sure there's no default witness table. (But also make sure we printed at
|
||||
// least some regular witness tables, or we'll have to change the test.)
|
||||
// CHECK-MODULE: sil_witness_table{{.+}}: MyProto module Conformances
|
||||
// NEGATIVE-MODULE-NOT: sil_default_witness_table{{.+}}MyProto
|
||||
|
||||
|
||||
@_fixed_layout // allow conformance devirtualization
|
||||
public struct FullStructImpl: MyProto {
|
||||
@@ -31,7 +42,8 @@ public struct OpaqueStructImpl: MyProto {}
|
||||
|
||||
// CHECK-LABEL: sil @$s16ConformancesUser10testOpaqueSiyF
|
||||
// CHECK: function_ref @$s12Conformances7MyProtoPxycfC
|
||||
// CHECK: function_ref @$s12Conformances7MyProtoP6methodyyF
|
||||
// Note the default implementation is filled in here.
|
||||
// CHECK: function_ref @$s12Conformances7MyProtoPAAE6methodyyF
|
||||
// CHECK: function_ref @$s12Conformances7MyProtoP4propSivs
|
||||
// CHECK: function_ref @$s12Conformances7MyProtoPyS2icig
|
||||
// CHECK: end sil function '$s16ConformancesUser10testOpaqueSiyF'
|
||||
|
||||
@@ -81,7 +81,18 @@ public struct OuterGeneric<T> {
|
||||
// CHECK-NEXT: {{^ }$}}
|
||||
}
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
|
||||
public protocol ConditionallyConformed {}
|
||||
public protocol ConditionallyConformedAgain {}
|
||||
|
||||
// CHECK-END: extension conformances.OuterGeneric : ConditionallyConformed, ConditionallyConformedAgain where T : _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {}
|
||||
extension OuterGeneric: ConditionallyConformed where T: PrivateProto {}
|
||||
extension OuterGeneric: ConditionallyConformedAgain where T == PrivateProto {}
|
||||
|
||||
// CHECK-END: extension conformances.OuterGeneric.Inner : PublicBaseProto {}
|
||||
// CHECK-END: extension conformances.OuterGeneric.Inner : ConditionallyConformed, ConditionallyConformedAgain where T : _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {}
|
||||
extension OuterGeneric.Inner: ConditionallyConformed where T: PrivateProto {}
|
||||
extension OuterGeneric.Inner: ConditionallyConformedAgain where T == PrivateProto {}
|
||||
|
||||
private protocol AnotherPrivateSubProto: PublicBaseProto {}
|
||||
|
||||
@@ -147,3 +158,13 @@ private protocol BaseConstrainedProto: Base, PublicProto {}
|
||||
public class H1: Base, ClassConstrainedProto {}
|
||||
// CHECK: public class H1 : Base {
|
||||
// CHECK-END: extension conformances.H1 : PublicProto {}
|
||||
|
||||
public struct MultiGeneric<T, U, V> {}
|
||||
extension MultiGeneric: PublicProto where U: PrivateProto {}
|
||||
|
||||
// CHECK: public struct MultiGeneric<T, U, V> {
|
||||
// CHECK-END: extension conformances.MultiGeneric : PublicProto where T : _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {}
|
||||
|
||||
|
||||
// CHECK-END: @usableFromInline
|
||||
// CHECK-END-NEXT: internal protocol _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {}
|
||||
|
||||
Reference in New Issue
Block a user