Skip to content

Commit 51c14c8

Browse files
authored
Merge pull request #16622 from huonw/better-protocol-conformance-printing
Better protocol conformance and substitution map printing
2 parents 8688bc7 + 35cc2d6 commit 51c14c8

File tree

8 files changed

+348
-86
lines changed

8 files changed

+348
-86
lines changed

include/swift/AST/SubstitutionMap.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,17 @@ class SubstitutionMap {
7171
/// signature nor any replacement types/conformances.
7272
Storage *storage = nullptr;
7373

74+
public:
7475
/// Retrieve the array of replacement types, which line up with the
7576
/// generic parameters.
7677
///
7778
/// Note that the types may be null, for cases where the generic parameter
7879
/// is concrete but hasn't been queried yet.
80+
///
81+
/// Prefer \c getReplacementTypes, this is public for printing purposes.
7982
ArrayRef<Type> getReplacementTypesBuffer() const;
8083

84+
private:
8185
MutableArrayRef<Type> getReplacementTypesBuffer();
8286

8387
/// Retrieve a mutable reference to the buffer of conformances.
@@ -218,8 +222,12 @@ class SubstitutionMap {
218222
/// Verify that this substitution map is valid.
219223
void verify() const;
220224

225+
/// Whether to dump the full substitution map, or just a minimal useful subset
226+
/// (on a single line).
227+
enum class DumpStyle { Minimal, Full };
221228
/// Dump the contents of this substitution map for debugging purposes.
222-
void dump(llvm::raw_ostream &out) const;
229+
void dump(llvm::raw_ostream &out, DumpStyle style = DumpStyle::Full,
230+
unsigned indent = 0) const;
223231

224232
LLVM_ATTRIBUTE_DEPRECATED(void dump() const, "only for use in the debugger");
225233

lib/AST/ASTDumper.cpp

Lines changed: 163 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/AST/ParameterList.h"
2424
#include "swift/AST/ProtocolConformance.h"
2525
#include "swift/AST/TypeVisitor.h"
26+
#include "swift/Basic/Defer.h"
2627
#include "swift/Basic/QuotedString.h"
2728
#include "swift/Basic/STLExtras.h"
2829
#include "llvm/ADT/APFloat.h"
@@ -2792,55 +2793,74 @@ void TypeRepr::dump() const {
27922793
llvm::errs() << '\n';
27932794
}
27942795

2795-
void ProtocolConformanceRef::dump() const {
2796-
dump(llvm::errs());
2797-
}
2798-
2799-
void ProtocolConformanceRef::dump(llvm::raw_ostream &out,
2800-
unsigned indent) const {
2801-
if (isConcrete()) {
2802-
getConcrete()->dump(out, indent);
2796+
// Recursive helpers to avoid infinite recursion for recursive protocol
2797+
// conformances.
2798+
static void dumpProtocolConformanceRec(
2799+
const ProtocolConformance *conformance, llvm::raw_ostream &out,
2800+
unsigned indent,
2801+
llvm::SmallPtrSetImpl<const ProtocolConformance *> &visited);
2802+
2803+
static void dumpSubstitutionMapRec(
2804+
SubstitutionMap map, llvm::raw_ostream &out,
2805+
SubstitutionMap::DumpStyle style, unsigned indent,
2806+
llvm::SmallPtrSetImpl<const ProtocolConformance *> &visited);
2807+
2808+
static void dumpProtocolConformanceRefRec(
2809+
const ProtocolConformanceRef conformance, llvm::raw_ostream &out,
2810+
unsigned indent,
2811+
llvm::SmallPtrSetImpl<const ProtocolConformance *> &visited) {
2812+
if (conformance.isConcrete()) {
2813+
dumpProtocolConformanceRec(conformance.getConcrete(), out, indent, visited);
28032814
} else {
28042815
out.indent(indent) << "(abstract_conformance protocol="
2805-
<< getAbstract()->getName();
2816+
<< conformance.getAbstract()->getName();
28062817
PrintWithColorRAII(out, ParenthesisColor) << ')';
2807-
out << '\n';
28082818
}
28092819
}
28102820

2811-
void ProtocolConformance::dump() const {
2812-
auto &out = llvm::errs();
2813-
dump(out);
2814-
out << '\n';
2815-
}
2821+
static void dumpProtocolConformanceRec(
2822+
const ProtocolConformance *conformance, llvm::raw_ostream &out,
2823+
unsigned indent,
2824+
llvm::SmallPtrSetImpl<const ProtocolConformance *> &visited) {
2825+
// A recursive conformance shouldn't have its contents printed, or there's
2826+
// infinite recursion. (This also avoids printing things that occur multiple
2827+
// times in a conformance hierarchy.)
2828+
auto shouldPrintDetails = visited.insert(conformance).second;
28162829

2817-
void ProtocolConformance::dump(llvm::raw_ostream &out, unsigned indent) const {
28182830
auto printCommon = [&](StringRef kind) {
28192831
out.indent(indent);
28202832
PrintWithColorRAII(out, ParenthesisColor) << '(';
2821-
out << kind << "_conformance type=" << getType()
2822-
<< " protocol=" << getProtocol()->getName();
2833+
out << kind << "_conformance type=" << conformance->getType()
2834+
<< " protocol=" << conformance->getProtocol()->getName();
2835+
2836+
if (!shouldPrintDetails)
2837+
out << " (details printed above)";
28232838
};
28242839

2825-
switch (getKind()) {
2840+
switch (conformance->getKind()) {
28262841
case ProtocolConformanceKind::Normal: {
2827-
auto normal = cast<NormalProtocolConformance>(this);
2842+
auto normal = cast<NormalProtocolConformance>(conformance);
28282843

28292844
printCommon("normal");
2845+
if (!shouldPrintDetails)
2846+
break;
2847+
28302848
// Maybe print information about the conforming context?
28312849
if (normal->isLazilyLoaded()) {
28322850
out << " lazy";
28332851
} else {
2834-
forEachTypeWitness(nullptr, [&](const AssociatedTypeDecl *req,
2835-
Type ty, const TypeDecl *) -> bool {
2836-
out << '\n';
2837-
out.indent(indent + 2);
2838-
PrintWithColorRAII(out, ParenthesisColor) << '(';
2839-
out << "assoc_type req=" << req->getName() << " type=";
2840-
PrintWithColorRAII(out, TypeColor) << ty;
2841-
PrintWithColorRAII(out, ParenthesisColor) << ')';
2842-
return false;
2843-
});
2852+
normal->forEachTypeWitness(
2853+
nullptr,
2854+
[&](const AssociatedTypeDecl *req, Type ty,
2855+
const TypeDecl *) -> bool {
2856+
out << '\n';
2857+
out.indent(indent + 2);
2858+
PrintWithColorRAII(out, ParenthesisColor) << '(';
2859+
out << "assoc_type req=" << req->getName() << " type=";
2860+
PrintWithColorRAII(out, TypeColor) << Type(ty->getDesugaredType());
2861+
PrintWithColorRAII(out, ParenthesisColor) << ')';
2862+
return false;
2863+
});
28442864
normal->forEachValueWitness(nullptr, [&](const ValueDecl *req,
28452865
Witness witness) {
28462866
out << '\n';
@@ -2857,9 +2877,9 @@ void ProtocolConformance::dump(llvm::raw_ostream &out, unsigned indent) const {
28572877
PrintWithColorRAII(out, ParenthesisColor) << ')';
28582878
});
28592879

2860-
for (auto conformance : normal->getSignatureConformances()) {
2880+
for (auto sigConf : normal->getSignatureConformances()) {
28612881
out << '\n';
2862-
conformance.dump(out, indent + 2);
2882+
dumpProtocolConformanceRefRec(sigConf, out, indent + 2, visited);
28632883
}
28642884
}
28652885

@@ -2872,31 +2892,137 @@ void ProtocolConformance::dump(llvm::raw_ostream &out, unsigned indent) const {
28722892
}
28732893

28742894
case ProtocolConformanceKind::Inherited: {
2875-
auto conf = cast<InheritedProtocolConformance>(this);
2895+
auto conf = cast<InheritedProtocolConformance>(conformance);
28762896
printCommon("inherited");
2897+
if (!shouldPrintDetails)
2898+
break;
2899+
28772900
out << '\n';
2878-
conf->getInheritedConformance()->dump(out, indent + 2);
2901+
dumpProtocolConformanceRec(conf->getInheritedConformance(), out, indent + 2,
2902+
visited);
28792903
break;
28802904
}
28812905

28822906
case ProtocolConformanceKind::Specialized: {
2883-
auto conf = cast<SpecializedProtocolConformance>(this);
2907+
auto conf = cast<SpecializedProtocolConformance>(conformance);
28842908
printCommon("specialized");
2909+
if (!shouldPrintDetails)
2910+
break;
2911+
2912+
out << '\n';
2913+
dumpSubstitutionMapRec(conf->getSubstitutionMap(), out,
2914+
SubstitutionMap::DumpStyle::Full, indent + 2,
2915+
visited);
28852916
out << '\n';
2886-
conf->getSubstitutionMap().dump(out);
28872917
for (auto subReq : conf->getConditionalRequirements()) {
28882918
out.indent(indent + 2);
28892919
subReq.dump(out);
28902920
out << '\n';
28912921
}
2892-
conf->getGenericConformance()->dump(out, indent + 2);
2922+
dumpProtocolConformanceRec(conf->getGenericConformance(), out, indent + 2,
2923+
visited);
28932924
break;
28942925
}
28952926
}
28962927

28972928
PrintWithColorRAII(out, ParenthesisColor) << ')';
28982929
}
28992930

2931+
static void dumpSubstitutionMapRec(
2932+
SubstitutionMap map, llvm::raw_ostream &out,
2933+
SubstitutionMap::DumpStyle style, unsigned indent,
2934+
llvm::SmallPtrSetImpl<const ProtocolConformance *> &visited) {
2935+
auto *genericSig = map.getGenericSignature();
2936+
out.indent(indent);
2937+
2938+
auto printParen = [&](char p) {
2939+
PrintWithColorRAII(out, ParenthesisColor) << p;
2940+
};
2941+
printParen('(');
2942+
SWIFT_DEFER { printParen(')'); };
2943+
out << "substitution_map generic_signature=";
2944+
if (genericSig == nullptr) {
2945+
out << "<nullptr>";
2946+
return;
2947+
}
2948+
2949+
genericSig->print(out);
2950+
auto genericParams = genericSig->getGenericParams();
2951+
auto replacementTypes =
2952+
static_cast<const SubstitutionMap &>(map).getReplacementTypesBuffer();
2953+
for (unsigned i : indices(genericParams)) {
2954+
if (style == SubstitutionMap::DumpStyle::Minimal) {
2955+
out << " ";
2956+
} else {
2957+
out << "\n";
2958+
out.indent(indent + 2);
2959+
}
2960+
printParen('(');
2961+
out << "substitution ";
2962+
genericParams[i]->print(out);
2963+
out << " -> ";
2964+
if (replacementTypes[i])
2965+
replacementTypes[i]->print(out);
2966+
else
2967+
out << "<<unresolved concrete type>>";
2968+
printParen(')');
2969+
}
2970+
// A minimal dump doesn't need the details about the conformances, a lot of
2971+
// that info can be inferred from the signature.
2972+
if (style == SubstitutionMap::DumpStyle::Minimal)
2973+
return;
2974+
2975+
auto conformances = map.getConformances();
2976+
for (const auto &req : genericSig->getRequirements()) {
2977+
if (req.getKind() != RequirementKind::Conformance)
2978+
continue;
2979+
2980+
out << "\n";
2981+
out.indent(indent + 2);
2982+
printParen('(');
2983+
out << "conformance type=";
2984+
req.getFirstType()->print(out);
2985+
out << "\n";
2986+
dumpProtocolConformanceRefRec(conformances.front(), out, indent + 4,
2987+
visited);
2988+
2989+
printParen(')');
2990+
conformances = conformances.slice(1);
2991+
}
2992+
}
2993+
2994+
void ProtocolConformanceRef::dump() const {
2995+
dump(llvm::errs());
2996+
llvm::errs() << '\n';
2997+
}
2998+
2999+
void ProtocolConformanceRef::dump(llvm::raw_ostream &out,
3000+
unsigned indent) const {
3001+
llvm::SmallPtrSet<const ProtocolConformance *, 8> visited;
3002+
dumpProtocolConformanceRefRec(*this, out, indent, visited);
3003+
}
3004+
void ProtocolConformance::dump() const {
3005+
auto &out = llvm::errs();
3006+
dump(out);
3007+
out << '\n';
3008+
}
3009+
3010+
void ProtocolConformance::dump(llvm::raw_ostream &out, unsigned indent) const {
3011+
llvm::SmallPtrSet<const ProtocolConformance *, 8> visited;
3012+
dumpProtocolConformanceRec(this, out, indent, visited);
3013+
}
3014+
3015+
void SubstitutionMap::dump(llvm::raw_ostream &out, DumpStyle style,
3016+
unsigned indent) const {
3017+
llvm::SmallPtrSet<const ProtocolConformance *, 8> visited;
3018+
dumpSubstitutionMapRec(*this, out, style, indent, visited);
3019+
}
3020+
3021+
void SubstitutionMap::dump() const {
3022+
dump(llvm::errs());
3023+
llvm::errs() << "\n";
3024+
}
3025+
29003026
//===----------------------------------------------------------------------===//
29013027
// Dumping for Types.
29023028
//===----------------------------------------------------------------------===//

lib/AST/ConcreteDeclRef.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ void ConcreteDeclRef::dump(raw_ostream &os) {
5656
// If specialized, dump the substitutions.
5757
if (isSpecialized()) {
5858
os << " [with ";
59-
getSubstitutions().dump(os);
59+
getSubstitutions().dump(os, SubstitutionMap::DumpStyle::Minimal);
6060
os << ']';
6161
}
6262
}

lib/AST/SubstitutionMap.cpp

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -615,48 +615,6 @@ void SubstitutionMap::verify() const {
615615
#endif
616616
}
617617

618-
void SubstitutionMap::dump(llvm::raw_ostream &out) const {
619-
auto *genericSig = getGenericSignature();
620-
if (genericSig == nullptr) {
621-
out << "Empty substitution map\n";
622-
return;
623-
}
624-
out << "Generic signature: ";
625-
genericSig->print(out);
626-
out << "\n";
627-
out << "Substitutions:\n";
628-
auto genericParams = genericSig->getGenericParams();
629-
auto replacementTypes = getReplacementTypesBuffer();
630-
for (unsigned i : indices(genericParams)) {
631-
out.indent(2);
632-
genericParams[i]->print(out);
633-
out << " -> ";
634-
if (replacementTypes[i])
635-
replacementTypes[i]->print(out);
636-
else
637-
out << "<<unresolved concrete type>>";
638-
out << "\n";
639-
}
640-
641-
out << "\nConformance map:\n";
642-
auto conformances = getConformances();
643-
for (const auto &req : genericSig->getRequirements()) {
644-
if (req.getKind() != RequirementKind::Conformance) continue;
645-
646-
out.indent(2);
647-
req.getFirstType()->print(out);
648-
out << " -> ";
649-
conformances.front().dump(out);
650-
out << "\n";
651-
652-
conformances = conformances.slice(1);
653-
}
654-
}
655-
656-
void SubstitutionMap::dump() const {
657-
return dump(llvm::errs());
658-
}
659-
660618
void SubstitutionMap::profile(llvm::FoldingSetNodeID &id) const {
661619
id.AddPointer(storage);
662620
}

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4668,17 +4668,20 @@ void TypeChecker::checkConformancesInContext(DeclContext *dc,
46684668
inferStaticInitializeObjCMetadata(*this, classDecl);
46694669
}
46704670
}
4671+
}
4672+
4673+
// Check all conformances.
4674+
groupChecker.checkAllConformances();
46714675

4672-
// When requested, print out information about this conformance.
4673-
if (Context.LangOpts.DebugGenericSignatures) {
4676+
if (Context.LangOpts.DebugGenericSignatures) {
4677+
// Now that they're filled out, print out information about the conformances
4678+
// here, when requested.
4679+
for (auto conformance : conformances) {
46744680
dc->dumpContext();
46754681
conformance->dump();
46764682
}
46774683
}
46784684

4679-
// Check all conformances.
4680-
groupChecker.checkAllConformances();
4681-
46824685
// Catalog all of members of this declaration context that satisfy
46834686
// requirements of conformances in this context.
46844687
SmallVector<ValueDecl *, 16>

0 commit comments

Comments
 (0)