Merge remote-tracking branch 'origin/master' into master-next

This commit is contained in:
swift-ci
2018-11-09 08:29:26 -08:00
5 changed files with 129 additions and 11 deletions

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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'

View File

@@ -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 {}