//===--- ASTPrinter.cpp - Swift Language AST Printer---------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements printing for the Swift ASTs. // //===----------------------------------------------------------------------===// #include "swift/AST/ArchetypeBuilder.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/PrintOptions.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeVisitor.h" #include "swift/AST/Types.h" #include "swift/Basic/Fallthrough.h" #include "swift/Basic/PrimitiveParsing.h" #include "swift/Basic/STLExtras.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SaveAndRestore.h" #include using namespace swift; void ASTPrinter::anchor() {} void ASTPrinter::printIndent() { llvm::SmallString<16> Str; for (unsigned i = 0; i != CurrentIndentation; ++i) Str += ' '; printText(Str); } void ASTPrinter::printTextImpl(StringRef Text) { if (PendingNewlines != 0) { llvm::SmallString<16> Str; for (unsigned i = 0; i != PendingNewlines; ++i) Str += '\n'; PendingNewlines = 0; printText(Str); printIndent(); } const Decl *PreD = PendingDeclPreCallback; const Decl *LocD = PendingDeclLocCallback; PendingDeclPreCallback = nullptr; PendingDeclLocCallback = nullptr; if (PreD) { printDeclPre(PreD); } if (LocD) { printDeclLoc(LocD); } printText(Text); } ASTPrinter &ASTPrinter::operator<<(unsigned long long N) { llvm::SmallString<32> Str; llvm::raw_svector_ostream OS(Str); OS << N; printTextImpl(OS.str()); return *this; } void ASTPrinter::printName(Identifier Name) { if (Name.empty()) { *this << "_"; return; } bool IsKeyword = llvm::StringSwitch(Name.str()) #define KEYWORD(KW) \ .Case(#KW, true) #include "swift/Parse/Tokens.def" .Default(false); if (IsKeyword) *this << "`"; *this << Name.str(); if (IsKeyword) *this << "`"; } void StreamPrinter::printText(StringRef Text) { OS << Text; } namespace { /// \brief AST pretty-printer. class PrintAST : public ASTVisitor { ASTPrinter &Printer; PrintOptions Options; unsigned IndentLevel = 0; friend DeclVisitor; /// \brief RAII object that increases the indentation level. class IndentRAII { PrintAST &Self; bool DoIndent; public: IndentRAII(PrintAST &self, bool DoIndent = true) : Self(self), DoIndent(DoIndent) { if (DoIndent) Self.IndentLevel += Self.Options.Indent; } ~IndentRAII() { if (DoIndent) Self.IndentLevel -= Self.Options.Indent; } }; /// \brief Indent the current number of indentation spaces. void indent() { Printer.setIndent(IndentLevel); } /// \brief Record the location of this declaration, which is about to /// be printed. void recordDeclLoc(Decl *decl) { Printer.callPrintDeclLoc(decl); } void printClangDocumentationComment(const clang::Decl *D) { const auto &ClangContext = D->getASTContext(); const clang::RawComment *RC = ClangContext.getRawCommentForAnyRedecl(D); if (!RC) return; if (!Options.PrintRegularClangComments) { Printer.printNewline(); indent(); } bool Invalid; unsigned StartLocCol = ClangContext.getSourceManager().getSpellingColumnNumber( RC->getLocStart(), &Invalid); if (Invalid) StartLocCol = 0; unsigned WhitespaceToTrim = StartLocCol ? StartLocCol - 1 : 0; SmallVector Lines; StringRef RawText = RC->getRawText(ClangContext.getSourceManager()).rtrim("\n\r"); trimLeadingWhitespaceFromLines(RawText, WhitespaceToTrim, Lines); for (auto Line : Lines) { Printer << Line; Printer.printNewline(); } } void printDocumentationComment(Decl *D) { if (!Options.PrintDocumentationComments) return; auto MaybeClangNode = D->getClangNode(); if (MaybeClangNode) { if (auto *CD = MaybeClangNode.getAsDecl()) printClangDocumentationComment(CD); return; } // FIXME: print native Swift documentation comments. } void printStaticKeyword(StaticSpellingKind StaticSpelling) { switch (StaticSpelling) { case StaticSpellingKind::None: llvm_unreachable("should not be called for non-static decls"); case StaticSpellingKind::KeywordStatic: Printer << "static "; break; case StaticSpellingKind::KeywordClass: Printer<< "class "; break; } } void printOverrideKeyword(Decl *D) { if (Options.PrintOverrideKeyword && D->getAttrs().hasAttribute()) Printer << "override "; } void printTypeLoc(const TypeLoc &TL) { // Print a TypeRepr if instructed to do so by options, or if the type // is null. if ((Options.PreferTypeRepr && TL.hasLocation()) || TL.getType().isNull()) { TL.getTypeRepr()->print(Printer, Options); return; } TL.getType().print(Printer, Options); } void printAttributes(const Decl *D); void printTypedPattern(const TypedPattern *TP, bool StripOuterSliceType = false); public: void printPattern(const Pattern *pattern); void printGenericParams(GenericParamList *params); private: bool shouldPrint(const Decl *D); void printAccessors(AbstractStorageDecl *ASD); void printMembers(DeclRange members, bool needComma = false); void printNominalDeclName(NominalTypeDecl *decl); void printInherited(const Decl *decl, ArrayRef inherited, ArrayRef protos, Type superclass = {}, bool PrintAsProtocolComposition = false); template void printInheritedWithSuperclass(DeclWithSuperclass *decl); void printInherited(const TypeDecl *decl); void printInherited(const EnumDecl *D); void printInherited(const ExtensionDecl *decl); void printInherited(const GenericTypeParamDecl *D); void printEnumElement(EnumElementDecl *elt); /// \returns true if anything was printed. bool printBraceStmtElements(BraceStmt *stmt, bool NeedIndent = true); void printOneParameter(Identifier ArgName, const Pattern *BodyPattern, bool ArgNameIsAPIByDefault, bool StripOuterSliceType, bool Curried); /// \brief Print the function parameters in curried or selector style, /// to match the original function declaration. void printFunctionParameters(AbstractFunctionDecl *AFD); #define DECL(Name,Parent) void visit##Name##Decl(Name##Decl *decl); #define ABSTRACT_DECL(Name, Parent) #define DECL_RANGE(Name,Start,End) #include "swift/AST/DeclNodes.def" #define STMT(Name, Parent) void visit##Name##Stmt(Name##Stmt *stmt); #include "swift/AST/StmtNodes.def" public: PrintAST(ASTPrinter &Printer, const PrintOptions &Options) : Printer(Printer), Options(Options) {} using ASTVisitor::visit; bool visit(Decl *D) { if (!shouldPrint(D)) return false; Printer.callPrintDeclPre(D); ASTVisitor::visit(D); Printer.printDeclPost(D); return true; } }; } // unnamed namespace void PrintAST::printAttributes(const Decl *D) { if (Options.SkipAttributes) return; D->getAttrs().print(Printer, Options); } void PrintAST::printTypedPattern(const TypedPattern *TP, bool StripOuterSliceType) { auto TheTypeLoc = TP->getTypeLoc(); if (TheTypeLoc.hasLocation()) { // If the outer typeloc is an InOutTypeRepr, print the inout before the // subpattern. if (auto *IOT = dyn_cast(TheTypeLoc.getTypeRepr())) { TheTypeLoc = TypeLoc(IOT->getBase()); Type T = TheTypeLoc.getType(); if (T) { if (auto *IOT = T->getAs()) { T = IOT->getObjectType(); TheTypeLoc.setType(T); } } Printer << "inout "; } printPattern(TP->getSubPattern()); Printer << ": "; if (StripOuterSliceType) { Type T = TP->getType(); if (auto *BGT = T->getAs()) { BGT->getGenericArgs()[0].print(Printer, Options); return; } } printTypeLoc(TheTypeLoc); return; } Type T = TP->getType(); if (auto *IOT = T->getAs()) { T = IOT->getObjectType(); Printer << "inout "; } printPattern(TP->getSubPattern()); Printer << ": "; if (StripOuterSliceType) { if (auto *BGT = T->getAs()) { BGT->getGenericArgs()[0].print(Printer, Options); return; } } T.print(Printer, Options); } void PrintAST::printPattern(const Pattern *pattern) { switch (pattern->getKind()) { case PatternKind::Any: Printer << "_"; break; case PatternKind::Named: { auto named = cast(pattern); recordDeclLoc(named->getDecl()); Printer.printName(named->getBoundName()); break; } case PatternKind::Paren: Printer << "("; printPattern(cast(pattern)->getSubPattern()); Printer << ")"; break; case PatternKind::Tuple: { Printer << "("; auto TP = cast(pattern); auto Fields = TP->getFields(); for (unsigned i = 0, e = Fields.size(); i != e; ++i) { const auto &Elt = Fields[i]; if (i != 0) Printer << ", "; if (i == e - 1 && TP->hasVararg()) { printTypedPattern(cast(Elt.getPattern()), /*StripOuterSliceType=*/true); } else { printPattern(Elt.getPattern()); } if (Elt.getDefaultArgKind() != DefaultArgumentKind::None) { if (Options.PrintDefaultParameterPlaceholder) Printer << " = default"; else if (Options.VarInitializers) { // FIXME: Print initializer here. } } } if (TP->hasVararg()) Printer << "..."; Printer << ")"; break; } case PatternKind::Typed: printTypedPattern(cast(pattern)); break; case PatternKind::Isa: { auto isa = cast(pattern); Printer << "is "; isa->getCastTypeLoc().getType().print(Printer, Options); break; } case PatternKind::NominalType: { auto type = cast(pattern); type->getCastTypeLoc().getType().print(Printer, Options); Printer << "("; interleave(type->getElements().begin(), type->getElements().end(), [&](const NominalTypePattern::Element &elt) { Printer << elt.getPropertyName().str() << ":"; printPattern(elt.getSubPattern()); }, [&] { Printer << ", "; }); break; } case PatternKind::EnumElement: { auto elt = cast(pattern); // FIXME: Print element expr. if (elt->hasSubPattern()) printPattern(elt->getSubPattern()); break; } case PatternKind::Expr: // FIXME: Print expr. break; case PatternKind::Var: if (!Options.SkipIntroducerKeywords) Printer << "var "; printPattern(cast(pattern)->getSubPattern()); } } void PrintAST::printGenericParams(GenericParamList *Params) { if (!Params) return; Printer << "<"; bool IsFirst = true; for (auto GP : Params->getParams()) { if (IsFirst) { IsFirst = false; } else { Printer << ", "; } auto TypeParam = GP.getAsTypeParam(); Printer.printName(TypeParam->getName()); printInherited(TypeParam); } auto Requirements = Params->getRequirements(); if (!Requirements.empty()) { bool IsFirst = true; for (auto &Req : Requirements) { if (Req.isInvalid() || Req.getKind() == RequirementKind::WitnessMarker) continue; if (IsFirst) { Printer << " where "; IsFirst = false; } else { Printer << ", "; } switch (Req.getKind()) { case RequirementKind::Conformance: printTypeLoc(Req.getSubjectLoc()); Printer << " : "; printTypeLoc(Req.getConstraintLoc()); break; case RequirementKind::SameType: printTypeLoc(Req.getFirstTypeLoc()); Printer << " == "; printTypeLoc(Req.getSecondTypeLoc()); break; case RequirementKind::WitnessMarker: llvm_unreachable("Handled above"); } } } Printer << ">"; } bool PrintAST::shouldPrint(const Decl *D) { if (Options.SkipImplicit && D->isImplicit()) return false; if (Options.SkipUnavailable && D->getAttrs().isUnavailable()) return false; if (Options.SkipLeadingUnderscoreDecls) { if (auto VD = dyn_cast(D)) { if (VD->hasName() && VD->getFullName().getBaseName().str().startswith("_")) return false; } } if (auto Ext = dyn_cast(D)) { // If the extension doesn't add protocols or has no members that we should // print then skip printing it. if (Ext->getProtocols().empty()) { bool HasMemberToPrint = false; for (auto Member : Ext->getMembers()) { if (shouldPrint(Member)) { HasMemberToPrint = true; break; } } if (!HasMemberToPrint) return false; } } return true; } void PrintAST::printAccessors(AbstractStorageDecl *ASD) { if (!ASD->hasAccessorFunctions() || ASD->getStorageKind() == AbstractStorageDecl::StoredWithTrivialAccessors){ // This is a 'let' vardecl. We could print the initializer if we could // print expressions. return; } if (Options.PrintGetSetOnRWProperties && !Options.FunctionDefinitions && (ASD->getGetter() || ASD->getSetter())) { Printer << " {"; if (ASD->getGetter()) Printer << " get"; if (ASD->getSetter()) Printer << " set"; Printer << " }"; return; } bool InProtocol = isa(ASD->getDeclContext()); if (!InProtocol && !Options.FunctionDefinitions && !Options.PrintGetSetOnRWProperties && ASD->getGetter() && ASD->getSetter()) return; bool PrintAccessorBody = Options.FunctionDefinitions && !InProtocol; auto PrintAccessor = [&](AbstractFunctionDecl *Accessor, StringRef Label) { if (!Accessor) return; if (!PrintAccessorBody) Printer << " " << Label; else { Printer.printNewline(); IndentRAII IndentMore(*this); indent(); visit(Accessor); } }; Printer << " {"; if (ASD->getStorageKind() == VarDecl::Observing) { PrintAccessor(ASD->getWillSetFunc(), "willSet"); PrintAccessor(ASD->getDidSetFunc(), "didSet"); } else { PrintAccessor(ASD->getGetter(), "get"); PrintAccessor(ASD->getSetter(), "set"); } if (PrintAccessorBody) { Printer.printNewline(); indent(); } else Printer << " "; Printer << "}"; } void PrintAST::printMembers(DeclRange members, bool needComma) { Printer << " {"; Printer.printNewline(); { IndentRAII indentMore(*this); for (auto i = members.begin(), iEnd = members.end(); i != iEnd; ++i) { auto member = *i; if (!shouldPrint(member)) continue; if (!member->shouldPrintInContext(Options)) continue; indent(); visit(member); if (needComma && std::next(i) != iEnd) Printer << ","; Printer.printNewline(); } } indent(); Printer << "}"; } void PrintAST::printNominalDeclName(NominalTypeDecl *decl) { Printer.printName(decl->getName()); if (auto gp = decl->getGenericParams()) { if (!isa(decl)) printGenericParams(gp); } } void PrintAST::printInherited(const Decl *decl, ArrayRef inherited, ArrayRef protos, Type superclass, bool PrintAsProtocolComposition) { if (inherited.empty() && superclass.isNull()) { if (protos.empty()) return; // If only conforms to AnyObject protocol, nothing to print. if (protos.size() == 1) { if (protos.front()->isSpecificProtocol(KnownProtocolKind::AnyObject)) return; } } if (inherited.empty()) { bool PrintedColon = false; bool PrintedInherited = false; if (superclass) { Printer << " : "; superclass.print(Printer, Options); PrintedInherited = true; } bool UseProtocolCompositionSyntax = PrintAsProtocolComposition && protos.size() > 1; if (UseProtocolCompositionSyntax) { Printer << " : protocol<"; PrintedColon = true; } for (auto Proto : protos) { if (Proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) continue; if (auto Enum = dyn_cast(decl)) { // Conformance to RawRepresentable is implied by having a raw type. if (Enum->hasRawType() && Proto->isSpecificProtocol(KnownProtocolKind::RawRepresentable)) continue; // Conformance to Equatable and Hashable is implied by being a "simple" // no-payload enum. if (Enum->isSimpleEnum() && (Proto->isSpecificProtocol(KnownProtocolKind::Equatable) || Proto->isSpecificProtocol(KnownProtocolKind::Hashable))) continue; } if (PrintedInherited) Printer << ", "; else if (!PrintedColon) Printer << " : "; Proto->getDeclaredType()->print(Printer, Options); PrintedInherited = true; PrintedColon = true; } if (UseProtocolCompositionSyntax) Printer << ">"; } else { Printer << " : "; interleave(inherited, [&](TypeLoc TL) { TL.getType()->print(Printer, Options); }, [&]() { Printer << ", "; }); } } template void PrintAST::printInheritedWithSuperclass(DeclWithSuperclass *decl) { printInherited(decl, decl->getInherited(), decl->getProtocols(), decl->getSuperclass()); } void PrintAST::printInherited(const TypeDecl *decl) { printInherited(decl, decl->getInherited(), decl->getProtocols()); } void PrintAST::printInherited(const EnumDecl *D) { printInherited(D, D->getInherited(), D->getProtocols(), D->getRawType()); } void PrintAST::printInherited(const ExtensionDecl *decl) { printInherited(decl, decl->getInherited(), decl->getProtocols()); } void PrintAST::printInherited(const GenericTypeParamDecl *D) { printInherited(D, D->getInherited(), D->getProtocols(), D->getSuperclass(), true); } void PrintAST::visitImportDecl(ImportDecl *decl) { printAttributes(decl); Printer << "import "; switch (decl->getImportKind()) { case ImportKind::Module: break; case ImportKind::Type: Printer << "typealias "; break; case ImportKind::Struct: Printer << "struct "; break; case ImportKind::Class: Printer << "class "; break; case ImportKind::Enum: Printer << "enum "; break; case ImportKind::Protocol: Printer << "protocol "; break; case ImportKind::Var: Printer << "var "; break; case ImportKind::Func: Printer << "func "; break; } recordDeclLoc(decl); interleave(decl->getFullAccessPath(), [&](const ImportDecl::AccessPathElement &Elem) { Printer << Elem.first.str(); }, [&] { Printer << "."; }); } void PrintAST::visitExtensionDecl(ExtensionDecl *decl) { Printer << "extension "; recordDeclLoc(decl); decl->getExtendedType().print(Printer, Options); printInherited(decl); if (Options.TypeDefinitions) { printMembers(decl->getMembers()); } } void PrintAST::visitPatternBindingDecl(PatternBindingDecl *decl) { recordDeclLoc(decl); if (decl->isStatic()) printStaticKeyword(decl->getCorrectStaticSpelling()); // FIXME: We're not printing proper "{ get set }" annotations in pattern // binding decls. As a hack, scan the decl to find out if any of the // variables are immutable, and if so, we print as 'let'. This allows us to // handle the 'let x = 4' case properly at least. bool isMutable = true; decl->getPattern()->forEachVariable([&](VarDecl *V) { if (!V->isSettable(V->getDeclContext())) isMutable = false; }); printAttributes(decl); Printer << (isMutable ? "var " : "let "); printPattern(decl->getPattern()); if (Options.VarInitializers) { // FIXME: Implement once we can pretty-print expressions. } } void PrintAST::visitTopLevelCodeDecl(TopLevelCodeDecl *decl) { printBraceStmtElements(decl->getBody(), /*NeedIndent=*/false); } void PrintAST::visitIfConfigDecl(IfConfigDecl *ICD) { // FIXME: Pretty print #if decls } void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { printDocumentationComment(decl); printAttributes(decl); if (!Options.SkipIntroducerKeywords) Printer << "typealias "; recordDeclLoc(decl); Printer.printName(decl->getName()); if (Options.TypeDefinitions && decl->hasUnderlyingType()) { Printer << " = "; decl->getUnderlyingType().print(Printer, Options); } } void PrintAST::visitGenericTypeParamDecl(GenericTypeParamDecl *decl) { recordDeclLoc(decl); Printer.printName(decl->getName()); printInheritedWithSuperclass(decl); } void PrintAST::visitAssociatedTypeDecl(AssociatedTypeDecl *decl) { printDocumentationComment(decl); printAttributes(decl); if (!Options.SkipIntroducerKeywords) Printer << "typealias "; recordDeclLoc(decl); Printer.printName(decl->getName()); printInheritedWithSuperclass(decl); if (!decl->getDefaultDefinitionLoc().isNull()) { Printer << " = "; decl->getDefaultDefinitionLoc().getType().print(Printer, Options); } } void PrintAST::visitEnumDecl(EnumDecl *decl) { printDocumentationComment(decl); printAttributes(decl); if (!Options.SkipIntroducerKeywords) Printer << "enum "; recordDeclLoc(decl); printNominalDeclName(decl); printInherited(decl); if (Options.TypeDefinitions) { printMembers(decl->getMembers()); } } void PrintAST::visitStructDecl(StructDecl *decl) { printDocumentationComment(decl); printAttributes(decl); if (!Options.SkipIntroducerKeywords) Printer << "struct "; recordDeclLoc(decl); printNominalDeclName(decl); printInherited(decl); if (Options.TypeDefinitions) { printMembers(decl->getMembers()); } } void PrintAST::visitClassDecl(ClassDecl *decl) { printDocumentationComment(decl); printAttributes(decl); if (!Options.SkipIntroducerKeywords) Printer << "class "; recordDeclLoc(decl); printNominalDeclName(decl); printInheritedWithSuperclass(decl); if (Options.TypeDefinitions) { printMembers(decl->getMembers()); } } void PrintAST::visitProtocolDecl(ProtocolDecl *decl) { printDocumentationComment(decl); printAttributes(decl); if (!Options.SkipIntroducerKeywords) Printer << "protocol "; recordDeclLoc(decl); printNominalDeclName(decl); printInherited(decl); if (Options.TypeDefinitions) { printMembers(decl->getMembers()); } } void PrintAST::visitVarDecl(VarDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printOverrideKeyword(decl); if (!Options.SkipIntroducerKeywords) { if (decl->isStatic()) printStaticKeyword(decl->getCorrectStaticSpelling()); Printer << (decl->isLet() ? "let " : "var "); } recordDeclLoc(decl); Printer.printName(decl->getName()); if (decl->hasType()) { Printer << ": "; decl->getType().print(Printer, Options); } printAccessors(decl); } void PrintAST::visitParamDecl(ParamDecl *decl) { return visitVarDecl(decl); } void PrintAST::printOneParameter(Identifier ArgName, const Pattern *BodyPattern, bool ArgNameIsAPIByDefault, bool StripOuterSliceType, bool Curried) { if (auto *VP = dyn_cast(BodyPattern)) BodyPattern = VP->getSubPattern(); auto *TypedBodyPattern = cast(BodyPattern); auto TheTypeLoc = TypedBodyPattern->getTypeLoc(); if (TheTypeLoc.hasLocation()) { // If the outer typeloc is an InOutTypeRepr, print the 'inout' before the // subpattern. if (auto *IOTR = dyn_cast(TheTypeLoc.getTypeRepr())) { TheTypeLoc = TypeLoc(IOTR->getBase()); if (Type T = TheTypeLoc.getType()) { if (auto *IOT = T->getAs()) { TheTypeLoc.setType(IOT->getObjectType()); } } Printer << "inout "; } } else { if (Type T = TheTypeLoc.getType()) { if (auto *IOT = T->getAs()) { Printer << "inout "; TheTypeLoc.setType(IOT->getObjectType()); } } } // Print argument name. auto BodyName = BodyPattern->getBoundName(); if (Curried) { // For curried parameters, just print the body name if there is one. Printer.printName(BodyName); Printer << ": "; } else { auto printArg = [&]{ if (!ArgName.empty() && !ArgNameIsAPIByDefault) Printer << "`"; Printer.printName(ArgName); }; switch (Options.ArgAndParamPrinting) { case PrintOptions::ArgAndParamPrintingMode::ArgumentOnly: printArg(); break; case PrintOptions::ArgAndParamPrintingMode::BothIfDifferent: if (ArgName == BodyName) { printArg(); break; } if (ArgName.empty() && !ArgNameIsAPIByDefault) { Printer.printName(BodyName); break; } SWIFT_FALLTHROUGH; case PrintOptions::ArgAndParamPrintingMode::BothAlways: Printer.printName(ArgName); Printer << " "; Printer.printName(BodyName); break; } Printer << ": "; } if (StripOuterSliceType && !TheTypeLoc.hasLocation()) { if (auto *BGT = TypedBodyPattern->getType()->getAs()) { BGT->getGenericArgs()[0].print(Printer, Options); return; } } printTypeLoc(TheTypeLoc); } void PrintAST::printFunctionParameters(AbstractFunctionDecl *AFD) { ArrayRef ArgNames; DeclName Name = AFD->getFullName(); if (Name) { ArgNames = Name.getArgumentNames(); } ArrayRef BodyPatterns = AFD->getBodyParamPatterns(); // Skip over the implicit 'self'. if (AFD->getImplicitSelfDecl()) { BodyPatterns = BodyPatterns.slice(1); } for (unsigned CurrPattern = 0, NumPatterns = BodyPatterns.size(); CurrPattern != NumPatterns; ++CurrPattern) { bool UseArgName = Name && (CurrPattern == 0); if (auto *BodyTuple = dyn_cast(BodyPatterns[CurrPattern])) { Printer << "("; for (unsigned i = 0, e = BodyTuple->getFields().size(); i != e; ++i) { if (i > 0) Printer << ", "; // Determine whether the argument name is API by default. bool ArgNameIsAPIByDefault = (CurrPattern == 0 && AFD->argumentNameIsAPIByDefault(i)) || (BodyTuple->getFields()[i].getDefaultArgKind() != DefaultArgumentKind::None && Options.PrintDefaultParameterPlaceholder); printOneParameter(UseArgName ? ArgNames[i] : Identifier(), BodyTuple->getFields()[i].getPattern(), ArgNameIsAPIByDefault, /*StripOuterSliceType=*/i == e - 1 && BodyTuple->hasVararg(), /*Curried=*/CurrPattern > 0); if (Options.PrintDefaultParameterPlaceholder && BodyTuple->getFields()[i].getDefaultArgKind() != DefaultArgumentKind::None) Printer << " = default"; } if (BodyTuple->hasVararg()) Printer << "..."; Printer << ")"; continue; } bool ArgNameIsAPIByDefault = (CurrPattern == 0 && AFD->argumentNameIsAPIByDefault(0)); auto *BodyParen = cast(BodyPatterns[CurrPattern]); Printer << "("; printOneParameter(UseArgName? ArgNames[0] : Identifier(), BodyParen->getSubPattern(), ArgNameIsAPIByDefault, /*StripOuterSliceType=*/false, /*Curried=*/CurrPattern > 0); Printer << ")"; } } bool PrintAST::printBraceStmtElements(BraceStmt *stmt, bool NeedIndent) { IndentRAII IndentMore(*this, NeedIndent); bool PrintedSomething = false; for (auto element : stmt->getElements()) { PrintedSomething = true; Printer.printNewline(); indent(); if (auto decl = element.dyn_cast()) { if (decl->shouldPrintInContext(Options)) visit(decl); } else if (auto stmt = element.dyn_cast()) { visit(stmt); } else { // FIXME: print expression // visit(element.get()); } } return PrintedSomething; } void PrintAST::visitFuncDecl(FuncDecl *decl) { if (decl->isAccessor()) { printDocumentationComment(decl); printAttributes(decl); recordDeclLoc(decl); switch (decl->getAccessorKind()) { case AccessorKind::NotAccessor: break; case AccessorKind::IsGetter: Printer << "get {"; break; case AccessorKind::IsDidSet: Printer << "didSet {"; break; case AccessorKind::IsSetter: case AccessorKind::IsWillSet: Printer << (decl->isSetter() ? "set" : "willSet"); auto BodyParams = decl->getBodyParamPatterns(); auto ValueParam = BodyParams.back()->getSemanticsProvidingPattern(); if (auto *TP = dyn_cast(ValueParam)) { if (!TP->isImplicit() && !TP->getFields().empty()) { auto *P = TP->getFields().begin()->getPattern()-> getSemanticsProvidingPattern(); Identifier Name = P->getBoundName(); if (!Name.empty() && !P->isImplicit()) { Printer << "("; Printer.printName(Name); Printer << ")"; } } } Printer << " {"; } if (Options.FunctionDefinitions && decl->getBody()) { if (printBraceStmtElements(decl->getBody())) { Printer.printNewline(); indent(); } } Printer << "}"; } else { printDocumentationComment(decl); printAttributes(decl); printOverrideKeyword(decl); if (decl->isStatic() && !decl->isOperator()) printStaticKeyword(decl->getCorrectStaticSpelling()); if (!Options.SkipIntroducerKeywords) Printer << "func "; recordDeclLoc(decl); if (!decl->hasName()) Printer << ""; else Printer.printName(decl->getName()); if (decl->isGeneric()) { printGenericParams(decl->getGenericParams()); } printFunctionParameters(decl); auto &Context = decl->getASTContext(); Type ResultTy = decl->getResultType(); if (ResultTy && !ResultTy->isEqual(TupleType::getEmpty(Context))) { Printer << " -> "; ResultTy->print(Printer, Options); } if (!Options.FunctionDefinitions || !decl->getBody()) { return; } Printer << " "; visit(decl->getBody()); } } void PrintAST::printEnumElement(EnumElementDecl *elt) { Printer.printName(elt->getName()); if (elt->hasArgumentType()) elt->getArgumentType().print(Printer, Options); } void PrintAST::visitEnumCaseDecl(EnumCaseDecl *decl) { // FIXME: Attributes? recordDeclLoc(decl); Printer << "case "; interleave(decl->getElements().begin(), decl->getElements().end(), [&](EnumElementDecl *elt) { printEnumElement(elt); }, [&] { Printer << ", "; }); } void PrintAST::visitEnumElementDecl(EnumElementDecl *decl) { if (!decl->shouldPrintInContext(Options)) return; // In cases where there is no parent EnumCaseDecl (such as imported or // deserialized elements), print the element independently. Printer << "case "; printEnumElement(decl); } void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) { recordDeclLoc(decl); printAttributes(decl); printOverrideKeyword(decl); Printer << "subscript "; printPattern(decl->getIndices()); Printer << " -> "; decl->getElementType().print(Printer, Options); printAccessors(decl); } void PrintAST::visitConstructorDecl(ConstructorDecl *decl) { printDocumentationComment(decl); recordDeclLoc(decl); printAttributes(decl); if (decl->getInitKind() == CtorInitializerKind::Convenience || decl->getInitKind() == CtorInitializerKind::ConvenienceFactory) Printer << "convenience "; Printer << "init"; if (decl->isGeneric()) printGenericParams(decl->getGenericParams()); printFunctionParameters(decl); if (decl->getInitKind() == CtorInitializerKind::Factory) { Printer << " -> "; Printer.printName(decl->getExtensionType()->getAnyNominal()->getName()); } if (!Options.FunctionDefinitions || !decl->getBody()) { return; } Printer << " "; visit(decl->getBody()); } void PrintAST::visitDestructorDecl(DestructorDecl *decl) { printDocumentationComment(decl); recordDeclLoc(decl); printAttributes(decl); Printer << "deinit "; if (!Options.FunctionDefinitions || !decl->getBody()) { return; } Printer << " "; visit(decl->getBody()); } void PrintAST::visitInfixOperatorDecl(InfixOperatorDecl *decl) { recordDeclLoc(decl); Printer << "operator infix "; Printer.printName(decl->getName()); Printer << " {"; Printer.printNewline(); { IndentRAII indentMore(*this); if (decl->getAssociativityLoc().isValid()) { indent(); Printer << "associativity "; switch (decl->getAssociativity()) { case Associativity::None: Printer << "none"; break; case Associativity::Left: Printer << "left"; break; case Associativity::Right: Printer << "right"; break; } Printer.printNewline(); } if (decl->getPrecedenceLoc().isValid()) { indent(); Printer << "precedence " << decl->getPrecedence(); Printer.printNewline(); } } indent(); Printer << "}"; } void PrintAST::visitPrefixOperatorDecl(PrefixOperatorDecl *decl) { recordDeclLoc(decl); Printer << "operator prefix "; Printer.printName(decl->getName()); Printer << " {"; Printer.printNewline(); Printer << "}"; } void PrintAST::visitPostfixOperatorDecl(PostfixOperatorDecl *decl) { recordDeclLoc(decl); Printer << "operator postfix "; Printer.printName(decl->getName()); Printer << " {"; Printer.printNewline(); Printer << "}"; } void PrintAST::visitBraceStmt(BraceStmt *stmt) { Printer << "{"; printBraceStmtElements(stmt); Printer.printNewline(); indent(); Printer << "}"; } void PrintAST::visitReturnStmt(ReturnStmt *stmt) { Printer << "return"; if (stmt->hasResult()) { Printer << " "; // FIXME: print expression. } } void PrintAST::visitIfStmt(IfStmt *stmt) { Printer << "if "; // FIXME: print condition Printer << " "; visit(stmt->getThenStmt()); if (auto elseStmt = stmt->getElseStmt()) { Printer << " else "; visit(elseStmt); } } void PrintAST::visitIfConfigStmt(IfConfigStmt *stmt) { for (auto &Clause : stmt->getClauses()) { if (&Clause == &*stmt->getClauses().begin()) Printer << "#if "; // FIXME: print condition else if (Clause.Cond) Printer << "#elseif"; // FIXME: print condition else Printer << "#else"; Printer.printNewline(); visit(Clause.Body); } Printer.printNewline(); Printer << "#endif"; } void PrintAST::visitWhileStmt(WhileStmt *stmt) { Printer << "while "; // FIXME: print condition Printer << " "; visit(stmt->getBody()); } void PrintAST::visitDoWhileStmt(DoWhileStmt *stmt) { Printer << "do "; visit(stmt->getBody()); Printer << " while "; // FIXME: print condition } void PrintAST::visitForStmt(ForStmt *stmt) { Printer << "for ("; // FIXME: print initializer Printer << "; "; if (stmt->getCond().isNonNull()) { // FIXME: print cond } Printer << "; "; // FIXME: print increment Printer << ") "; visit(stmt->getBody()); } void PrintAST::visitForEachStmt(ForEachStmt *stmt) { Printer << "for "; printPattern(stmt->getPattern()); Printer << " in "; // FIXME: print container Printer << " "; visit(stmt->getBody()); } void PrintAST::visitBreakStmt(BreakStmt *stmt) { Printer << "break"; } void PrintAST::visitContinueStmt(ContinueStmt *stmt) { Printer << "continue"; } void PrintAST::visitFallthroughStmt(FallthroughStmt *stmt) { Printer << "fallthrough"; } void PrintAST::visitSwitchStmt(SwitchStmt *stmt) { Printer << "switch "; // FIXME: print subject Printer << "{"; Printer.printNewline(); for (CaseStmt *C : stmt->getCases()) { visit(C); } Printer.printNewline(); indent(); Printer << "}"; } void PrintAST::visitCaseStmt(CaseStmt *CS) { if (CS->isDefault()) { Printer << "default"; } else { auto PrintCaseLabelItem = [&](const CaseLabelItem &CLI) { if (auto *P = CLI.getPattern()) printPattern(P); if (CLI.getGuardExpr()) { Printer << " where "; // FIXME: print guard expr } }; Printer << "case "; interleave(CS->getCaseLabelItems(), PrintCaseLabelItem, [&] { Printer << ", "; }); } Printer << ":"; Printer.printNewline(); printBraceStmtElements(cast(CS->getBody())); } void Decl::print(raw_ostream &os) const { PrintOptions options; options.FunctionDefinitions = true; options.TypeDefinitions = true; options.VarInitializers = true; print(os, options); } void Decl::print(raw_ostream &OS, const PrintOptions &Opts) const { StreamPrinter Printer(OS); print(Printer, Opts); } bool Decl::print(ASTPrinter &Printer, const PrintOptions &Opts) const { PrintAST printer(Printer, Opts); return printer.visit(const_cast(this)); } bool Decl::shouldPrintInContext(const PrintOptions &PO) const { // Skip getters/setters. They are part of the variable or subscript. if (isa(this) && cast(this)->isAccessor()) return false; if (PO.ExplodePatternBindingDecls) { if (isa(this)) return true; if (isa(this)) return false; } else { // Try to preserve the PatternBindingDecl structure. // Skip stored variables, unless they came from a Clang module. // Stored variables in Swift source will be picked up by the // PatternBindingDecl. if (auto *VD = dyn_cast(this)) { if (!VD->hasClangNode() && VD->hasStorage() && VD->getStorageKind() != VarDecl::Observing) return false; } // Skip pattern bindings that consist of just one computed variable. if (auto pbd = dyn_cast(this)) { auto pattern = pbd->getPattern()->getSemanticsProvidingPattern(); if (auto named = dyn_cast(pattern)) { auto StorageKind = named->getDecl()->getStorageKind(); if (StorageKind == VarDecl::Computed || StorageKind == VarDecl::Observing) return false; } } } if (auto EED = dyn_cast(this)) { // Enum elements are printed as part of the EnumCaseDecl, unless they were // imported without source info. return !EED->getSourceRange().isValid(); } // Print everything else. return true; } void Pattern::print(llvm::raw_ostream &OS, const PrintOptions &Options) const { StreamPrinter StreamPrinter(OS); PrintAST Printer(StreamPrinter, Options); Printer.printPattern(this); } //===----------------------------------------------------------------------===// // Type Printing //===----------------------------------------------------------------------===// namespace { class TypePrinter : public TypeVisitor { ASTPrinter &Printer; const PrintOptions &Options; Optional> UnwrappedGenericParams; void printDeclContext(DeclContext *DC) { switch (DC->getContextKind()) { case DeclContextKind::Module: { Module *M = cast(DC); if (auto Parent = M->getParent()) printDeclContext(Parent); Printer.printModuleRef(M, M->Name); return; } case DeclContextKind::FileUnit: printDeclContext(DC->getParent()); return; case DeclContextKind::AbstractClosureExpr: // FIXME: print closures somehow. return; case DeclContextKind::NominalTypeDecl: visit(cast(DC)->getType()); return; case DeclContextKind::ExtensionDecl: visit(cast(DC)->getExtendedType()); return; case DeclContextKind::Initializer: case DeclContextKind::TopLevelCodeDecl: llvm_unreachable("bad decl context"); case DeclContextKind::AbstractFunctionDecl: visit(cast(DC)->getType()); return; } } void printGenericArgs(ArrayRef Args) { if (Args.empty()) return; Printer << "<"; bool First = true; for (Type Arg : Args) { if (First) First = false; else Printer << ", "; visit(Arg); } Printer << ">"; } static bool isSimple(Type type) { switch (type->getKind()) { case TypeKind::ArraySlice: case TypeKind::Function: case TypeKind::PolymorphicFunction: case TypeKind::GenericFunction: case TypeKind::ImplicitlyUnwrappedOptional: return false; case TypeKind::Metatype: case TypeKind::ExistentialMetatype: return !cast(type.getPointer())->hasRepresentation(); default: return true; } } /// Helper function for printing a type that is embedded within a larger type. /// /// This is necessary whenever the inner type may not normally be represented /// as a 'type-simple' production in the type grammar. void printWithParensIfNotSimple(Type T) { if (T.isNull()) { visit(T); return; } if (!isSimple(T)) { Printer << "("; visit(T); Printer << ")"; } else { visit(T); } } void printGenericParams(GenericParamList *Params) { PrintAST(Printer, Options).printGenericParams(Params); } template void printModuleContext(T *Ty) { Module *Mod = Ty->getDecl()->getModuleContext(); Printer.printModuleRef(Mod, Mod->Name); Printer << "."; } template void printTypeDeclName(T *Ty) { TypeDecl *TD = Ty->getDecl(); Printer.printTypeRef(TD, TD->getName()); } bool shouldPrintFullyQualified(TypeBase *T) { if (Options.FullyQualifiedTypes) return true; if (!Options.FullyQualifiedTypesIfAmbiguous) return false; Decl *D = nullptr; if (auto *NAT = dyn_cast(T)) D = NAT->getDecl(); else D = T->getAnyNominal(); // If we can not find the declaration, be extra careful and print // the type qualified. if (!D) return true; Module *M = D->getDeclContext()->getParentModule(); // Don't print qualifiers for types from the standard library. if (M->isStdlibModule() || M->Name == T->getASTContext().ObjCModuleName) return false; // Don't print qualifiers for imported types. for (auto File : M->getFiles()) { if (File->getKind() == FileUnitKind::ClangModule) return false; } return true; } public: TypePrinter(ASTPrinter &Printer, const PrintOptions &PO) : Printer(Printer), Options(PO) {} void visitErrorType(ErrorType *T) { Printer << "<>"; } void visitBuiltinRawPointerType(BuiltinRawPointerType *T) { Printer << "Builtin.RawPointer"; } void visitBuiltinNativeObjectType(BuiltinNativeObjectType *T) { Printer << "Builtin.NativeObject"; } void visitBuiltinUnknownObjectType(BuiltinUnknownObjectType *T) { Printer << "Builtin.UnknownObject"; } void visitBuiltinVectorType(BuiltinVectorType *T) { llvm::SmallString<32> UnderlyingStrVec; StringRef UnderlyingStr; { // FIXME: Ugly hack: remove the .Builtin from the element type. llvm::raw_svector_ostream UnderlyingOS(UnderlyingStrVec); visit(T->getElementType()); if (UnderlyingStrVec.startswith("Builtin.")) UnderlyingStr = UnderlyingStrVec.substr(9); else UnderlyingStr = UnderlyingStrVec; } Printer << "Builtin.Vec" << T->getNumElements() << "x" << UnderlyingStr; } void visitBuiltinIntegerType(BuiltinIntegerType *T) { auto width = T->getWidth(); if (width.isFixedWidth()) { Printer << "Builtin.Int" << width.getFixedWidth(); } else if (width.isPointerWidth()) { Printer << "Builtin.Word"; } else { llvm_unreachable("impossible bit width"); } } void visitBuiltinFloatType(BuiltinFloatType *T) { switch (T->getFPKind()) { case BuiltinFloatType::IEEE16: Printer << "Builtin.FPIEEE16"; return; case BuiltinFloatType::IEEE32: Printer << "Builtin.FPIEEE32"; return; case BuiltinFloatType::IEEE64: Printer << "Builtin.FPIEEE64"; return; case BuiltinFloatType::IEEE80: Printer << "Builtin.FPIEEE80"; return; case BuiltinFloatType::IEEE128: Printer << "Builtin.FPIEEE128"; return; case BuiltinFloatType::PPC128: Printer << "Builtin.FPPPC128"; return; } } void visitNameAliasType(NameAliasType *T) { if (shouldPrintFullyQualified(T)) { if (auto ParentDC = T->getDecl()->getDeclContext()) { printDeclContext(ParentDC); Printer << "."; } } printTypeDeclName(T); } void visitParenType(ParenType *T) { Printer << "("; visit(T->getUnderlyingType()); Printer << ")"; } void visitTupleType(TupleType *T) { Printer << "("; auto Fields = T->getFields(); for (unsigned i = 0, e = Fields.size(); i != e; ++i) { if (i) Printer << ", "; const TupleTypeElt &TD = Fields[i]; Type EltType = TD.getType(); if (auto *IOT = EltType->getAs()) { Printer << "inout "; EltType = IOT->getObjectType(); } if (TD.hasName()) { Printer.printName(TD.getName()); Printer << ": "; } if (TD.isVararg()) { visit(TD.getVarargBaseTy()); Printer << "..."; } else visit(EltType); } Printer << ")"; } void visitUnboundGenericType(UnboundGenericType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); } void visitBoundGenericType(BoundGenericType *T) { if (Options.SynthesizeSugarOnTypes) { auto *NT = T->getDecl(); auto &Ctx = T->getASTContext(); if (NT == Ctx.getArrayDecl()) { printWithParensIfNotSimple(T->getGenericArgs()[0]); Printer << "[]"; return; } if (NT == Ctx.getOptionalDecl()) { printWithParensIfNotSimple(T->getGenericArgs()[0]); Printer << "?"; return; } if (NT == Ctx.getImplicitlyUnwrappedOptionalDecl()) { printWithParensIfNotSimple(T->getGenericArgs()[0]); Printer << "!"; return; } } if (auto ParentType = T->getParent()) { visit(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); printGenericArgs(T->getGenericArgs()); } void visitEnumType(EnumType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); } void visitStructType(StructType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); } void visitClassType(ClassType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); } void visitAnyMetatypeType(AnyMetatypeType *T) { if (T->hasRepresentation()) { switch (T->getRepresentation()) { case MetatypeRepresentation::Thin: Printer << "@thin "; break; case MetatypeRepresentation::Thick: Printer << "@thick "; break; case MetatypeRepresentation::ObjC: Printer << "@objc_metatype "; break; } } printWithParensIfNotSimple(T->getInstanceType()); // We spell normal metatypes of existential types as .Protocol. if (isa(T) && T->getInstanceType()->isAnyExistentialType()) { Printer << ".Protocol"; } else { Printer << ".Type"; } } void visitModuleType(ModuleType *T) { Printer << "module<"; Printer.printModuleRef(T->getModule(), T->getModule()->Name); Printer << ">"; } void visitDynamicSelfType(DynamicSelfType *T) { Printer << "Self"; } void printFunctionExtInfo(AnyFunctionType::ExtInfo info) { if (info.isAutoClosure()) Printer << "@auto_closure "; switch (info.getCC()) { case AbstractCC::Freestanding: break; case AbstractCC::Method: Printer << "@cc(method) "; break; case AbstractCC::C: Printer << "@cc(cdecl) "; break; case AbstractCC::ObjCMethod: Printer << "@cc(objc_method) "; break; case AbstractCC::WitnessMethod: Printer << "@cc(witness_method) "; break; } if (Options.PrintFunctionRepresentationAttrs) { switch (info.getRepresentation()) { case AnyFunctionType::Representation::Thick: break; case AnyFunctionType::Representation::Thin: Printer << "@thin "; break; case AnyFunctionType::Representation::Block: Printer << "@objc_block "; break; } } if (info.isNoReturn()) Printer << "@noreturn "; } void visitFunctionType(FunctionType *T) { printFunctionExtInfo(T->getExtInfo()); printWithParensIfNotSimple(T->getInput()); Printer << " -> "; T->getResult().print(Printer, Options); } void visitPolymorphicFunctionType(PolymorphicFunctionType *T) { printFunctionExtInfo(T->getExtInfo()); printGenericParams(&T->getGenericParams()); Printer << " "; printWithParensIfNotSimple(T->getInput()); Printer << " -> "; T->getResult().print(Printer, Options); } void printGenericSignature(ArrayRef genericParams, ArrayRef requirements) { // Print the generic parameters. Printer << "<"; bool isFirstParam = true; for (auto param : genericParams) { if (isFirstParam) isFirstParam = false; else Printer << ", "; visit(param); } // Print the requirements. bool isFirstReq = true; for (const auto &req : requirements) { if (req.getKind() == RequirementKind::WitnessMarker) continue; if (isFirstReq) { Printer << " where "; isFirstReq = false; } else { Printer << ", "; } visit(req.getFirstType()); switch (req.getKind()) { case RequirementKind::Conformance: Printer << " : "; break; case RequirementKind::SameType: Printer << " == "; break; case RequirementKind::WitnessMarker: llvm_unreachable("Handled above"); } visit(req.getSecondType()); } Printer << ">"; } void visitGenericFunctionType(GenericFunctionType *T) { printFunctionExtInfo(T->getExtInfo()); printGenericSignature(T->getGenericParams(), T->getRequirements()); Printer << " "; printWithParensIfNotSimple(T->getInput()); Printer << " -> "; T->getResult().print(Printer, Options); } void printCalleeConvention(ParameterConvention conv) { switch (conv) { case ParameterConvention::Direct_Unowned: return; case ParameterConvention::Direct_Owned: Printer << "@callee_owned "; return; case ParameterConvention::Direct_Guaranteed: Printer << "@callee_guaranteed "; return; case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_Out: case ParameterConvention::Indirect_Inout: llvm_unreachable("callee convention cannot be indirect"); } llvm_unreachable("bad convention"); } void visitSILFunctionType(SILFunctionType *T) { printFunctionExtInfo(T->getExtInfo()); printCalleeConvention(T->getCalleeConvention()); if (auto sig = T->getGenericSignature()) { printGenericSignature(sig->getGenericParams(), sig->getRequirements()); Printer << " "; } Printer << "("; bool first = true; for (auto param : T->getInterfaceParameters()) { if (first) { first = false; } else { Printer << ", "; } param.print(Printer, Options); } Printer << ") -> "; T->getInterfaceResult().print(Printer, Options); } void visitSILBlockStorageType(SILBlockStorageType *T) { Printer << "@block_storage "; printWithParensIfNotSimple(T->getCaptureType()); } void visitArraySliceType(ArraySliceType *T) { printWithParensIfNotSimple(T->getBaseType()); Printer << "[]"; } void visitOptionalType(OptionalType *T) { printWithParensIfNotSimple(T->getBaseType()); Printer << "?"; } void visitImplicitlyUnwrappedOptionalType(ImplicitlyUnwrappedOptionalType *T) { printWithParensIfNotSimple(T->getBaseType()); Printer << "!"; } void visitProtocolType(ProtocolType *T) { printTypeDeclName(T); } void visitProtocolCompositionType(ProtocolCompositionType *T) { Printer << "protocol<"; bool First = true; for (auto Proto : T->getProtocols()) { if (First) First = false; else Printer << ", "; visit(Proto); } Printer << ">"; } void visitLValueType(LValueType *T) { Printer << "@lvalue "; visit(T->getObjectType()); } void visitInOutType(InOutType *T) { Printer << "inout "; visit(T->getObjectType()); } void visitArchetypeType(ArchetypeType *T) { if (auto existentialTy = T->getOpenedExistentialType()) { Printer << "@opened(" << T->getOpenedExistentialID() << ") "; visit(existentialTy); } else { Printer << T->getFullName(); } } GenericParamList *getGenericParamListAtDepth(unsigned depth) { assert(Options.ContextGenericParams); auto ¶mLists = UnwrappedGenericParams.cache([&]{ std::vector paramLists; for (auto *params = Options.ContextGenericParams; params; params = params->getOuterParameters()) { paramLists.push_back(params); } return paramLists; }); return paramLists.rbegin()[depth]; } void visitGenericTypeParamType(GenericTypeParamType *T) { // Substitute a context archetype if we have context generic params. if (Options.ContextGenericParams) { return visit(getGenericParamListAtDepth(T->getDepth()) ->getPrimaryArchetypes()[T->getIndex()]); } auto Name = T->getName(); if (Name.empty()) Printer << ""; else Printer.printName(Name); } void visitAssociatedTypeType(AssociatedTypeType *T) { auto Name = T->getDecl()->getName(); if (Name.empty()) Printer << ""; else Printer.printName(Name); } void visitSubstitutedType(SubstitutedType *T) { visit(T->getReplacementType()); } void visitDependentMemberType(DependentMemberType *T) { visit(T->getBase()); Printer << "."; Printer.printName(T->getName()); } void visitUnownedStorageType(UnownedStorageType *T) { Printer << "@sil_unowned "; visit(T->getReferentType()); } void visitUnmanagedStorageType(UnmanagedStorageType *T) { Printer << "@sil_unmanaged "; visit(T->getReferentType()); } void visitWeakStorageType(WeakStorageType *T) { Printer << "@sil_weak "; visit(T->getReferentType()); } void visitTypeVariableType(TypeVariableType *T) { Printer << "$T" << T->getID(); } }; } // unnamed namespace void Type::dump() const { print(llvm::errs()); llvm::errs() << '\n'; } void Type::print(raw_ostream &OS, const PrintOptions &PO) const { StreamPrinter Printer(OS); print(Printer, PO); } void Type::print(ASTPrinter &Printer, const PrintOptions &PO) const { if (isNull()) Printer << ""; else TypePrinter(Printer, PO).visit(*this); } void GenericSignature::print(raw_ostream &OS) const { StreamPrinter Printer(OS); TypePrinter(Printer, PrintOptions()) .printGenericSignature(getGenericParams(), getRequirements()); } void GenericSignature::dump() const { print(llvm::errs()); llvm::errs() << '\n'; } static StringRef getStringForParameterConvention(ParameterConvention conv) { switch (conv) { case ParameterConvention::Indirect_In: return "@in "; case ParameterConvention::Indirect_Out: return "@out "; case ParameterConvention::Indirect_Inout: return "@inout "; case ParameterConvention::Direct_Owned: return "@owned "; case ParameterConvention::Direct_Unowned: return ""; case ParameterConvention::Direct_Guaranteed: return "@guaranteed "; } llvm_unreachable("bad parameter convention"); } StringRef swift::getCheckedCastKindName(CheckedCastKind kind) { switch (kind) { case CheckedCastKind::Unresolved: return "unresolved"; case CheckedCastKind::Coercion: return "coercion"; case CheckedCastKind::Downcast: return "downcast"; case CheckedCastKind::SuperToArchetype: return "super_to_archetype"; case CheckedCastKind::ArchetypeToArchetype: return "archetype_to_archetype"; case CheckedCastKind::ArchetypeToConcrete: return "archetype_to_concrete"; case CheckedCastKind::ExistentialToArchetype: return "existential_to_archetype"; case CheckedCastKind::ExistentialToConcrete: return "existential_to_concrete"; case CheckedCastKind::ConcreteToArchetype: return "concrete_to_archetype"; case CheckedCastKind::ConcreteToUnrelatedExistential: return "concrete_to_unrelated_existential"; } llvm_unreachable("bad checked cast name"); } void SILParameterInfo::dump() const { print(llvm::errs()); llvm::errs() << '\n'; } void SILParameterInfo::print(raw_ostream &OS, const PrintOptions &Opts) const { StreamPrinter Printer(OS); print(Printer, Opts); } void SILParameterInfo::print(ASTPrinter &Printer, const PrintOptions &Opts) const { Printer << getStringForParameterConvention(getConvention()); getType().print(Printer, Opts); } static StringRef getStringForResultConvention(ResultConvention conv) { switch (conv) { case ResultConvention::Owned: return "@owned "; case ResultConvention::Unowned: return ""; case ResultConvention::UnownedInnerPointer: return "@unowned_inner_pointer "; case ResultConvention::Autoreleased: return "@autoreleased "; } llvm_unreachable("bad result convention"); } void SILResultInfo::dump() const { print(llvm::errs()); llvm::errs() << '\n'; } void SILResultInfo::print(raw_ostream &OS, const PrintOptions &Opts) const { StreamPrinter Printer(OS); print(Printer, Opts); } void SILResultInfo::print(ASTPrinter &Printer, const PrintOptions &Opts) const { Printer << getStringForResultConvention(getConvention()); getType().print(Printer, Opts); } std::string Type::getString(const PrintOptions &PO) const { std::string Result; llvm::raw_string_ostream OS(Result); print(OS, PO); return OS.str(); } std::string TypeBase::getString(const PrintOptions &PO) const { std::string Result; llvm::raw_string_ostream OS(Result); print(OS, PO); return OS.str(); } void TypeBase::dump() const { print(llvm::errs()); llvm::errs() << '\n'; } void TypeBase::print(raw_ostream &OS, const PrintOptions &PO) const { Type(const_cast(this)).print(OS, PO); } void TypeBase::print(ASTPrinter &Printer, const PrintOptions &PO) const { Type(const_cast(this)).print(Printer, PO); }