mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
ASTPrinter: Refactor printing of RequirementSignatures
This commit is contained in:
@@ -73,6 +73,16 @@ public:
|
||||
GenericSignatureErrors getErrors() const {
|
||||
return Errors;
|
||||
}
|
||||
|
||||
void getRequirementsWithInverses(
|
||||
ProtocolDecl *owner,
|
||||
SmallVector<Requirement, 2> &reqs,
|
||||
SmallVector<InverseRequirement, 2> &inverses) const;
|
||||
|
||||
void print(ProtocolDecl *owner, raw_ostream &OS,
|
||||
const PrintOptions &Options = PrintOptions()) const;
|
||||
void print(ProtocolDecl *owner, ASTPrinter &Printer,
|
||||
const PrintOptions &Opts = PrintOptions()) const;
|
||||
};
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
@@ -970,6 +970,10 @@ public:
|
||||
ArrayRef<InverseRequirement> inverses,
|
||||
bool &isFirstReq, unsigned flags,
|
||||
llvm::function_ref<bool(const Requirement &)> filter);
|
||||
void printRequirementSignature(ProtocolDecl *owner,
|
||||
RequirementSignature sig,
|
||||
unsigned flags,
|
||||
TypeDecl *attachingTo);
|
||||
void printRequirement(const Requirement &req);
|
||||
void printRequirement(const InverseRequirement &inverse,
|
||||
bool forInherited);
|
||||
@@ -1566,46 +1570,20 @@ bestRequirementPrintLocation(ProtocolDecl *proto, const Requirement &req) {
|
||||
}
|
||||
|
||||
void PrintAST::printInheritedFromRequirementSignature(ProtocolDecl *proto,
|
||||
TypeDecl* attachingTo) {
|
||||
Type attachedGP[1];
|
||||
if (auto proto = dyn_cast<ProtocolDecl>(attachingTo))
|
||||
attachedGP[0] = proto->getSelfInterfaceType();
|
||||
else if (auto assoc = dyn_cast<AssociatedTypeDecl>(attachingTo))
|
||||
attachedGP[0] = assoc->getDeclaredInterfaceType();
|
||||
else
|
||||
llvm_unreachable("nonexhaustive");
|
||||
|
||||
printGenericSignature(
|
||||
proto->getRequirementSignatureAsGenericSignature(),
|
||||
PrintInherited,
|
||||
[&](const Requirement &req) {
|
||||
// Skip the inferred 'Self : AnyObject' constraint if this is an
|
||||
// @objc protocol.
|
||||
if ((req.getKind() == RequirementKind::Layout) &&
|
||||
req.getFirstType()->isEqual(proto->getSelfInterfaceType()) &&
|
||||
req.getLayoutConstraint()->getKind() ==
|
||||
LayoutConstraintKind::Class &&
|
||||
proto->isObjC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto location = bestRequirementPrintLocation(proto, req);
|
||||
return location.AttachedTo == attachingTo && !location.InWhereClause;
|
||||
});
|
||||
TypeDecl *attachingTo) {
|
||||
printRequirementSignature(
|
||||
proto, proto->getRequirementSignature(),
|
||||
PrintInherited | PrintInverseRequirements,
|
||||
attachingTo);
|
||||
}
|
||||
|
||||
void PrintAST::printWhereClauseFromRequirementSignature(ProtocolDecl *proto,
|
||||
TypeDecl *attachingTo) {
|
||||
unsigned flags = PrintRequirements;
|
||||
unsigned flags = PrintRequirements | PrintInverseRequirements;
|
||||
if (isa<AssociatedTypeDecl>(attachingTo))
|
||||
flags |= SwapSelfAndDependentMemberType;
|
||||
printGenericSignature(
|
||||
proto->getRequirementSignatureAsGenericSignature(),
|
||||
flags,
|
||||
[&](const Requirement &req) {
|
||||
auto location = bestRequirementPrintLocation(proto, req);
|
||||
return location.AttachedTo == attachingTo && location.InWhereClause;
|
||||
});
|
||||
printRequirementSignature(proto, proto->getRequirementSignature(), flags,
|
||||
attachingTo);
|
||||
}
|
||||
|
||||
/// A helper function to return the depth of a requirement.
|
||||
@@ -1926,6 +1904,62 @@ void PrintAST::printSingleDepthOfGenericSignature(
|
||||
Printer << ">";
|
||||
}
|
||||
|
||||
void PrintAST::printRequirementSignature(ProtocolDecl *owner,
|
||||
RequirementSignature sig,
|
||||
unsigned flags,
|
||||
TypeDecl *attachingTo) {
|
||||
SmallVector<Requirement, 2> requirements;
|
||||
SmallVector<InverseRequirement, 2> inverses;
|
||||
|
||||
if (flags & PrintInverseRequirements) {
|
||||
sig.getRequirementsWithInverses(owner, requirements, inverses);
|
||||
} else {
|
||||
requirements.append(sig.getRequirements().begin(),
|
||||
sig.getRequirements().end());
|
||||
}
|
||||
|
||||
if (attachingTo) {
|
||||
llvm::erase_if(requirements,
|
||||
[&](Requirement req) {
|
||||
// Skip the inferred 'Self : AnyObject' constraint if this is an
|
||||
// @objc protocol.
|
||||
if ((req.getKind() == RequirementKind::Layout) &&
|
||||
req.getFirstType()->isEqual(owner->getSelfInterfaceType()) &&
|
||||
req.getLayoutConstraint()->getKind() ==
|
||||
LayoutConstraintKind::Class &&
|
||||
owner->isObjC()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto location = bestRequirementPrintLocation(owner, req);
|
||||
if (location.AttachedTo != attachingTo)
|
||||
return true;
|
||||
|
||||
if (flags & PrintRequirements)
|
||||
return !location.InWhereClause;
|
||||
|
||||
return location.InWhereClause;
|
||||
});
|
||||
|
||||
auto interfaceTy =
|
||||
(isa<ProtocolDecl>(attachingTo)
|
||||
? cast<ProtocolDecl>(attachingTo)->getSelfInterfaceType()
|
||||
: cast<AssociatedTypeDecl>(attachingTo)->getDeclaredInterfaceType());
|
||||
|
||||
llvm::erase_if(inverses,
|
||||
[&](InverseRequirement req) {
|
||||
// We print inverse requirements in the inheritance clause only.
|
||||
if (flags & PrintRequirements)
|
||||
return true;
|
||||
return !req.subject->isEqual(interfaceTy);
|
||||
});
|
||||
}
|
||||
|
||||
printSingleDepthOfGenericSignature(
|
||||
owner->getGenericSignature().getGenericParams(), requirements, inverses,
|
||||
flags, [&](Requirement) { return true; });
|
||||
}
|
||||
|
||||
void PrintAST::printRequirement(const Requirement &req) {
|
||||
SmallVector<Type, 2> rootParameterPacks;
|
||||
getTransformedType(req.getFirstType())
|
||||
@@ -2786,13 +2820,12 @@ void PrintAST::printSynthesizedExtension(Type ExtendedType,
|
||||
void PrintAST::printSynthesizedExtensionImpl(Type ExtendedType,
|
||||
ExtensionDecl *ExtDecl) {
|
||||
auto printRequirementsFrom = [&](ExtensionDecl *ED, bool &IsFirst) {
|
||||
// NOTE: As with normal extensions, we do not collapse defaults.
|
||||
auto Sig = ED->getGenericSignature();
|
||||
printSingleDepthOfGenericSignature(Sig.getGenericParams(),
|
||||
Sig.getRequirements(),
|
||||
/*inverses=*/{},
|
||||
IsFirst,
|
||||
PrintRequirements,
|
||||
PrintRequirements | PrintInverseRequirements,
|
||||
[](const Requirement &Req){
|
||||
return true;
|
||||
});
|
||||
@@ -7946,6 +7979,22 @@ void GenericSignature::print(ASTPrinter &Printer,
|
||||
PrintAST(Printer, Opts).printGenericSignature(*this, flags);
|
||||
}
|
||||
|
||||
void RequirementSignature::print(ProtocolDecl *owner,
|
||||
raw_ostream &OS,
|
||||
const PrintOptions &Opts) const {
|
||||
StreamPrinter Printer(OS);
|
||||
print(owner, Printer, Opts);
|
||||
}
|
||||
|
||||
void RequirementSignature::print(ProtocolDecl *owner,
|
||||
ASTPrinter &Printer,
|
||||
const PrintOptions &Opts) const {
|
||||
auto flags = PrintAST::PrintParams | PrintAST::PrintRequirements;
|
||||
if (Opts.PrintInverseRequirements)
|
||||
flags |= PrintAST::PrintInverseRequirements;
|
||||
PrintAST(Printer, Opts).printRequirementSignature(owner, *this, flags, nullptr);
|
||||
}
|
||||
|
||||
void Requirement::print(raw_ostream &os, const PrintOptions &opts) const {
|
||||
StreamPrinter printer(os);
|
||||
PrintAST(printer, opts).printRequirement(*this);
|
||||
|
||||
@@ -1286,6 +1286,63 @@ void GenericSignatureImpl::getRequirementsWithInverses(
|
||||
continue;
|
||||
}
|
||||
|
||||
reqs.push_back(req);
|
||||
}
|
||||
}
|
||||
|
||||
void RequirementSignature::getRequirementsWithInverses(
|
||||
ProtocolDecl *owner,
|
||||
SmallVector<Requirement, 2> &reqs,
|
||||
SmallVector<InverseRequirement, 2> &inverses) const {
|
||||
auto &ctx = owner->getASTContext();
|
||||
|
||||
if (!SWIFT_ENABLE_EXPERIMENTAL_NONCOPYABLE_GENERICS &&
|
||||
!ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
|
||||
reqs.append(getRequirements().begin(), getRequirements().end());
|
||||
return;
|
||||
}
|
||||
|
||||
auto sig = owner->getGenericSignature();
|
||||
|
||||
llvm::SmallDenseSet<CanType, 2> assocTypes;
|
||||
|
||||
auto visit = [&](Type interfaceType) {
|
||||
assocTypes.insert(interfaceType->getCanonicalType());
|
||||
|
||||
// Any associated type declaration with a superclass bound or concrete type
|
||||
// does not have an inverse.
|
||||
if (sig->getSuperclassBound(interfaceType) ||
|
||||
sig->getConcreteType(interfaceType))
|
||||
return;
|
||||
|
||||
for (auto ip : InvertibleProtocolSet::full()) {
|
||||
auto *proto = ctx.getProtocol(getKnownProtocolKind(ip));
|
||||
|
||||
// If we can derive a conformance to this protocol, then don't add an
|
||||
// inverse.
|
||||
if (sig->requiresProtocol(interfaceType, proto))
|
||||
continue;
|
||||
|
||||
// Nothing implies a conformance to this protocol, so record the inverse.
|
||||
inverses.push_back({interfaceType, proto, SourceLoc()});
|
||||
}
|
||||
};
|
||||
|
||||
visit(owner->getSelfInterfaceType());
|
||||
|
||||
// Record the absence of conformances to invertible protocols.
|
||||
for (auto assocType : owner->getAssociatedTypeMembers()) {
|
||||
visit(assocType->getDeclaredInterfaceType());
|
||||
}
|
||||
|
||||
// Filter out explicit conformances to invertible protocols.
|
||||
for (auto req : getRequirements()) {
|
||||
if (req.getKind() == RequirementKind::Conformance &&
|
||||
assocTypes.count(req.getFirstType()->getCanonicalType()) &&
|
||||
req.getProtocolDecl()->getInvertibleProtocolKind()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
reqs.push_back(req);
|
||||
}
|
||||
}
|
||||
@@ -3449,28 +3449,18 @@ public:
|
||||
TypeChecker::inferDefaultWitnesses(PD);
|
||||
|
||||
if (Ctx.TypeCheckerOpts.DebugGenericSignatures) {
|
||||
auto sig = PD->getRequirementSignatureAsGenericSignature();
|
||||
llvm::errs() << "\n";
|
||||
llvm::errs() << "Protocol requirement signature:\n";
|
||||
auto sig = PD->getRequirementSignature();
|
||||
PD->dumpRef(llvm::errs());
|
||||
llvm::errs() << "\n";
|
||||
llvm::errs() << "Requirement signature: ";
|
||||
PrintOptions Opts;
|
||||
Opts.ProtocolQualifiedDependentMemberTypes = true;
|
||||
Opts.PrintInverseRequirements = true;
|
||||
sig->print(llvm::errs(), Opts);
|
||||
llvm::errs() << "\n";
|
||||
|
||||
llvm::errs() << "Canonical requirement signature: ";
|
||||
auto canSig =
|
||||
CanGenericSignature::getCanonical(sig.getGenericParams(),
|
||||
sig.getRequirements());
|
||||
canSig->print(llvm::errs(), Opts);
|
||||
Opts.PrintInverseRequirements =
|
||||
Ctx.TypeCheckerOpts.DebugInverseRequirements;
|
||||
sig.print(PD, llvm::errs(), Opts);
|
||||
llvm::errs() << "\n";
|
||||
}
|
||||
|
||||
dumpGenericSignature(Ctx, PD);
|
||||
|
||||
if (!reqSig.getErrors()) {
|
||||
// Always verify signatures, even if building without asserts.
|
||||
//
|
||||
|
||||
@@ -1,32 +1,23 @@
|
||||
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s 2>&1 | %FileCheck %s
|
||||
|
||||
// CHECK: Generic signature: <Self where Self : P1>
|
||||
// CHECK-NEXT: Canonical generic signature: <τ_0_0 where τ_0_0 : P1>
|
||||
// CHECK-LABEL: main.(file).P1@
|
||||
// CHECK: Requirement signature: <Self>
|
||||
// CHECK-NEXT: Canonical requirement signature: <τ_0_0>
|
||||
protocol P1 {
|
||||
associatedtype A
|
||||
func f() -> A
|
||||
}
|
||||
|
||||
// Recursion, and where clauses.
|
||||
// CHECK: Generic signature: <Self where Self : P2>
|
||||
// CHECK-NEXT: Canonical generic signature: <τ_0_0 where τ_0_0 : P2>
|
||||
// CHECK-LABEL: main.(file).P2@
|
||||
// CHECK: Requirement signature: <Self where Self.[P2]A : P2, Self.[P2]B : P2, Self.[P2]A.[P2]A == Self.[P2]B.[P2]A>
|
||||
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.[P2]A : P2, τ_0_0.[P2]B : P2, τ_0_0.[P2]A.[P2]A == τ_0_0.[P2]B.[P2]A>
|
||||
// CHECK-NEXT: Requirement signature: <Self where Self.[P2]A : P2, Self.[P2]B : P2, Self.[P2]A.[P2]A == Self.[P2]B.[P2]A>
|
||||
protocol P2 {
|
||||
associatedtype A: P2
|
||||
associatedtype B: P2 where Self.A.A == Self.B.A
|
||||
}
|
||||
|
||||
// Simpler recursion
|
||||
// CHECK: Generic signature: <Self where Self : P3>
|
||||
// CHECK-NEXT: Canonical generic signature: <τ_0_0 where τ_0_0 : P3>
|
||||
// CHECK-LABEL: main.(file).P3@
|
||||
// CHECK: Requirement signature: <Self where Self.[P3]A : P3>
|
||||
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.[P3]A : P3>
|
||||
// CHECK-NEXT: Requirement signature: <Self where Self.[P3]A : P3>
|
||||
protocol P3 {
|
||||
associatedtype A: P3
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ protocol PWorse {
|
||||
protocol Q1 {}
|
||||
protocol Q2 {}
|
||||
|
||||
// CHECK-LABEL: ExtensionDecl line={{.*}} base=P
|
||||
// CHECK-NEXT: Generic signature: <Self where Self : P>
|
||||
extension P {
|
||||
typealias B = (Q1 & Q2)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ class X3 { }
|
||||
|
||||
// CHECK-LABEL: .P25a@
|
||||
// CHECK-NEXT: Requirement signature: <Self where Self.[P25a]A == X24<Self.[P25a]B>, Self.[P25a]B : P20>
|
||||
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.[P25a]A == X24<τ_0_0.[P25a]B>, τ_0_0.[P25a]B : P20>
|
||||
protocol P25a {
|
||||
associatedtype A: P24 // expected-warning{{redundant conformance constraint 'X24<Self.B>' : 'P24'}}
|
||||
associatedtype B: P20 where A == X24<B>
|
||||
@@ -31,7 +30,6 @@ protocol P25a {
|
||||
|
||||
// CHECK-LABEL: .P25b@
|
||||
// CHECK-NEXT: Requirement signature: <Self where Self.[P25b]A == X24<Self.[P25b]B>, Self.[P25b]B : P20>
|
||||
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.[P25b]A == X24<τ_0_0.[P25b]B>, τ_0_0.[P25b]B : P20>
|
||||
protocol P25b {
|
||||
associatedtype A
|
||||
associatedtype B: P20 where A == X24<B>
|
||||
@@ -39,7 +37,6 @@ protocol P25b {
|
||||
|
||||
// CHECK-LABEL: .P27a@
|
||||
// CHECK-NEXT: Requirement signature: <Self where Self.[P27a]A == X26<Self.[P27a]B>, Self.[P27a]B : X3>
|
||||
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.[P27a]A == X26<τ_0_0.[P27a]B>, τ_0_0.[P27a]B : X3>
|
||||
protocol P27a {
|
||||
associatedtype A: P26 // expected-warning{{redundant conformance constraint 'X26<Self.B>' : 'P26'}}
|
||||
|
||||
@@ -48,7 +45,6 @@ protocol P27a {
|
||||
|
||||
// CHECK-LABEL: .P27b@
|
||||
// CHECK-NEXT: Requirement signature: <Self where Self.[P27b]A == X26<Self.[P27b]B>, Self.[P27b]B : X3>
|
||||
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.[P27b]A == X26<τ_0_0.[P27b]B>, τ_0_0.[P27b]B : X3>
|
||||
protocol P27b {
|
||||
associatedtype A
|
||||
associatedtype B: X3 where A == X26<B>
|
||||
|
||||
@@ -282,23 +282,15 @@ struct X22<T, U> {
|
||||
U == X20<T> { }
|
||||
}
|
||||
|
||||
// CHECK: Generic signature: <Self where Self : P22>
|
||||
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P22>
|
||||
// CHECK: Protocol requirement signature:
|
||||
// CHECK: .P22@
|
||||
// CHECK-NEXT: Requirement signature: <Self where Self.[P22]A == X20<Self.[P22]B>, Self.[P22]B : P20>
|
||||
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.[P22]A == X20<τ_0_0.[P22]B>, τ_0_0.[P22]B : P20>
|
||||
protocol P22 {
|
||||
associatedtype A
|
||||
associatedtype B: P20 where A == X20<B>
|
||||
}
|
||||
|
||||
// CHECK: Generic signature: <Self where Self : P23>
|
||||
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P23>
|
||||
// CHECK: Protocol requirement signature:
|
||||
// CHECK: .P23@
|
||||
// CHECK-NEXT: Requirement signature: <Self where Self.[P23]A == X20<Self.[P23]B>, Self.[P23]B : P20>
|
||||
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.[P23]A == X20<τ_0_0.[P23]B>, τ_0_0.[P23]B : P20>
|
||||
protocol P23 {
|
||||
associatedtype A
|
||||
associatedtype B: P20
|
||||
@@ -332,8 +324,7 @@ struct X28 : P2 {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: .P28@
|
||||
// CHECK-NEXT: Requirement signature: <Self where Self : P3, Self.[P3]P3Assoc == X28>
|
||||
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : P3, τ_0_0.[P3]P3Assoc == X28>
|
||||
// CHECK: Requirement signature: <Self where Self : P3, Self.[P3]P3Assoc == X28>
|
||||
protocol P28: P3 {
|
||||
typealias P3Assoc = X28 // expected-warning{{typealias overriding associated type}}
|
||||
}
|
||||
|
||||
@@ -11,15 +11,14 @@ protocol IteratorProtocol {
|
||||
func next() -> Element?
|
||||
}
|
||||
|
||||
// CHECK: requirement_inference_funny_order.(file).LocalArray@
|
||||
// CHECK: Generic signature: <Element where Element : P1>
|
||||
|
||||
// CHECK: ExtensionDecl line={{[0-9]+}} base=LocalArray
|
||||
// CHECK: Generic signature: <Element where Element : P1, Element : P2>
|
||||
extension LocalArray where Element : P2 {
|
||||
static func ==(lhs: Self, rhs: Self) -> Bool {}
|
||||
}
|
||||
|
||||
// CHECK: requirement_inference_funny_order.(file).LocalArray@
|
||||
// CHECK: Generic signature: <Element where Element : P1>
|
||||
struct LocalArray<Element : P1>: IteratorProtocol {
|
||||
func next() -> Element? {}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ import NoncopyableGenerics_Misc
|
||||
// CHECK-MISC-NEXT: public struct ExplicitHello<T> : ~Copyable where T : ~Copyable {
|
||||
|
||||
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
|
||||
// CHECK-MISC-NEXT: extension {{.*}}.ExplicitHello : Swift.Copyable where T : Swift.Copyable {
|
||||
// CHECK-MISC-NEXT: extension {{.*}}.ExplicitHello : Swift.Copyable {
|
||||
|
||||
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
|
||||
// CHECK-MISC-NEXT: public struct Hello<T> where T : ~Copyable, T : ~Escapable {
|
||||
|
||||
Reference in New Issue
Block a user