//===--- 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/ASTContext.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/PrintOptions.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeVisitor.h" #include "swift/AST/Types.h" #include "swift/Basic/STLExtras.h" #include "llvm/Support/raw_ostream.h" using namespace swift; namespace { /// \brief AST pretty-printer. class PrintAST : public ASTVisitor { raw_ostream &OS; const PrintOptions &Options; SmallVectorImpl> *DeclOffsets; 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() { OS.indent(IndentLevel); } /// \brief Record the location of this declaration, which is about to /// be printed. void recordDeclLoc(Decl *decl) { if (DeclOffsets) DeclOffsets->push_back({decl, OS.tell()}); } void printImplicitObjCNote(Decl *D) { if (Options.SkipImplicit) return; if (D->getAttrs().isObjC()) return; auto *VD = dyn_cast(D); if (!VD) return; if (!VD->isObjC()) return; OS << "/* @objc(inferred) */ "; } 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(OS); return; } TL.getType().print(OS, Options); } void printAttributes(const DeclAttributes &attrs); void printTypedPattern(const TypedPattern *TP, bool StripOuterSliceType = false); public: void printPattern(const Pattern *pattern); void printGenericParams(GenericParamList *params); private: void printMembers(ArrayRef 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 printBraceStmtElements(BraceStmt *stmt, bool NeedIndent = true); /// \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(raw_ostream &os, const PrintOptions &options, SmallVectorImpl> *declOffsets) : OS(os), Options(options), DeclOffsets(declOffsets) { } }; } // unnamed namespace void PrintAST::printAttributes(const DeclAttributes &Attrs) { if (Attrs.empty()) return; if (Attrs.isAssignment()) OS << "@assignment "; if (Attrs.isConversion()) OS << "@conversion "; if (Attrs.isTransparent()) OS << "@transparent "; if (Attrs.isInfix()) OS << "@infix "; switch (Attrs.getResilienceKind()) { case Resilience::Default: break; case Resilience::Fragile: OS << "@fragile "; break; case Resilience::InherentlyFragile: OS << "@born_fragile "; break; case Resilience::Resilient: OS << "@resilient "; break; } if (Attrs.isNoReturn()) OS << "@noreturn "; if (!Attrs.AsmName.empty()) OS << "@asmname=\"" << Attrs.AsmName << "\" "; if (Attrs.isPostfix()) OS << "@postfix "; if (Attrs.isObjC()) OS << "@objc "; if (Attrs.isIBOutlet()) OS << "@iboutlet "; if (Attrs.isIBAction()) OS << "@ibaction "; if (Attrs.isClassProtocol()) OS << "@class_protocol "; if (Attrs.isExported()) OS << "@exported "; if (Attrs.isOptional()) OS << "@optional "; } void PrintAST::printTypedPattern(const TypedPattern *TP, bool StripOuterSliceType) { printPattern(TP->getSubPattern()); OS << ": "; if (StripOuterSliceType) { Type T = TP->getType(); if (auto *BGT = T->getAs()) { BGT->getGenericArgs()[0].print(OS, Options); return; } } printTypeLoc(TP->getTypeLoc()); } void PrintAST::printPattern(const Pattern *pattern) { switch (pattern->getKind()) { case PatternKind::Any: OS << "_"; break; case PatternKind::Named: { auto named = cast(pattern); recordDeclLoc(named->getDecl()); printImplicitObjCNote(named->getDecl()); OS << named->getBoundName(); break; } case PatternKind::Paren: OS << "("; printPattern(cast(pattern)->getSubPattern()); OS << ")"; break; case PatternKind::Tuple: { OS << "("; 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) OS << ", "; if (i == e - 1 && TP->hasVararg()) { printTypedPattern(cast(Elt.getPattern()), /*StripOuterSliceType=*/true); } else { printPattern(Elt.getPattern()); } if (Options.VarInitializers && Elt.getInit()) { // FIXME: Print initializer here. } } if (TP->hasVararg()) OS << "..."; OS << ")"; break; } case PatternKind::Typed: printTypedPattern(cast(pattern)); break; case PatternKind::Isa: { auto isa = cast(pattern); OS << "is "; isa->getCastTypeLoc().getType().print(OS); break; } case PatternKind::NominalType: { auto type = cast(pattern); OS << type->getCastTypeLoc().getType() << '('; interleave(type->getElements().begin(), type->getElements().end(), [&](const NominalTypePattern::Element &elt) { OS << elt.getPropertyName().str() << ':'; printPattern(elt.getSubPattern()); }, [&] { OS << ", "; }); 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: { auto var = cast(pattern); OS << "var "; printPattern(var->getSubPattern()); } } } void PrintAST::printGenericParams(GenericParamList *Params) { if (!Params) return; OS << "<"; bool IsFirst = true; for (auto GP : Params->getParams()) { if (IsFirst) { IsFirst = false; } else { OS << ", "; } auto TypeParam = GP.getAsTypeParam(); OS << TypeParam->getName().str(); printInherited(TypeParam); } auto Requirements = Params->getRequirements(); if (!Requirements.empty()) { bool IsFirst = true; for (auto &Req : Requirements) { if (Req.isInvalid() || Req.getKind() == RequirementKind::ValueWitnessMarker) continue; if (IsFirst) { OS << " where "; IsFirst = false; } else { OS << ", "; } switch (Req.getKind()) { case RequirementKind::Conformance: printTypeLoc(Req.getSubjectLoc()); OS << " : "; printTypeLoc(Req.getConstraintLoc()); break; case RequirementKind::SameType: printTypeLoc(Req.getFirstTypeLoc()); OS << " == "; printTypeLoc(Req.getSecondTypeLoc()); break; case RequirementKind::ValueWitnessMarker: llvm_unreachable("Handled above"); } } } OS << ">"; } void PrintAST::printMembers(ArrayRef members, bool needComma) { OS << " {\n"; { IndentRAII indentMore(*this); for (auto member : members) { if (!member->shouldPrintInContext()) continue; if (Options.SkipImplicit && member->isImplicit()) continue; indent(); visit(member); if (needComma && member != members.back()) OS << ","; OS << "\n"; } } indent(); OS << "}"; } void PrintAST::printNominalDeclName(NominalTypeDecl *decl) { OS << 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 DynamicLookup protocol, nothing to print. if (protos.size() == 1) { if (protos.front()->isSpecificProtocol(KnownProtocolKind::DynamicLookup)) return; } } OS << " : "; if (inherited.empty()) { bool PrintedInherited = false; if (superclass) { superclass.print(OS); PrintedInherited = true; } bool UseProtocolCompositionSyntax = PrintAsProtocolComposition && protos.size() > 1; if (UseProtocolCompositionSyntax) OS << "protocol<"; for (auto Proto : protos) { if (Proto->isSpecificProtocol(KnownProtocolKind::DynamicLookup)) continue; if (isa(decl) && cast(decl)->hasRawType() && Proto->isSpecificProtocol(KnownProtocolKind::RawRepresentable)) continue; if (PrintedInherited) OS << ", "; Proto->getDeclaredType()->print(OS); PrintedInherited = true; } if (UseProtocolCompositionSyntax) OS << ">"; } else { interleave(inherited, [&](TypeLoc TL) { TL.getType()->print(OS); }, [&]() { OS << ", "; }); } } 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) { if (decl->isExported()) OS << "@exported "; OS << "import "; switch (decl->getImportKind()) { case ImportKind::Module: break; case ImportKind::Type: OS << "typealias "; break; case ImportKind::Struct: OS << "struct "; break; case ImportKind::Class: OS << "class "; break; case ImportKind::Enum: OS << "enum "; break; case ImportKind::Protocol: OS << "protocol "; break; case ImportKind::Var: OS << "var "; break; case ImportKind::Func: OS << "def "; break; } recordDeclLoc(decl); interleave(decl->getFullAccessPath(), [&](const ImportDecl::AccessPathElement &Elem) { OS << Elem.first; }, [&] { OS << '.'; }); } void PrintAST::visitExtensionDecl(ExtensionDecl *decl) { OS << "extension "; recordDeclLoc(decl); decl->getExtendedType().print(OS); printInherited(decl); if (Options.TypeDefinitions) { printMembers(decl->getMembers()); } } void PrintAST::visitPatternBindingDecl(PatternBindingDecl *decl) { recordDeclLoc(decl); if (decl->isStatic()) OS << "static "; OS << "var "; 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::visitTypeAliasDecl(TypeAliasDecl *decl) { printAttributes(decl->getAttrs()); OS << "typealias "; recordDeclLoc(decl); OS << decl->getName().str(); printInherited(decl); if (Options.TypeDefinitions && decl->hasUnderlyingType()) { OS << " = "; decl->getUnderlyingType().print(OS); } } void PrintAST::visitGenericTypeParamDecl(GenericTypeParamDecl *decl) { recordDeclLoc(decl); OS << decl->getName().str(); printInheritedWithSuperclass(decl); } void PrintAST::visitAssociatedTypeDecl(AssociatedTypeDecl *decl) { printAttributes(decl->getAttrs()); OS << "typealias "; recordDeclLoc(decl); OS << decl->getName().str(); printInheritedWithSuperclass(decl); } void PrintAST::visitEnumDecl(EnumDecl *decl) { printAttributes(decl->getAttrs()); OS << "enum "; recordDeclLoc(decl); printNominalDeclName(decl); printInherited(decl); if (Options.TypeDefinitions) { printMembers(decl->getMembers()); } } void PrintAST::visitStructDecl(StructDecl *decl) { printAttributes(decl->getAttrs()); OS << "struct "; recordDeclLoc(decl); printNominalDeclName(decl); printInherited(decl); if (Options.TypeDefinitions) { printMembers(decl->getMembers()); } } void PrintAST::visitClassDecl(ClassDecl *decl) { printAttributes(decl->getAttrs()); printImplicitObjCNote(decl); OS << "class "; recordDeclLoc(decl); printNominalDeclName(decl); printInheritedWithSuperclass(decl); if (Options.TypeDefinitions) { printMembers(decl->getMembers()); } } void PrintAST::visitProtocolDecl(ProtocolDecl *decl) { printAttributes(decl->getAttrs()); printImplicitObjCNote(decl); OS << "protocol "; recordDeclLoc(decl); printNominalDeclName(decl); printInherited(decl); if (Options.TypeDefinitions) { printMembers(decl->getMembers()); } } void PrintAST::visitVarDecl(VarDecl *decl) { printAttributes(decl->getAttrs()); printImplicitObjCNote(decl); OS << "var "; recordDeclLoc(decl); OS << decl->getName().str(); if (decl->hasType()) { OS << ": "; decl->getType().print(OS); } if (decl->isComputed() && Options.FunctionDefinitions) { OS << " {"; { if (auto getter = decl->getGetter()) { OS << "\n"; indent(); visit(getter); OS << "\n"; } if (auto setter = decl->getSetter()) { OS << "\n"; indent(); visit(setter); OS << "\n"; } } indent(); OS << "}"; } } void PrintAST::printFunctionParameters(AbstractFunctionDecl *AFD) { ArrayRef ArgPatterns = AFD->getArgParamPatterns(); ArrayRef BodyPatterns = AFD->getBodyParamPatterns(); // Skip over the implicit 'self'. if (AFD->getImplicitSelfDecl() && isa(AFD)) { ArgPatterns = ArgPatterns.slice(1); BodyPatterns = BodyPatterns.slice(1); } if (!AFD->hasSelectorStyleSignature()) { for (auto Pat : ArgPatterns) { printPattern(Pat); } return; } auto ArgTuple = cast(ArgPatterns[0]); auto BodyTuple = cast(BodyPatterns[0]); // Print in selector style. for (unsigned i = 0, e = ArgTuple->getFields().size(); i != e; ++i) { if (isa(AFD) || (isa(AFD) && i != 0)) { OS << ' '; auto ArgName = ArgTuple->getFields()[i].getPattern()->getBoundName(); if (ArgName.empty()) OS << '_'; else OS << ArgName.str(); } OS << '('; printPattern(BodyTuple->getFields()[i].getPattern()); OS << ')'; } } void PrintAST::printBraceStmtElements(BraceStmt *stmt, bool NeedIndent) { IndentRAII IndentMore(*this, NeedIndent); for (auto element : stmt->getElements()) { OS << "\n"; indent(); if (auto decl = element.dyn_cast()) { if (decl->shouldPrintInContext()) visit(decl); } else if (auto stmt = element.dyn_cast()) { visit(stmt); } else { // FIXME: print expression // visit(element.get()); } } } void PrintAST::visitFuncDecl(FuncDecl *decl) { if (decl->isGetterOrSetter()) { // FIXME: Attributes printImplicitObjCNote(decl); recordDeclLoc(decl); if (decl->getGetterDecl()) { OS << "get:"; } else { OS << "set"; auto BodyParams = decl->getBodyParamPatterns(); auto ValueParam = BodyParams.back()->getSemanticsProvidingPattern(); if (auto *TP = dyn_cast(ValueParam)) { if (!TP->isImplicit()) { for (auto &Elt : TP->getFields()) { Identifier Name = Elt.getPattern()->getBoundName(); if (!Name.empty()) OS << "(" << Name.str() << ")"; } } } OS << ":"; } if (!Options.FunctionDefinitions || !decl->getBody()) { return; } printBraceStmtElements(decl->getBody()); } else { printAttributes(decl->getAttrs()); printImplicitObjCNote(decl); if (decl->isStatic() && !decl->isOperator()) OS << "static "; OS << "def "; recordDeclLoc(decl); if (decl->getName().empty()) OS << ""; else OS << decl->getName().str(); if (decl->isGeneric()) { printGenericParams(decl->getGenericParams()); } printFunctionParameters(decl); auto &Context = decl->getASTContext(); Type ResultTy = decl->getResultType(); if (ResultTy && !ResultTy->isEqual(TupleType::getEmpty(Context))) { OS << " -> "; ResultTy->print(OS); } if (!Options.FunctionDefinitions || !decl->getBody()) { return; } OS << " "; visit(decl->getBody()); } } static void printEnumElement(raw_ostream &OS, EnumElementDecl *elt) { OS << elt->getName(); if (elt->hasArgumentType()) elt->getArgumentType().print(OS); } void PrintAST::visitEnumCaseDecl(EnumCaseDecl *decl) { // FIXME: Attributes? recordDeclLoc(decl); OS << "case "; interleave(decl->getElements().begin(), decl->getElements().end(), [&](EnumElementDecl *elt) { printEnumElement(OS, elt); }, [&] { OS << ", "; }); } void PrintAST::visitEnumElementDecl(EnumElementDecl *decl) { if (!decl->shouldPrintInContext()) return; // In cases where there is no parent EnumCaseDecl (such as imported or // deserialized elements), print the element independently. OS << "case "; printEnumElement(OS, decl); } void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) { recordDeclLoc(decl); printAttributes(decl->getAttrs()); OS << "subscript "; printPattern(decl->getIndices()); OS << " -> "; decl->getElementType().print(OS); if (!Options.FunctionDefinitions) return; OS << " {"; { IndentRAII indentMore(*this); if (auto getter = decl->getGetter()) { OS << "\n"; indent(); visit(getter); OS << "\n"; } if (auto setter = decl->getSetter()) { OS << "\n"; indent(); visit(setter); OS << "\n"; } } indent(); OS << "}"; } void PrintAST::visitConstructorDecl(ConstructorDecl *decl) { recordDeclLoc(decl); printAttributes(decl->getAttrs()); printImplicitObjCNote(decl); OS << "init"; if (decl->isGeneric()) { printGenericParams(decl->getGenericParams()); } printFunctionParameters(decl); if (!Options.FunctionDefinitions || !decl->getBody()) { return; } OS << " "; visit(decl->getBody()); } void PrintAST::visitDestructorDecl(DestructorDecl *decl) { recordDeclLoc(decl); printAttributes(decl->getAttrs()); printImplicitObjCNote(decl); OS << "destructor() "; if (!Options.FunctionDefinitions || !decl->getBody()) { return; } OS << " "; visit(decl->getBody()); } void PrintAST::visitInfixOperatorDecl(InfixOperatorDecl *decl) { recordDeclLoc(decl); OS << "operator infix " << decl->getName() << " {\n"; { IndentRAII indentMore(*this); if (decl->getAssociativityLoc().isValid()) { indent(); OS << "associativity "; switch (decl->getAssociativity()) { case Associativity::None: OS << "none\n"; break; case Associativity::Left: OS << "left\n"; break; case Associativity::Right: OS << "right\n"; break; } } if (decl->getPrecedenceLoc().isValid()) { indent(); OS << "precedence " << decl->getPrecedence() << '\n'; } } indent(); OS << "}"; } void PrintAST::visitPrefixOperatorDecl(PrefixOperatorDecl *decl) { recordDeclLoc(decl); OS << "operator prefix " << decl->getName() << " {\n}"; } void PrintAST::visitPostfixOperatorDecl(PostfixOperatorDecl *decl) { recordDeclLoc(decl); OS << "operator postfix " << decl->getName() << " {\n}"; } void PrintAST::visitBraceStmt(BraceStmt *stmt) { OS << "{"; printBraceStmtElements(stmt); OS << "\n"; indent(); OS << "}"; } void PrintAST::visitReturnStmt(ReturnStmt *stmt) { OS << "return"; if (stmt->hasResult()) { OS << " "; // FIXME: print expression. } } void PrintAST::visitIfStmt(IfStmt *stmt) { OS << "if "; // FIXME: print condition OS << " "; visit(stmt->getThenStmt()); if (auto elseStmt = stmt->getElseStmt()) { OS << " else "; visit(elseStmt); } } void PrintAST::visitWhileStmt(WhileStmt *stmt) { OS << "while "; // FIXME: print condition OS << " "; visit(stmt->getBody()); } void PrintAST::visitDoWhileStmt(DoWhileStmt *stmt) { OS << "do "; visit(stmt->getBody()); OS << " while "; // FIXME: print condition } void PrintAST::visitForStmt(ForStmt *stmt) { OS << "for ("; // FIXME: print initializer OS << "; "; if (stmt->getCond().isNonNull()) { // FIXME: print cond } OS << "; "; // FIXME: print increment OS << ") "; visit(stmt->getBody()); } void PrintAST::visitForEachStmt(ForEachStmt *stmt) { OS << "for "; printPattern(stmt->getPattern()); OS << " in "; // FIXME: print container OS << " "; visit(stmt->getBody()); } void PrintAST::visitBreakStmt(BreakStmt *stmt) { OS << "break"; } void PrintAST::visitContinueStmt(ContinueStmt *stmt) { OS << "continue"; } void PrintAST::visitFallthroughStmt(FallthroughStmt *stmt) { OS << "fallthrough"; } void PrintAST::visitSwitchStmt(SwitchStmt *stmt) { OS << "switch "; // FIXME: print subject OS << "{\n"; for (CaseStmt *C : stmt->getCases()) { visit(C); } OS << '\n'; indent(); OS << "}"; } void PrintAST::visitCaseStmt(CaseStmt *stmt) { auto printCaseLabel = [&](CaseLabel *label) { if (label->isDefault()) { OS << "default"; // '_' pattern is implicit and doesn't need to be printed. } else { OS << "case "; interleave(label->getPatterns(), [&](Pattern *p) { printPattern(p); }, [&] { OS << ", "; }); } if (label->getGuardExpr()) { OS << " where "; // FIXME: print guard expr } OS << ":\n"; }; for (auto *label : stmt->getCaseLabels()) printCaseLabel(label); printBraceStmtElements(cast(stmt->getBody())); } void Decl::print(raw_ostream &os) const { PrintOptions options; options.FunctionDefinitions = true; options.TypeDefinitions = true; options.VarInitializers = true; PrintAST printer(os, options, nullptr); printer.visit(const_cast(this)); } void Decl::print( raw_ostream &os, const PrintOptions &options, SmallVectorImpl> *declOffsets) const { PrintAST printer(os, options, declOffsets); printer.visit(const_cast(this)); } bool Decl::shouldPrintInContext() const { // Skip getters/setters. They are part of the variable or subscript. if (isa(this) && cast(this)->isGetterOrSetter()) return false; // Skip stored variables, unless they came from a Clang module. // Stored variables in Swift source will be picked up by the // PatternBindingDecl. if (isa(this) && !this->hasClangNode() && !cast(this)->isComputed()) 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)) { if (named->getDecl()->isComputed()) { 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(); } // FIXME: Skip implicitly-generated constructors. // Print everything else. return true; } void Pattern::print(llvm::raw_ostream &OS, const PrintOptions &Options) const { PrintAST Printer(OS, Options, nullptr); Printer.printPattern(this); } //===----------------------------------------------------------------------===// // Type Printing //===----------------------------------------------------------------------===// namespace { class TypePrinter : public TypeVisitor { raw_ostream &OS; const PrintOptions &Options; void printDeclContext(DeclContext *DC) { switch (DC->getContextKind()) { case DeclContextKind::Module: { Module *M = cast(DC); if (auto Parent = M->getParent()) printDeclContext(Parent); OS << M->Name; return; } case DeclContextKind::SourceFile: 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::TopLevelCodeDecl: llvm_unreachable("bad decl context"); case DeclContextKind::AbstractFunctionDecl: visit(cast(DC)->getType()); return; } } void printGenericArgs(ArrayRef Args) { if (Args.empty()) return; OS << '<'; bool First = true; for (Type Arg : Args) { if (First) First = false; else OS << ", "; visit(Arg); } OS << '>'; } /// 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; } switch (T->getKind()) { case TypeKind::Array: case TypeKind::ArraySlice: case TypeKind::Function: case TypeKind::PolymorphicFunction: case TypeKind::GenericFunction: OS << '('; visit(T); OS << ')'; break; default: visit(T); } } void printGenericParams(GenericParamList *Params) { PrintAST(OS, Options, nullptr).printGenericParams(Params); } public: TypePrinter(raw_ostream &OS, const PrintOptions &PO) : OS(OS), Options(PO) {} void visitErrorType(ErrorType *T) { OS << "<>"; } void visitBuiltinRawPointerType(BuiltinRawPointerType *T) { OS << "Builtin.RawPointer"; } void visitBuiltinObjectPointerType(BuiltinObjectPointerType *T) { OS << "Builtin.ObjectPointer"; } void visitBuiltinObjCPointerType(BuiltinObjCPointerType *T) { OS << "Builtin.ObjCPointer"; } 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; } OS << "Builtin.Vec" << T->getNumElements() << "x" << UnderlyingStr; } void visitBuiltinIntegerType(BuiltinIntegerType *T) { OS << "Builtin.Int" << T->getBitWidth(); } void visitBuiltinFloatType(BuiltinFloatType *T) { switch (T->getFPKind()) { case BuiltinFloatType::IEEE16: OS << "Builtin.FPIEEE16"; return; case BuiltinFloatType::IEEE32: OS << "Builtin.FPIEEE32"; return; case BuiltinFloatType::IEEE64: OS << "Builtin.FPIEEE64"; return; case BuiltinFloatType::IEEE80: OS << "Builtin.FPIEEE80"; return; case BuiltinFloatType::IEEE128: OS << "Builtin.FPIEEE128"; return; case BuiltinFloatType::PPC128: OS << "Builtin.FPPPC128"; return; } } void visitNameAliasType(NameAliasType *T) { if (Options.FullyQualifiedTypes) { if (auto ParentDC = T->getDecl()->getDeclContext()) { printDeclContext(ParentDC); OS << '.'; } } OS << T->getDecl()->getName().get(); } void visitParenType(ParenType *T) { OS << '('; visit(T->getUnderlyingType()); OS << ')'; } void visitTupleType(TupleType *T) { OS << "("; auto Fields = T->getFields(); for (unsigned i = 0, e = Fields.size(); i != e; ++i) { if (i) OS << ", "; const TupleTypeElt &TD = Fields[i]; if (TD.hasName()) OS << TD.getName() << ": "; if (TD.isVararg()) OS << TD.getVarargBaseTy() << "..."; else OS << TD.getType(); } OS << ')'; } void visitUnboundGenericType(UnboundGenericType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); OS << "."; } else if (Options.FullyQualifiedTypes) { OS << T->getDecl()->getModuleContext()->Name << "."; } OS << T->getDecl()->getName().get(); } void visitBoundGenericType(BoundGenericType *T) { if (Options.SynthesizeSugarOnTypes) { auto *NT = T->getAnyNominal(); auto &Ctx = T->getASTContext(); if (NT == Ctx.getSliceDecl()) { printWithParensIfNotSimple(T->getGenericArgs()[0]); OS << "[]"; return; } if (NT == Ctx.getOptionalDecl()) { printWithParensIfNotSimple(T->getGenericArgs()[0]); OS << "?"; return; } } if (auto ParentType = T->getParent()) { visit(ParentType); OS << "."; } else if (Options.FullyQualifiedTypes) { OS << T->getDecl()->getModuleContext()->Name << "."; } OS << T->getDecl()->getName().get(); printGenericArgs(T->getGenericArgs()); } void visitEnumType(EnumType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); OS << "."; } else if (Options.FullyQualifiedTypes) { OS << T->getDecl()->getModuleContext()->Name << "."; } OS << T->getDecl()->getName().get(); } void visitStructType(StructType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); OS << "."; } else if (Options.FullyQualifiedTypes) { OS << T->getDecl()->getModuleContext()->Name << "."; } OS << T->getDecl()->getName().get(); } void visitClassType(ClassType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); OS << "."; } else if (Options.FullyQualifiedTypes) { OS << T->getDecl()->getModuleContext()->Name << "."; } OS << T->getDecl()->getName().get(); } void visitMetaTypeType(MetaTypeType *T) { printWithParensIfNotSimple(T->getInstanceType()); OS << ".metatype"; } void visitModuleType(ModuleType *T) { OS << "module<" << T->getModule()->Name << '>'; } void printFunctionExtInfo(AnyFunctionType::ExtInfo info) { if (info.isAutoClosure()) OS << "@auto_closure "; switch (info.getCC()) { case AbstractCC::Freestanding: break; case AbstractCC::Method: OS << "@cc(method) "; break; case AbstractCC::C: OS << "@cc(cdecl) "; break; case AbstractCC::ObjCMethod: OS << "@cc(objc_method) "; break; } if (info.isBlock()) OS << "@objc_block "; if (info.isThin()) OS << "@thin "; if (info.isNoReturn()) OS << "@noreturn "; } void visitFunctionType(FunctionType *T) { printFunctionExtInfo(T->getExtInfo()); printWithParensIfNotSimple(T->getInput()); OS << " -> " << T->getResult(); } void visitPolymorphicFunctionType(PolymorphicFunctionType *T) { printFunctionExtInfo(T->getExtInfo()); printGenericParams(&T->getGenericParams()); OS << ' '; printWithParensIfNotSimple(T->getInput()); OS << " -> " << T->getResult(); } void visitGenericFunctionType(GenericFunctionType *T) { printFunctionExtInfo(T->getExtInfo()); // Print the generic parameters. OS << '<'; bool isFirstParam = true; for (auto param : T->getGenericParams()) { if (isFirstParam) isFirstParam = false; else OS << ", "; visit(param); } // Print the requirements. bool isFirstReq = true; for (const auto &req : T->getRequirements()) { if (req.getKind() == RequirementKind::ValueWitnessMarker) continue; if (isFirstReq) { OS << " where "; isFirstReq = false; } else { OS << ", "; } visit(req.getFirstType()); switch (req.getKind()) { case RequirementKind::Conformance: OS << " : "; break; case RequirementKind::SameType: OS << " == "; break; case RequirementKind::ValueWitnessMarker: llvm_unreachable("Handled above"); } visit(req.getSecondType()); } OS << '>'; OS << ' '; printWithParensIfNotSimple(T->getInput()); OS << " -> " << T->getResult(); } void visitSILFunctionType(SILFunctionType *T) { OS << "def "; printFunctionExtInfo(T->getExtInfo()); if (auto generics = T->getGenericParams()) printGenericParams(generics); OS << '('; bool first = true; for (auto param : T->getParameters()) { if (first) { first = false; } else { OS << ", "; } param.print(OS, Options); } OS << ") -> "; T->getResult().print(OS, Options); } void visitArrayType(ArrayType *T) { printWithParensIfNotSimple(T->getBaseType()); OS << '[' << T->getSize() << ']'; } void visitArraySliceType(ArraySliceType *T) { printWithParensIfNotSimple(T->getBaseType()); OS << "[]"; } void visitOptionalType(OptionalType *T) { printWithParensIfNotSimple(T->getBaseType()); OS << '?'; } void visitProtocolType(ProtocolType *T) { OS << T->getDecl()->getName().str(); } void visitProtocolCompositionType(ProtocolCompositionType *T) { OS << "protocol<"; bool First = true; for (auto Proto : T->getProtocols()) { if (First) First = false; else OS << ", "; visit(Proto); } OS << ">"; } void visitLValueType(LValueType *T) { OS << "@inout "; LValueType::Qual QS = T->getQualifiers(); if (QS != LValueType::Qual::DefaultForType) { bool HasQual = false; #define APPEND_QUAL(Cond, Text) \ do { \ if (Cond) { \ if (HasQual) \ OS << ", "; \ HasQual = true; \ OS << Text; \ } \ } while(false) OS << '('; APPEND_QUAL(QS & LValueType::Qual::Implicit, "implicit"); APPEND_QUAL(QS & LValueType::Qual::NonSettable, "nonsettable"); OS << ')'; #undef APPEND_QUAL } visit(T->getObjectType()); } void visitArchetypeType(ArchetypeType *T) { OS << T->getFullName(); } void visitGenericTypeParamType(GenericTypeParamType *T) { if (auto decl = T->getDecl()) { auto Name = decl->getName(); if (Name.empty()) OS << ""; else OS << Name.str(); return; } OS << "$T_" << T->getDepth() << "_" << T->getIndex(); } void visitAssociatedTypeType(AssociatedTypeType *T) { auto Name = T->getDecl()->getName(); if (Name.empty()) OS << ""; else OS << Name.str(); } void visitSubstitutedType(SubstitutedType *T) { visit(T->getReplacementType()); } void visitDependentMemberType(DependentMemberType *T) { visit(T->getBase()); OS << "." << T->getName().str(); } void visitUnownedStorageType(UnownedStorageType *T) { OS << "@sil_unowned "; visit(T->getReferentType()); } void visitWeakStorageType(WeakStorageType *T) { OS << "@sil_weak "; visit(T->getReferentType()); } void visitTypeVariableType(TypeVariableType *T) { OS << "$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 { if (isNull()) OS << ""; else TypePrinter(OS, PO).visit(*this); } 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"); } void SILParameterInfo::dump() const { print(llvm::errs()); } void SILParameterInfo::print(raw_ostream &out, const PrintOptions &opts) const { out << getStringForParameterConvention(getConvention()); getType().print(out, opts); } static StringRef getStringForResultConvention(ResultConvention conv) { switch (conv) { case ResultConvention::Owned: return "@owned "; case ResultConvention::Unowned: return ""; case ResultConvention::Autoreleased: return "@autoreleased "; } llvm_unreachable("bad result convention"); } void SILResultInfo::dump() const { print(llvm::errs()); } void SILResultInfo::print(raw_ostream &out, const PrintOptions &opts) const { out << getStringForResultConvention(getConvention()); getType().print(out, 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); }