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:
@@ -4445,11 +4445,17 @@ swift::getInheritedForPrinting(const Decl *decl,
|
||||
inherited = ed->getInherited();
|
||||
}
|
||||
|
||||
// Collect explicit inheritted types.
|
||||
// Collect explicit inherited types.
|
||||
for (auto TL: inherited) {
|
||||
if (auto Ty = TL.getType()) {
|
||||
if (auto NTD = Ty->getAnyNominal())
|
||||
if (!shouldPrint(NTD))
|
||||
if (auto ty = TL.getType()) {
|
||||
bool foundUnprintable = ty.findIf([shouldPrint](Type subTy) {
|
||||
if (auto aliasTy = dyn_cast<NameAliasType>(subTy.getPointer()))
|
||||
return !shouldPrint(aliasTy->getDecl());
|
||||
if (auto NTD = subTy->getAnyNominal())
|
||||
return !shouldPrint(NTD);
|
||||
return false;
|
||||
});
|
||||
if (foundUnprintable)
|
||||
continue;
|
||||
}
|
||||
Results.push_back(TL);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "swift/AST/ASTContext.h"
|
||||
#include "swift/AST/Decl.h"
|
||||
#include "swift/AST/DiagnosticsFrontend.h"
|
||||
#include "swift/AST/ExistentialLayout.h"
|
||||
#include "swift/AST/FileSystem.h"
|
||||
#include "swift/AST/Module.h"
|
||||
#include "swift/Frontend/Frontend.h"
|
||||
@@ -431,6 +432,157 @@ static void printImports(raw_ostream &out, ModuleDecl *M) {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Copied from ASTPrinter.cpp...
|
||||
static bool isPublicOrUsableFromInline(const ValueDecl *VD) {
|
||||
AccessScope scope =
|
||||
VD->getFormalAccessScope(/*useDC*/nullptr,
|
||||
/*treatUsableFromInlineAsPublic*/true);
|
||||
return scope.isPublic();
|
||||
}
|
||||
|
||||
static bool isPublicOrUsableFromInline(Type ty) {
|
||||
// Note the double negative here: we're looking for any referenced decls that
|
||||
// are *not* public-or-usableFromInline.
|
||||
return !ty.findIf([](Type typePart) -> bool {
|
||||
// FIXME: If we have an internal typealias for a non-internal type, we ought
|
||||
// to be able to print it by desugaring.
|
||||
if (auto *aliasTy = dyn_cast<NameAliasType>(typePart.getPointer()))
|
||||
return !isPublicOrUsableFromInline(aliasTy->getDecl());
|
||||
if (auto *nominal = typePart->getAnyNominal())
|
||||
return !isPublicOrUsableFromInline(nominal);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// Collects protocols that are conformed to by a particular nominal. Since
|
||||
/// ASTPrinter will only print the public ones, the non-public ones get left by
|
||||
/// the wayside. This is a problem when a non-public protocol inherits from a
|
||||
/// public protocol; the generated parseable interface still needs to make that
|
||||
/// dependency public.
|
||||
///
|
||||
/// The solution implemented here is to generate synthetic extensions that
|
||||
/// declare the extra conformances. This isn't perfect (it loses the sugared
|
||||
/// spelling of the protocol type, as well as the locality in the file), but it
|
||||
/// does work.
|
||||
class InheritedProtocolCollector {
|
||||
/// 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;
|
||||
|
||||
/// For each type in \p directlyInherited, classify the protocols it refers to
|
||||
/// as included for printing or not, and record them in the appropriate
|
||||
/// vectors.
|
||||
void recordProtocols(ArrayRef<TypeLoc> directlyInherited) {
|
||||
for (TypeLoc inherited : directlyInherited) {
|
||||
Type inheritedTy = inherited.getType();
|
||||
if (!inheritedTy || !inheritedTy->isExistentialType())
|
||||
continue;
|
||||
|
||||
bool canPrintNormally = isPublicOrUsableFromInline(inheritedTy);
|
||||
SmallVectorImpl<ProtocolDecl *> &whichProtocols =
|
||||
canPrintNormally ? IncludedProtocols : ExtraProtocols;
|
||||
|
||||
ExistentialLayout layout = inheritedTy->getExistentialLayout();
|
||||
for (ProtocolType *protoTy : layout.getProtocols())
|
||||
whichProtocols.push_back(protoTy->getDecl());
|
||||
// FIXME: This ignores layout constraints, but currently we don't support
|
||||
// any of those besides 'AnyObject'.
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
using PerTypeMap = llvm::MapVector<const NominalTypeDecl *,
|
||||
InheritedProtocolCollector>;
|
||||
|
||||
/// Given that we're about to print \p D, record its protocols in \p map.
|
||||
///
|
||||
/// \sa recordProtocols
|
||||
static void collectProtocols(PerTypeMap &map, const Decl *D) {
|
||||
ArrayRef<TypeLoc> directlyInherited;
|
||||
const NominalTypeDecl *nominal;
|
||||
const IterableDeclContext *memberContext;
|
||||
|
||||
if ((nominal = dyn_cast<NominalTypeDecl>(D))) {
|
||||
directlyInherited = nominal->getInherited();
|
||||
memberContext = nominal;
|
||||
|
||||
} else if (auto *extension = dyn_cast<ExtensionDecl>(D)) {
|
||||
if (extension->isConstrainedExtension()) {
|
||||
// Conditional conformances never apply to inherited protocols, nor
|
||||
// can they provide unconditional conformances that might be used in
|
||||
// other extensions.
|
||||
return;
|
||||
}
|
||||
nominal = extension->getExtendedNominal();
|
||||
directlyInherited = extension->getInherited();
|
||||
memberContext = extension;
|
||||
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
map[nominal].recordProtocols(directlyInherited);
|
||||
|
||||
// Recurse to find any nested types.
|
||||
for (const Decl *member : memberContext->getMembers())
|
||||
collectProtocols(map, member);
|
||||
}
|
||||
|
||||
/// 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.
|
||||
void
|
||||
printSynthesizedExtensionIfNeeded(raw_ostream &out,
|
||||
const PrintOptions &printOptions,
|
||||
const NominalTypeDecl *nominal) const {
|
||||
if (ExtraProtocols.empty())
|
||||
return;
|
||||
|
||||
SmallPtrSet<ProtocolDecl *, 16> handledProtocols;
|
||||
|
||||
// First record all protocols that have already been handled.
|
||||
for (ProtocolDecl *proto : IncludedProtocols) {
|
||||
proto->walkInheritedProtocols(
|
||||
[&handledProtocols](ProtocolDecl *inherited) -> TypeWalker::Action {
|
||||
handledProtocols.insert(inherited);
|
||||
return TypeWalker::Action::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
// Then walk the remaining ones, and see what we need to print.
|
||||
// Note: We could do this in one pass, but the logic is easier to
|
||||
// understand if we build up the list and then print it, even if it takes
|
||||
// a bit more memory.
|
||||
SmallVector<ProtocolDecl *, 16> protocolsToPrint;
|
||||
for (ProtocolDecl *proto : ExtraProtocols) {
|
||||
proto->walkInheritedProtocols(
|
||||
[&](ProtocolDecl *inherited) -> TypeWalker::Action {
|
||||
if (!handledProtocols.insert(inherited).second)
|
||||
return TypeWalker::Action::SkipChildren;
|
||||
if (isPublicOrUsableFromInline(inherited)) {
|
||||
protocolsToPrint.push_back(inherited);
|
||||
return TypeWalker::Action::SkipChildren;
|
||||
}
|
||||
return TypeWalker::Action::Continue;
|
||||
});
|
||||
}
|
||||
if (protocolsToPrint.empty())
|
||||
return;
|
||||
|
||||
out << "extension ";
|
||||
nominal->getDeclaredType().print(out, printOptions);
|
||||
out << " : ";
|
||||
swift::interleave(protocolsToPrint,
|
||||
[&out, &printOptions](ProtocolDecl *proto) {
|
||||
proto->getDeclaredType()->print(out, printOptions);
|
||||
}, [&out] { out << ", "; });
|
||||
out << " {}\n";
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
bool swift::emitParseableInterface(raw_ostream &out,
|
||||
ParseableInterfaceOptions const &Opts,
|
||||
ModuleDecl *M) {
|
||||
@@ -440,13 +592,26 @@ bool swift::emitParseableInterface(raw_ostream &out,
|
||||
printImports(out, M);
|
||||
|
||||
const PrintOptions printOptions = PrintOptions::printParseableInterfaceFile();
|
||||
InheritedProtocolCollector::PerTypeMap inheritedProtocolMap;
|
||||
|
||||
SmallVector<Decl *, 16> topLevelDecls;
|
||||
M->getTopLevelDecls(topLevelDecls);
|
||||
for (const Decl *D : topLevelDecls) {
|
||||
if (!D->shouldPrintInContext(printOptions))
|
||||
continue;
|
||||
|
||||
D->print(out, printOptions);
|
||||
out << "\n";
|
||||
|
||||
InheritedProtocolCollector::collectProtocols(inheritedProtocolMap, D);
|
||||
}
|
||||
|
||||
// Print dummy extensions for any protocols that were indirectly conformed to.
|
||||
for (const auto &nominalAndCollector : inheritedProtocolMap) {
|
||||
const InheritedProtocolCollector &collector = nominalAndCollector.second;
|
||||
collector.printSynthesizedExtensionIfNeeded(out, printOptions,
|
||||
nominalAndCollector.first);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// RUN: %target-swift-frontend-typecheck -emit-parseable-module-interface-path %t.swiftinterface %s
|
||||
// RUN: %FileCheck %s < %t.swiftinterface
|
||||
// RUN: %FileCheck -check-prefix CHECK-END %s < %t.swiftinterface
|
||||
// RUN: %FileCheck -check-prefix NEGATIVE %s < %t.swiftinterface
|
||||
|
||||
// CHECK-LABEL: public protocol SimpleProto {
|
||||
@@ -11,10 +12,138 @@ public protocol SimpleProto {
|
||||
func inference(_: Inferred)
|
||||
} // CHECK: {{^}$}}
|
||||
|
||||
// CHECK-LABEL: public struct SimplImpl<Element> : SimpleProto {
|
||||
public struct SimplImpl<Element>: SimpleProto {
|
||||
// CHECK-LABEL: public struct SimpleImpl<Element> : SimpleProto {
|
||||
public struct SimpleImpl<Element>: SimpleProto {
|
||||
// NEGATIVE-NOT: typealias Element =
|
||||
// CHECK: public func inference(_: Int){{$}}
|
||||
public func inference(_: Int) {}
|
||||
// CHECK: public typealias Inferred = Swift.Int
|
||||
} // CHECK: {{^}$}}
|
||||
|
||||
|
||||
public protocol PublicProto {}
|
||||
private protocol PrivateProto {}
|
||||
|
||||
// CHECK: public struct A1 : PublicProto {
|
||||
// NEGATIVE-NOT: extension conformances.A1
|
||||
public struct A1: PublicProto, PrivateProto {}
|
||||
// CHECK: public struct A2 : PublicProto {
|
||||
// NEGATIVE-NOT: extension conformances.A2
|
||||
public struct A2: PrivateProto, PublicProto {}
|
||||
// CHECK: public struct A3 {
|
||||
// CHECK-END: extension conformances.A3 : PublicProto {}
|
||||
public struct A3: PublicProto & PrivateProto {}
|
||||
// CHECK: public struct A4 {
|
||||
// CHECK-END: extension conformances.A4 : PublicProto {}
|
||||
public struct A4: PrivateProto & PublicProto {}
|
||||
|
||||
public protocol PublicBaseProto {}
|
||||
private protocol PrivateSubProto: PublicBaseProto {}
|
||||
|
||||
// CHECK: public struct B1 {
|
||||
// CHECK-END: extension conformances.B1 : PublicBaseProto {}
|
||||
public struct B1: PrivateSubProto {}
|
||||
// CHECK: public struct B2 : PublicBaseProto {
|
||||
// NEGATIVE-NOT: extension conformances.B2
|
||||
public struct B2: PublicBaseProto, PrivateSubProto {}
|
||||
// CHECK: public struct B3 {
|
||||
// CHECK-END: extension conformances.B3 : PublicBaseProto {}
|
||||
public struct B3: PublicBaseProto & PrivateSubProto {}
|
||||
// CHECK: public struct B4 : PublicBaseProto {
|
||||
// CHECK: extension B4 {
|
||||
// NEGATIVE-NOT: extension conformances.B4
|
||||
public struct B4: PublicBaseProto {}
|
||||
extension B4: PrivateSubProto {}
|
||||
// CHECK: public struct B5 {
|
||||
// CHECK: extension B5 : PublicBaseProto {
|
||||
// NEGATIVE-NOT: extension conformances.B5
|
||||
public struct B5: PrivateSubProto {}
|
||||
extension B5: PublicBaseProto {}
|
||||
// CHECK: public struct B6 {
|
||||
// CHECK: extension B6 {
|
||||
// CHECK: extension B6 : PublicBaseProto {
|
||||
// NEGATIVE-NOT: extension conformances.B6
|
||||
public struct B6 {}
|
||||
extension B6: PrivateSubProto {}
|
||||
extension B6: PublicBaseProto {}
|
||||
// CHECK: public struct B7 {
|
||||
// CHECK: extension B7 : PublicBaseProto {
|
||||
// CHECK: extension B7 {
|
||||
// NEGATIVE-NOT: extension conformances.B7
|
||||
public struct B7 {}
|
||||
extension B7: PublicBaseProto {}
|
||||
extension B7: PrivateSubProto {}
|
||||
|
||||
// CHECK-LABEL: public struct OuterGeneric<T> {
|
||||
public struct OuterGeneric<T> {
|
||||
// CHECK-NEXT: public struct Inner {
|
||||
public struct Inner: PrivateSubProto {}
|
||||
// CHECK-NEXT: {{^ }$}}
|
||||
}
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
// CHECK-END: extension conformances.OuterGeneric.Inner : PublicBaseProto {}
|
||||
|
||||
private protocol AnotherPrivateSubProto: PublicBaseProto {}
|
||||
|
||||
// CHECK: public struct C1 {
|
||||
// CHECK-END: extension conformances.C1 : PublicBaseProto {}
|
||||
public struct C1: PrivateSubProto, AnotherPrivateSubProto {}
|
||||
// CHECK: public struct C2 {
|
||||
// CHECK-END: extension conformances.C2 : PublicBaseProto {}
|
||||
public struct C2: PrivateSubProto & AnotherPrivateSubProto {}
|
||||
// CHECK: public struct C3 {
|
||||
// CHECK: extension C3 {
|
||||
// CHECK-END: extension conformances.C3 : PublicBaseProto {}
|
||||
public struct C3: PrivateSubProto {}
|
||||
extension C3: AnotherPrivateSubProto {}
|
||||
|
||||
public protocol PublicSubProto: PublicBaseProto {}
|
||||
public protocol APublicSubProto: PublicBaseProto {}
|
||||
|
||||
// CHECK: public struct D1 : PublicSubProto {
|
||||
// NEGATIVE-NOT: extension conformances.D1
|
||||
public struct D1: PublicSubProto, PrivateSubProto {}
|
||||
// CHECK: public struct D2 : PublicSubProto {
|
||||
// NEGATIVE-NOT: extension conformances.D2
|
||||
public struct D2: PrivateSubProto, PublicSubProto {}
|
||||
// CHECK: public struct D3 {
|
||||
// CHECK-END: extension conformances.D3 : PublicBaseProto, PublicSubProto {}
|
||||
public struct D3: PrivateSubProto & PublicSubProto {}
|
||||
// CHECK: public struct D4 {
|
||||
// CHECK-END: extension conformances.D4 : APublicSubProto, PublicBaseProto {}
|
||||
public struct D4: APublicSubProto & PrivateSubProto {}
|
||||
// CHECK: public struct D5 {
|
||||
// CHECK: extension D5 : PublicSubProto {
|
||||
// NEGATIVE-NOT: extension conformances.D5
|
||||
public struct D5: PrivateSubProto {}
|
||||
extension D5: PublicSubProto {}
|
||||
// CHECK: public struct D6 : PublicSubProto {
|
||||
// CHECK: extension D6 {
|
||||
// NEGATIVE-NOT: extension conformances.D6
|
||||
public struct D6: PublicSubProto {}
|
||||
extension D6: PrivateSubProto {}
|
||||
|
||||
private typealias PrivateProtoAlias = PublicProto
|
||||
|
||||
// CHECK: public struct E1 {
|
||||
// CHECK-END: extension conformances.E1 : PublicProto {}
|
||||
public struct E1: PrivateProtoAlias {}
|
||||
|
||||
private typealias PrivateSubProtoAlias = PrivateSubProto
|
||||
|
||||
// CHECK: public struct F1 {
|
||||
// CHECK-END: extension conformances.F1 : PublicBaseProto {}
|
||||
public struct F1: PrivateSubProtoAlias {}
|
||||
|
||||
private protocol ClassConstrainedProto: PublicProto, AnyObject {}
|
||||
|
||||
public class G1: ClassConstrainedProto {}
|
||||
// CHECK: public class G1 {
|
||||
// CHECK-END: extension conformances.G1 : PublicProto {}
|
||||
|
||||
public class Base {}
|
||||
private protocol BaseConstrainedProto: Base, PublicProto {}
|
||||
|
||||
public class H1: Base, ClassConstrainedProto {}
|
||||
// CHECK: public class H1 : Base {
|
||||
// CHECK-END: extension conformances.H1 : PublicProto {}
|
||||
|
||||
Reference in New Issue
Block a user