From a3c27005b85509ca39ef23b28512f0534e44ada0 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Fri, 7 Sep 2018 10:38:29 -0700 Subject: [PATCH 01/16] Introduce stored inlinable function bodies --- include/swift/AST/Decl.h | 6 ++++++ include/swift/Serialization/ModuleFormat.h | 8 ++++++-- lib/AST/Decl.cpp | 12 ++++++++++++ lib/Serialization/Deserialization.cpp | 10 +++++++--- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 956edb105d13b..262bbbe5e77b1 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4988,6 +4988,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { private: ParameterList *Params; + StringRef BodyStringRepresentation; protected: // If a function has a body at all, we have either a parsed body AST node or @@ -5154,6 +5155,11 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { setBodyKind(BodyKind::TypeChecked); } + StringRef getBodyStringRepresentation(SmallVectorImpl &scratch); + void setBodyStringRepresentation(StringRef body) { + BodyStringRepresentation = body; + } + bool isBodyTypeChecked() const { return getBodyKind() == BodyKind::TypeChecked; } diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index 1a8de4c6e0bae..1faea5364e640 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t VERSION_MINOR = 443; // Last change: serialize unsubstituted type alias type +const uint16_t VERSION_MINOR = 444; // Last change: inlinable bodies using DeclIDField = BCFixed<31>; @@ -977,6 +977,7 @@ namespace decls_block { BCFixed<1>, // default argument resilience expansion BCFixed<1>, // 'required' but overridden is not (used for recovery) BCVBR<5>, // number of parameter name components + BCBlob, // inlinable body text BCArray // name components, // followed by TypeID dependencies // Trailed by its generic parameters, if any, followed by the parameter @@ -1038,6 +1039,7 @@ namespace decls_block { AccessLevelField, // access level BCFixed<1>, // requires a new vtable slot BCFixed<1>, // default argument resilience expansion + BCBlob, // inlinable body text BCArray // name components, // followed by TypeID dependencies // The record is trailed by: @@ -1149,6 +1151,7 @@ namespace decls_block { AccessLevelField, // access level AccessLevelField, // setter access, if applicable BCVBR<5>, // number of parameter name components + BCBlob, // inlinable body text BCArray // name components, // followed by DeclID accessors, // followed by TypeID dependencies @@ -1175,7 +1178,8 @@ namespace decls_block { DeclContextIDField, // context decl BCFixed<1>, // implicit? BCFixed<1>, // objc? - GenericEnvironmentIDField // generic environment + GenericEnvironmentIDField, // generic environment + BCBlob // inlinable body text >; using ParameterListLayout = BCRecordLayout< diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 141c9f4aa92f7..be33abb8fd178 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5419,6 +5419,18 @@ void AbstractFunctionDecl::computeType(AnyFunctionType::ExtInfo info) { computeSelfDeclType(); } +StringRef AbstractFunctionDecl::getBodyStringRepresentation( + SmallVectorImpl &scratch) { + if (!BodyStringRepresentation.empty()) + return BodyStringRepresentation; + + auto body = getBody(); + assert(body && !body->isImplicit() && + "can't get string representation of function with implicit body"); + + return extractInlinableText(getASTContext().SourceMgr, body, scratch); +} + FuncDecl *FuncDecl::createImpl(ASTContext &Context, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index dd294a09b8105..65622e23fbcbc 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2751,6 +2751,7 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { uint8_t rawDefaultArgumentResilienceExpansion; unsigned numArgNames; ArrayRef argNameAndDependencyIDs; + StringRef bodyText; decls_block::ConstructorLayout::readRecord(scratch, contextID, rawFailability, isImplicit, @@ -2762,7 +2763,7 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { needsNewVTableEntry, rawDefaultArgumentResilienceExpansion, firstTimeRequired, - numArgNames, + numArgNames, &bodyText, argNameAndDependencyIDs); // Resolve the name ids. @@ -2846,6 +2847,7 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { ctor->setInitKind(initKind.getValue()); ctor->setOverriddenDecl(cast_or_null(overridden.get())); ctor->setNeedsNewVTableEntry(needsNewVTableEntry); + ctor->setBodyStringRepresentation(bodyText); if (auto defaultArgumentResilienceExpansion = getActualResilienceExpansion( rawDefaultArgumentResilienceExpansion)) { @@ -3047,6 +3049,7 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { bool needsNewVTableEntry; uint8_t rawDefaultArgumentResilienceExpansion; ArrayRef nameAndDependencyIDs; + StringRef bodyText; if (!isAccessor) { decls_block::FuncLayout::readRecord(scratch, contextID, isImplicit, @@ -3060,7 +3063,7 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { rawAccessLevel, needsNewVTableEntry, rawDefaultArgumentResilienceExpansion, - nameAndDependencyIDs); + &bodyText, nameAndDependencyIDs); } else { decls_block::AccessorLayout::readRecord(scratch, contextID, isImplicit, isStatic, rawStaticSpelling, isObjC, @@ -3074,7 +3077,7 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { rawAccessLevel, needsNewVTableEntry, rawDefaultArgumentResilienceExpansion, - nameAndDependencyIDs); + &bodyText, nameAndDependencyIDs); } DeclDeserializationError::Flags errorFlags; @@ -3239,6 +3242,7 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { fn->setDynamicSelf(hasDynamicSelf); fn->setForcedStaticDispatch(hasForcedStaticDispatch); fn->setNeedsNewVTableEntry(needsNewVTableEntry); + fn->setBodyStringRepresentation(bodyText); if (auto defaultArgumentResilienceExpansion = getActualResilienceExpansion( rawDefaultArgumentResilienceExpansion)) { From 89ef7d4270fce65bde8cb5420df640ee7e30a9aa Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Fri, 7 Sep 2018 13:17:59 -0700 Subject: [PATCH 02/16] Remove serialization changes --- include/swift/AST/Decl.h | 2 +- include/swift/Serialization/ModuleFormat.h | 6 +----- lib/AST/Decl.cpp | 2 +- lib/Serialization/Deserialization.cpp | 10 +++------- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 262bbbe5e77b1..7184fc3674a14 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5155,7 +5155,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { setBodyKind(BodyKind::TypeChecked); } - StringRef getBodyStringRepresentation(SmallVectorImpl &scratch); + StringRef getBodyStringRepresentation(SmallVectorImpl &scratch) const; void setBodyStringRepresentation(StringRef body) { BodyStringRepresentation = body; } diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index 1faea5364e640..53889dca58b67 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -977,7 +977,6 @@ namespace decls_block { BCFixed<1>, // default argument resilience expansion BCFixed<1>, // 'required' but overridden is not (used for recovery) BCVBR<5>, // number of parameter name components - BCBlob, // inlinable body text BCArray // name components, // followed by TypeID dependencies // Trailed by its generic parameters, if any, followed by the parameter @@ -1039,7 +1038,6 @@ namespace decls_block { AccessLevelField, // access level BCFixed<1>, // requires a new vtable slot BCFixed<1>, // default argument resilience expansion - BCBlob, // inlinable body text BCArray // name components, // followed by TypeID dependencies // The record is trailed by: @@ -1151,7 +1149,6 @@ namespace decls_block { AccessLevelField, // access level AccessLevelField, // setter access, if applicable BCVBR<5>, // number of parameter name components - BCBlob, // inlinable body text BCArray // name components, // followed by DeclID accessors, // followed by TypeID dependencies @@ -1178,8 +1175,7 @@ namespace decls_block { DeclContextIDField, // context decl BCFixed<1>, // implicit? BCFixed<1>, // objc? - GenericEnvironmentIDField, // generic environment - BCBlob // inlinable body text + GenericEnvironmentIDField // generic environment >; using ParameterListLayout = BCRecordLayout< diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index be33abb8fd178..01b57af6e801c 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5420,7 +5420,7 @@ void AbstractFunctionDecl::computeType(AnyFunctionType::ExtInfo info) { } StringRef AbstractFunctionDecl::getBodyStringRepresentation( - SmallVectorImpl &scratch) { + SmallVectorImpl &scratch) const { if (!BodyStringRepresentation.empty()) return BodyStringRepresentation; diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 65622e23fbcbc..dd294a09b8105 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2751,7 +2751,6 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { uint8_t rawDefaultArgumentResilienceExpansion; unsigned numArgNames; ArrayRef argNameAndDependencyIDs; - StringRef bodyText; decls_block::ConstructorLayout::readRecord(scratch, contextID, rawFailability, isImplicit, @@ -2763,7 +2762,7 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { needsNewVTableEntry, rawDefaultArgumentResilienceExpansion, firstTimeRequired, - numArgNames, &bodyText, + numArgNames, argNameAndDependencyIDs); // Resolve the name ids. @@ -2847,7 +2846,6 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { ctor->setInitKind(initKind.getValue()); ctor->setOverriddenDecl(cast_or_null(overridden.get())); ctor->setNeedsNewVTableEntry(needsNewVTableEntry); - ctor->setBodyStringRepresentation(bodyText); if (auto defaultArgumentResilienceExpansion = getActualResilienceExpansion( rawDefaultArgumentResilienceExpansion)) { @@ -3049,7 +3047,6 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { bool needsNewVTableEntry; uint8_t rawDefaultArgumentResilienceExpansion; ArrayRef nameAndDependencyIDs; - StringRef bodyText; if (!isAccessor) { decls_block::FuncLayout::readRecord(scratch, contextID, isImplicit, @@ -3063,7 +3060,7 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { rawAccessLevel, needsNewVTableEntry, rawDefaultArgumentResilienceExpansion, - &bodyText, nameAndDependencyIDs); + nameAndDependencyIDs); } else { decls_block::AccessorLayout::readRecord(scratch, contextID, isImplicit, isStatic, rawStaticSpelling, isObjC, @@ -3077,7 +3074,7 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { rawAccessLevel, needsNewVTableEntry, rawDefaultArgumentResilienceExpansion, - &bodyText, nameAndDependencyIDs); + nameAndDependencyIDs); } DeclDeserializationError::Flags errorFlags; @@ -3242,7 +3239,6 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { fn->setDynamicSelf(hasDynamicSelf); fn->setForcedStaticDispatch(hasForcedStaticDispatch); fn->setNeedsNewVTableEntry(needsNewVTableEntry); - fn->setBodyStringRepresentation(bodyText); if (auto defaultArgumentResilienceExpansion = getActualResilienceExpansion( rawDefaultArgumentResilienceExpansion)) { From 2f89fd175a9979c5645617c3780fadb7efa85060 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Fri, 7 Sep 2018 17:53:34 -0700 Subject: [PATCH 03/16] [InterfaceGen] Print inlinable function bodies --- include/swift/AST/PrintOptions.h | 8 ++-- lib/AST/ASTPrinter.cpp | 74 ++++++++++++++------------------ lib/AST/Decl.cpp | 2 +- lib/AST/InlinableText.cpp | 22 +++++++--- lib/AST/InlinableText.h | 5 +++ lib/Sema/TypeCheckProtocol.cpp | 8 +++- 6 files changed, 64 insertions(+), 55 deletions(-) diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index 7823671a1b182..f1a066b27c5c4 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -23,6 +23,7 @@ #include namespace swift { +class ASTPrinter; class GenericEnvironment; class CanType; class Decl; @@ -356,10 +357,9 @@ struct PrintOptions { QualifyNestedDeclarations ShouldQualifyNestedDeclarations = QualifyNestedDeclarations::Never; - /// \brief If this is not \c nullptr then functions (including accessors and - /// constructors) will be printed with a body that is determined by this - /// function. - std::function FunctionBody; + /// \brief If this is not \c nullptr then function bodies (including accessors + /// and constructors) will be printed by this function. + std::function FunctionBody; BracketOptions BracketOptions; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 092d9a8b13178..7d369c2c29cdd 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -81,6 +81,15 @@ PrintOptions PrintOptions::printTextualInterfaceFile() { result.SkipImports = true; result.OmitNameOfInaccessibleProperties = true; + result.FunctionBody = [](const ValueDecl *decl, ASTPrinter &printer) { + auto AFD = dyn_cast(decl); + if (!AFD) return; + if (!AFD->getAttrs().hasAttribute()) + return; + SmallString<128> scratch; + printer << " " << AFD->getBodyStringRepresentation(scratch); + }; + class ShouldPrintForTextualInterface : public ShouldPrintChecker { bool shouldPrint(const Decl *D, const PrintOptions &options) override { // Skip anything that isn't 'public' or '@usableFromInline'. @@ -1630,26 +1639,32 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) { Printer << " "; Printer.printKeyword(getAccessorLabel(Accessor)); } else { - Printer.printNewline(); - IndentRAII IndentMore(*this); + { + IndentRAII IndentMore(*this); + indent(); + visit(Accessor); + } indent(); - visit(Accessor); + Printer.printNewline(); } }; - Printer << " {"; if ((PrintAbstract || (impl.getReadImpl() == ReadImplKind::Get && ASD->getGetter())) && !ASD->supportsMutation() && !ASD->isGetterMutating() && PrintAccessorBody && !Options.FunctionDefinitions) { // Omit the 'get' keyword. Directly print getter if (auto BodyFunc = Options.FunctionBody) { - Printer.printNewline(); - IndentRAII IndentBody(*this); - indent(); - Printer << BodyFunc(ASD->getGetter()); + BodyFunc(ASD->getGetter(), Printer); } - } else if (PrintAbstract) { + Printer.printNewline(); + indent(); + return; + } + + Printer << " {"; + Printer.printNewline(); + if (PrintAbstract) { PrintAccessor(ASD->getGetter()); if (ASD->supportsMutation()) PrintAccessor(ASD->getSetter()); @@ -1693,12 +1708,13 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) { break; } } - if (PrintAccessorBody) { - Printer.printNewline(); - indent(); - } else + + if (!PrintAccessorBody) Printer << " "; + Printer << "}"; + Printer.printNewline(); + indent(); } void PrintAST::printMembersOfDecl(Decl *D, bool needComma, @@ -2497,7 +2513,6 @@ void PrintAST::visitAccessorDecl(AccessorDecl *decl) { [&]{ Printer << getAccessorLabel(decl); }); - Printer << " {"; break; case AccessorKind::Set: case AccessorKind::WillSet: @@ -2515,24 +2530,16 @@ void PrintAST::visitAccessorDecl(AccessorDecl *decl) { } } }); - Printer << " {"; } if (auto BodyFunc = Options.FunctionBody) { - { - IndentRAII IndentBody(*this); - indent(); - Printer.printNewline(); - Printer << BodyFunc(decl); - } + BodyFunc(decl, Printer); indent(); - Printer.printNewline(); } else if (Options.FunctionDefinitions && decl->getBody()) { if (printASTNodes(decl->getBody()->getElements())) { Printer.printNewline(); indent(); } } - Printer << "}"; } void PrintAST::visitFuncDecl(FuncDecl *decl) { @@ -2605,17 +2612,8 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) { } if (auto BodyFunc = Options.FunctionBody) { - Printer << " {"; - Printer.printNewline(); - { - IndentRAII IndentBody(*this); - indent(); - Printer << BodyFunc(decl); - } + BodyFunc(decl, Printer); indent(); - Printer.printNewline(); - Printer << "}"; - } else if (Options.FunctionDefinitions && decl->getBody()) { Printer << " "; visit(decl->getBody()); @@ -2789,16 +2787,8 @@ void PrintAST::visitConstructorDecl(ConstructorDecl *decl) { printGenericDeclGenericRequirements(decl); if (auto BodyFunc = Options.FunctionBody) { - Printer << " {"; - { - Printer.printNewline(); - IndentRAII IndentBody(*this); - indent(); - Printer << BodyFunc(decl); - } + BodyFunc(decl, Printer); indent(); - Printer.printNewline(); - Printer << "}"; } else if (Options.FunctionDefinitions && decl->getBody()) { Printer << " "; visit(decl->getBody()); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 01b57af6e801c..20c00f43837cd 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5428,7 +5428,7 @@ StringRef AbstractFunctionDecl::getBodyStringRepresentation( assert(body && !body->isImplicit() && "can't get string representation of function with implicit body"); - return extractInlinableText(getASTContext().SourceMgr, body, scratch); + return extractInlinableBodyText(this, scratch); } FuncDecl *FuncDecl::createImpl(ASTContext &Context, diff --git a/lib/AST/InlinableText.cpp b/lib/AST/InlinableText.cpp index be89869d0bf93..e726cce89bbad 100644 --- a/lib/AST/InlinableText.cpp +++ b/lib/AST/InlinableText.cpp @@ -14,6 +14,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/ASTNode.h" #include "swift/AST/Decl.h" +#include "swift/AST/Stmt.h" #include "swift/Parse/Lexer.h" #include "llvm/ADT/SmallVector.h" @@ -121,26 +122,33 @@ struct ExtractInactiveRanges : public ASTWalker { }; } // end anonymous namespace -StringRef swift::extractInlinableText(SourceManager &sourceMgr, ASTNode node, - SmallVectorImpl &scratch) { +StringRef swift::extractInlinableBodyText(const AbstractFunctionDecl *func, + SmallVectorImpl &scratch) { + auto &sm = func->getASTContext().SourceMgr; + return extractInlinableText(sm, func->getBody(), scratch); +} + +StringRef +swift::extractInlinableText(SourceManager &sourceMgr, ASTNode node, + SmallVectorImpl &scratch) { // Extract inactive ranges from the text of the node. ExtractInactiveRanges extractor(sourceMgr); node.walk(extractor); + SourceRange fullRange = node.getSourceRange(); + // If there were no inactive ranges, then there were no #if configs. // Return an unowned buffer directly into the source file. if (extractor.ranges.empty()) { - auto range = - Lexer::getCharSourceRangeFromSourceRange( - sourceMgr, node.getSourceRange()); + auto range = Lexer::getCharSourceRangeFromSourceRange(sourceMgr, fullRange); return sourceMgr.extractText(range); } // Begin piecing together active code ranges. // Get the full start and end of the provided node, as character locations. - SourceLoc start = node.getStartLoc(); - SourceLoc end = Lexer::getLocForEndOfToken(sourceMgr, node.getEndLoc()); + SourceLoc start = fullRange.Start; + SourceLoc end = Lexer::getLocForEndOfToken(sourceMgr, fullRange.End); for (auto &range : extractor.getSortedRanges()) { // Add the text from the current 'start' to this ignored range's start. auto charRange = CharSourceRange(sourceMgr, start, range.getStart()); diff --git a/lib/AST/InlinableText.h b/lib/AST/InlinableText.h index c96b64036b8ab..c234ce2cbaeaf 100644 --- a/lib/AST/InlinableText.h +++ b/lib/AST/InlinableText.h @@ -14,12 +14,17 @@ #define SWIFT_AST_INLINABLETEXT_H #include "swift/AST/ASTNode.h" +#include "swift/Basic/SourceLoc.h" #include "swift/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallVector.h" namespace swift { class SourceManager; +class AbstractFunctionDecl; + +StringRef extractInlinableBodyText(const AbstractFunctionDecl *func, + SmallVectorImpl &scratch); /// Extracts the text of this ASTNode from the source buffer, ignoring /// all #if declarations and clauses except the elements that are active. diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index db31376fd4768..714e94b11d2a8 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2394,7 +2394,13 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter, Options.AccessFilter = AccessLevel::Private; Options.PrintAccess = false; Options.SkipAttributes = true; - Options.FunctionBody = [](const ValueDecl *VD) { return getCodePlaceholder(); }; + Options.FunctionBody = [&](const ValueDecl *VD, ASTPrinter &Printer) { + Printer << " {"; + Printer.printNewline(); + Printer << getCodePlaceholder(); + Printer.printNewline(); + Printer << "}"; + }; Options.setBaseType(AdopterTy); Options.CurrentModule = Adopter->getParentModule(); if (!Adopter->isExtensionContext()) { From b2620c56b317b5409bf01c72cf2b9973a4327880 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Mon, 10 Sep 2018 14:16:22 -0700 Subject: [PATCH 04/16] Clean up a little bit and add test --- lib/AST/ASTPrinter.cpp | 5 +- lib/AST/Decl.cpp | 2 +- lib/AST/InlinableText.cpp | 6 - lib/AST/InlinableText.h | 4 - test/ModuleInterface/inlinable-function.swift | 140 ++++++++++++++++++ 5 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 test/ModuleInterface/inlinable-function.swift diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 7d369c2c29cdd..e0a0932a9bc09 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -83,8 +83,9 @@ PrintOptions PrintOptions::printTextualInterfaceFile() { result.FunctionBody = [](const ValueDecl *decl, ASTPrinter &printer) { auto AFD = dyn_cast(decl); - if (!AFD) return; - if (!AFD->getAttrs().hasAttribute()) + if (!AFD || AFD->isImplicit()) return; + if (!AFD->getBody() || AFD->getBody()->isImplicit()) return; + if (AFD->getResilienceExpansion() != ResilienceExpansion::Minimal) return; SmallString<128> scratch; printer << " " << AFD->getBodyStringRepresentation(scratch); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 20c00f43837cd..01b57af6e801c 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5428,7 +5428,7 @@ StringRef AbstractFunctionDecl::getBodyStringRepresentation( assert(body && !body->isImplicit() && "can't get string representation of function with implicit body"); - return extractInlinableBodyText(this, scratch); + return extractInlinableText(getASTContext().SourceMgr, body, scratch); } FuncDecl *FuncDecl::createImpl(ASTContext &Context, diff --git a/lib/AST/InlinableText.cpp b/lib/AST/InlinableText.cpp index e726cce89bbad..f6f8667eef5ee 100644 --- a/lib/AST/InlinableText.cpp +++ b/lib/AST/InlinableText.cpp @@ -122,12 +122,6 @@ struct ExtractInactiveRanges : public ASTWalker { }; } // end anonymous namespace -StringRef swift::extractInlinableBodyText(const AbstractFunctionDecl *func, - SmallVectorImpl &scratch) { - auto &sm = func->getASTContext().SourceMgr; - return extractInlinableText(sm, func->getBody(), scratch); -} - StringRef swift::extractInlinableText(SourceManager &sourceMgr, ASTNode node, SmallVectorImpl &scratch) { diff --git a/lib/AST/InlinableText.h b/lib/AST/InlinableText.h index c234ce2cbaeaf..48e5093c089b7 100644 --- a/lib/AST/InlinableText.h +++ b/lib/AST/InlinableText.h @@ -21,10 +21,6 @@ namespace swift { class SourceManager; -class AbstractFunctionDecl; - -StringRef extractInlinableBodyText(const AbstractFunctionDecl *func, - SmallVectorImpl &scratch); /// Extracts the text of this ASTNode from the source buffer, ignoring /// all #if declarations and clauses except the elements that are active. diff --git a/test/ModuleInterface/inlinable-function.swift b/test/ModuleInterface/inlinable-function.swift new file mode 100644 index 0000000000000..4a64e9540635f --- /dev/null +++ b/test/ModuleInterface/inlinable-function.swift @@ -0,0 +1,140 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/Test.swiftmodule -emit-interface-path %t/Test.swiftinterface -module-name Test %s +// RUN: %FileCheck %s < %t/Test.swiftinterface +// RUN: %target-swift-frontend -emit-module -o /dev/null -merge-modules %t/Test.swiftmodule -emit-interface-path - -module-name Test | %FileCheck %s + +// CHECK: public struct Foo : Hashable { +public struct Foo: Hashable { + // CHECK: public var inlinableGetPublicSet: [[INT:(Swift.)?Int]] { + public var inlinableGetPublicSet: Int { + // CHECK: @inlinable get { + // CHECK-NEXT: return 3 + // CHECK-NEXT: } + @inlinable + get { + return 3 + } + // CHECK-NEXT: set{{$}} + set { + print("I am set to \(newValue)") + } + } + + // CHECK: public var noAccessors: [[INT]]{{$}} + public var noAccessors: Int + + // CHECK: public var hasDidSet: [[INT]] { + public var hasDidSet: Int { + // CHECK-NEXT: @_transparent get{{$}} + // CHECK-NEXT: set{{$}} + // CHECK-NOT: didSet + didSet { + print("b set to \(hasDidSet)") + } + // CHECK-NEXT: } + } + + + // CHECK: @_transparent public var transparent: [[INT]] { + // CHECK: return 34 + // CHECK: } + @_transparent + public var transparent: Int { + return 34 + } + + // CHECK: public var transparentSet: [[INT]] { + public var transparentSet: Int { + // CHECK-NEXT: get{{$}} + get { + return 34 + } + // CHECK-NEXT: @_transparent set { + // CHECK-NOT: #if false + // CHECK-NOT: print("I should not appear") + // CHECK-NOT: #else + // CHECK-NOT: #if false + // CHECK-NOT: print("I also should not") + // CHECK-NOT: #else + // CHECK: print("I am set to \(newValue)") + // CHECK-NOT: #endif + // CHECK-NOT: #endif + @_transparent + set { + #if false + print("I should not appear") + #else + #if false + print("I also should not") + #else + print("I am set to \(newValue)") + #endif + #endif + } + } + + // CHECK: @inlinable public var inlinableProperty: [[INT]] { + @inlinable + public var inlinableProperty: Int { + // CHECK: get { + // CHECK: return 32 + // CHECK: } + get { + return 32 + } + + // CHECK: set { + // CHECK-NOT: #if true + // CHECK: print("I am set to \(newValue)") + // CHECK-NOT: #else + // CHECK-NOT: print("I should not appear") + // CHECK-NOT #endif + // CHECK: } + set { + #if true + print("I am set to \(newValue)") + #else + print("I should not appear") + #endif + } + } + + // CHECK: @inlinable public func inlinableMethod() { + // CHECK-NOT: #if NO + // CHECK-NOT: print("Hello, world!") + // CHECK-NOT: #endif + // CHECK: print("Goodbye, world!") + // CHECK-NEXT: } + @inlinable + public func inlinableMethod() { + #if NO + print("Hello, world!") + #endif + print("Goodbye, world!") + } + + + // CHECK: @_transparent mutating public func transparentMethod() { + // CHECK-NEXT: inlinableProperty = 4 + // CHECK-NEXT: } + @_transparent + mutating public func transparentMethod() { + inlinableProperty = 4 + } + + // CHECK: @inline(__always) mutating public func inlineAlwaysMethod() { + // CHECK-NEXT: inlinableProperty = 4 + // CHECK-NEXT: } + @inline(__always) + mutating public func inlineAlwaysMethod() { + inlinableProperty = 4 + } + + // CHECK: public func nonInlinableMethod(){{$}} + // CHECK-NOT: print("Not inlinable") + public func nonInlinableMethod() { + print("Not inlinable") + } + + // CHECK: {{^}}} +} From be6228ecf00f73ca99ffee4c3ffd9ab83bad704f Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Mon, 10 Sep 2018 14:25:18 -0700 Subject: [PATCH 05/16] Undo changes to InlinableText --- lib/AST/InlinableText.cpp | 16 +++++++--------- lib/AST/InlinableText.h | 1 - test/ModuleInterface/attrs.swift | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/AST/InlinableText.cpp b/lib/AST/InlinableText.cpp index f6f8667eef5ee..be89869d0bf93 100644 --- a/lib/AST/InlinableText.cpp +++ b/lib/AST/InlinableText.cpp @@ -14,7 +14,6 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/ASTNode.h" #include "swift/AST/Decl.h" -#include "swift/AST/Stmt.h" #include "swift/Parse/Lexer.h" #include "llvm/ADT/SmallVector.h" @@ -122,27 +121,26 @@ struct ExtractInactiveRanges : public ASTWalker { }; } // end anonymous namespace -StringRef -swift::extractInlinableText(SourceManager &sourceMgr, ASTNode node, - SmallVectorImpl &scratch) { +StringRef swift::extractInlinableText(SourceManager &sourceMgr, ASTNode node, + SmallVectorImpl &scratch) { // Extract inactive ranges from the text of the node. ExtractInactiveRanges extractor(sourceMgr); node.walk(extractor); - SourceRange fullRange = node.getSourceRange(); - // If there were no inactive ranges, then there were no #if configs. // Return an unowned buffer directly into the source file. if (extractor.ranges.empty()) { - auto range = Lexer::getCharSourceRangeFromSourceRange(sourceMgr, fullRange); + auto range = + Lexer::getCharSourceRangeFromSourceRange( + sourceMgr, node.getSourceRange()); return sourceMgr.extractText(range); } // Begin piecing together active code ranges. // Get the full start and end of the provided node, as character locations. - SourceLoc start = fullRange.Start; - SourceLoc end = Lexer::getLocForEndOfToken(sourceMgr, fullRange.End); + SourceLoc start = node.getStartLoc(); + SourceLoc end = Lexer::getLocForEndOfToken(sourceMgr, node.getEndLoc()); for (auto &range : extractor.getSortedRanges()) { // Add the text from the current 'start' to this ignored range's start. auto charRange = CharSourceRange(sourceMgr, start, range.getStart()); diff --git a/lib/AST/InlinableText.h b/lib/AST/InlinableText.h index 48e5093c089b7..c96b64036b8ab 100644 --- a/lib/AST/InlinableText.h +++ b/lib/AST/InlinableText.h @@ -14,7 +14,6 @@ #define SWIFT_AST_INLINABLETEXT_H #include "swift/AST/ASTNode.h" -#include "swift/Basic/SourceLoc.h" #include "swift/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallVector.h" diff --git a/test/ModuleInterface/attrs.swift b/test/ModuleInterface/attrs.swift index aebf54930cdc5..4009368f8ae9f 100644 --- a/test/ModuleInterface/attrs.swift +++ b/test/ModuleInterface/attrs.swift @@ -1,7 +1,7 @@ // RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -enable-resilience -emit-module -o /dev/null %s // RUN: %FileCheck %s < %t.swiftinterface -// CHECK: @_transparent public func glass() -> Int{{$}} +// CHECK: @_transparent public func glass() -> Int { return 0 }{{$}} @_transparent public func glass() -> Int { return 0 } // CHECK: @_effects(readnone) public func illiterate(){{$}} From 9fbb83384b729aa3fdb7c2cc022dc15bf41d338d Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Mon, 10 Sep 2018 16:34:02 -0700 Subject: [PATCH 06/16] Add serialization and deserialization for inlinable body text --- include/swift/AST/Decl.h | 19 +++++++++---- .../Serialization/DeclTypeRecordNodes.def | 1 + include/swift/Serialization/ModuleFile.h | 3 ++ include/swift/Serialization/ModuleFormat.h | 20 +++++++++++-- lib/AST/ASTPrinter.cpp | 8 ++++-- lib/AST/Decl.cpp | 19 +++++++++---- lib/Sema/TypeCheckProtocol.cpp | 2 +- lib/Serialization/Deserialization.cpp | 28 +++++++++++++++++++ lib/Serialization/Serialization.cpp | 24 ++++++++++++++++ lib/Serialization/Serialization.h | 4 +++ 10 files changed, 110 insertions(+), 18 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 7184fc3674a14..32a32990d7685 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4988,7 +4988,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { private: ParameterList *Params; - StringRef BodyStringRepresentation; protected: // If a function has a body at all, we have either a parsed body AST node or @@ -4996,7 +4995,13 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { union { /// This enum member is active if getBodyKind() is BodyKind::Parsed or /// BodyKind::TypeChecked. - BraceStmt *Body; + struct { + /// The AST node of the body. + BraceStmt *Node; + + /// The string representation of the body, if anything. + StringRef StringRepresentation; + } Body; /// This enum member is active if getBodyKind() == BodyKind::Synthesize. BodySynthesizer Synthesizer; @@ -5019,7 +5024,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { GenericParamList *GenericParams) : GenericContext(DeclContextKind::AbstractFunctionDecl, Parent), ValueDecl(Kind, Parent, Name, NameLoc), - Body(nullptr), ThrowsLoc(ThrowsLoc) { + Body({nullptr, {}}), ThrowsLoc(ThrowsLoc) { setBodyKind(BodyKind::None); setGenericParams(GenericParams); Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl; @@ -5092,6 +5097,8 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { return getBodyKind() != BodyKind::None; } + bool hasInlinableBodyText() const; + /// Returns the function body, if it was parsed, or nullptr otherwise. /// /// Note that a null return value does not imply that the source code did not @@ -5105,7 +5112,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { } if (getBodyKind() == BodyKind::Parsed || getBodyKind() == BodyKind::TypeChecked) { - return Body; + return Body.Node; } return nullptr; } @@ -5113,7 +5120,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { assert(getBodyKind() != BodyKind::Skipped && "cannot set a body if it was skipped"); - Body = S; + Body.Node = S; setBodyKind(NewBodyKind); } @@ -5157,7 +5164,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { StringRef getBodyStringRepresentation(SmallVectorImpl &scratch) const; void setBodyStringRepresentation(StringRef body) { - BodyStringRepresentation = body; + Body.StringRepresentation = body; } bool isBodyTypeChecked() const { diff --git a/include/swift/Serialization/DeclTypeRecordNodes.def b/include/swift/Serialization/DeclTypeRecordNodes.def index 4df30ac43349c..4859fbb625adb 100644 --- a/include/swift/Serialization/DeclTypeRecordNodes.def +++ b/include/swift/Serialization/DeclTypeRecordNodes.def @@ -180,6 +180,7 @@ OTHER(NORMAL_PROTOCOL_CONFORMANCE_ID, 246) OTHER(PROTOCOL_CONFORMANCE_XREF, 247) OTHER(MEMBERS, 248) OTHER(XREF, 249) +OTHER(INLINABLE_BODY_TEXT, 250) #undef RECORD #undef DECLTYPERECORDNODES_HAS_RECORD_VAL diff --git a/include/swift/Serialization/ModuleFile.h b/include/swift/Serialization/ModuleFile.h index dd656cada859e..d18457367f284 100644 --- a/include/swift/Serialization/ModuleFile.h +++ b/include/swift/Serialization/ModuleFile.h @@ -857,6 +857,9 @@ class ModuleFile /// Reads a foreign error conformance from \c DeclTypeCursor, if present. Optional maybeReadForeignErrorConvention(); + + /// Reads inlinable body text from \c DeclTypeCursor, if present. + Optional maybeReadInlinableBodyText(); }; } // end namespace swift diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index 53889dca58b67..7e3d6ed379a88 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t VERSION_MINOR = 444; // Last change: inlinable bodies +const uint16_t VERSION_MINOR = 444; // Last change: inlinable body text using DeclIDField = BCFixed<31>; @@ -979,8 +979,11 @@ namespace decls_block { BCVBR<5>, // number of parameter name components BCArray // name components, // followed by TypeID dependencies - // Trailed by its generic parameters, if any, followed by the parameter - // patterns. + // This record is trailed by: + // - its generic parameters, if any + // - its parameter patterns, + // - the foreign error convention, if any + // - inlinable bldy text, if any >; using VarLayout = BCRecordLayout< @@ -1044,6 +1047,8 @@ namespace decls_block { // - its _silgen_name, if any // - its generic parameters, if any // - body parameter patterns + // - the foreign error convention, if any + // - inlinable body text, if any >; // TODO: remove the unnecessary FuncDecl components here @@ -1073,6 +1078,8 @@ namespace decls_block { // - its _silgen_name, if any // - its generic parameters, if any // - body parameter patterns + // - the foreign error convention, if any + // - inlinable body text, if any >; using PatternBindingLayout = BCRecordLayout< @@ -1155,6 +1162,7 @@ namespace decls_block { // Trailed by: // - generic parameters, if any // - the indices pattern + // - inlinable body text, if any >; using ExtensionLayout = BCRecordLayout< @@ -1176,6 +1184,12 @@ namespace decls_block { BCFixed<1>, // implicit? BCFixed<1>, // objc? GenericEnvironmentIDField // generic environment + // This record is trailed by its inlinable body text + >; + + using InlinableBodyTextLayout = BCRecordLayout< + INLINABLE_BODY_TEXT, + BCBlob // body text >; using ParameterListLayout = BCRecordLayout< diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index e0a0932a9bc09..c773a544a47b1 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -83,8 +83,7 @@ PrintOptions PrintOptions::printTextualInterfaceFile() { result.FunctionBody = [](const ValueDecl *decl, ASTPrinter &printer) { auto AFD = dyn_cast(decl); - if (!AFD || AFD->isImplicit()) return; - if (!AFD->getBody() || AFD->getBody()->isImplicit()) return; + if (!AFD || !AFD->hasInlinableBodyText()) return; if (AFD->getResilienceExpansion() != ResilienceExpansion::Minimal) return; SmallString<128> scratch; @@ -1664,7 +1663,10 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) { } Printer << " {"; - Printer.printNewline(); + + if (PrintAccessorBody) + Printer.printNewline(); + if (PrintAbstract) { PrintAccessor(ASD->getGetter()); if (ASD->supportsMutation()) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 01b57af6e801c..5ed3a0a2b8abe 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5419,15 +5419,24 @@ void AbstractFunctionDecl::computeType(AnyFunctionType::ExtInfo info) { computeSelfDeclType(); } +bool AbstractFunctionDecl::hasInlinableBodyText() const { + if (!Body.StringRepresentation.empty()) + return true; + if (getBodyKind() != BodyKind::Parsed && + getBodyKind() != BodyKind::TypeChecked) + return false; + auto body = getBody(); + return body && !body->isImplicit(); +} + StringRef AbstractFunctionDecl::getBodyStringRepresentation( SmallVectorImpl &scratch) const { - if (!BodyStringRepresentation.empty()) - return BodyStringRepresentation; + assert(hasInlinableBodyText() && + "can't get string representation of function with no text"); + if (!Body.StringRepresentation.empty()) + return Body.StringRepresentation; auto body = getBody(); - assert(body && !body->isImplicit() && - "can't get string representation of function with implicit body"); - return extractInlinableText(getASTContext().SourceMgr, body, scratch); } diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 714e94b11d2a8..e758b58d2cba4 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2397,7 +2397,7 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter, Options.FunctionBody = [&](const ValueDecl *VD, ASTPrinter &Printer) { Printer << " {"; Printer.printNewline(); - Printer << getCodePlaceholder(); + Printer << ExtraIndent << getCodePlaceholder(); Printer.printNewline(); Printer << "}"; }; diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index dd294a09b8105..df39f92aafaed 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2837,6 +2837,9 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { if (auto errorConvention = maybeReadForeignErrorConvention()) ctor->setForeignErrorConvention(*errorConvention); + if (auto bodyText = maybeReadInlinableBodyText()) + ctor->setBodyStringRepresentation(*bodyText); + if (isImplicit) ctor->setImplicit(); ctor->setIsObjC(isObjC); @@ -3229,6 +3232,9 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { if (auto errorConvention = maybeReadForeignErrorConvention()) fn->setForeignErrorConvention(*errorConvention); + if (auto bodyText = maybeReadInlinableBodyText()) + fn->setBodyStringRepresentation(*bodyText); + fn->setOverriddenDecl(cast_or_null(overridden.get())); if (fn->getOverriddenDecl()) AddAttribute(new (ctx) OverrideAttr(SourceLoc())); @@ -3933,6 +3939,9 @@ ModuleFile::getDeclCheckedImpl(DeclID DID) { auto dtor = createDecl(SourceLoc(), DC); declOrOffset = dtor; + if (auto bodyText = maybeReadInlinableBodyText()) + dtor->setBodyStringRepresentation(*bodyText); + configureGenericEnvironment(dtor, genericEnvID); dtor->setAccess(std::max(cast(DC)->getFormalAccess(), @@ -5341,6 +5350,25 @@ decodeRawStableForeignErrorConventionKind(uint8_t kind) { } } +Optional ModuleFile::maybeReadInlinableBodyText() { + using namespace decls_block; + + SmallVector scratch; + BCOffsetRAII restoreOffset(DeclTypeCursor); + StringRef blobData; + + auto next = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + if (next.Kind != llvm::BitstreamEntry::Record) + return None; + + unsigned recKind = DeclTypeCursor.readRecord(next.ID, scratch, &blobData); + if (recKind != INLINABLE_BODY_TEXT) + return None; + + restoreOffset.reset(); + return blobData; +} + Optional ModuleFile::maybeReadForeignErrorConvention() { using namespace decls_block; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 6ac6b852791b0..38490a3dbfb81 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -898,6 +898,8 @@ void Serializer::writeBlockInfoBlock() { decls_block::GENERIC_REQUIREMENT); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::LAYOUT_REQUIREMENT); + BLOCK_RECORD_WITH_NAMESPACE(sil_block, + decls_block::INLINABLE_BODY_TEXT); BLOCK(SIL_INDEX_BLOCK); BLOCK_RECORD(sil_index_block, SIL_FUNC_NAMES); @@ -1361,6 +1363,19 @@ void Serializer::writeGenericRequirements(ArrayRef requirements, } } +void Serializer::writeInlinableBodyText(const AbstractFunctionDecl *AFD) { + using namespace decls_block; + + if (AFD->getResilienceExpansion() != swift::ResilienceExpansion::Minimal) + return; + if (!AFD->hasInlinableBodyText()) return; + SmallString<128> scratch; + auto body = AFD->getBodyStringRepresentation(scratch); + + unsigned abbrCode = DeclTypeAbbrCodes[InlinableBodyTextLayout::Code]; + InlinableBodyTextLayout::emitRecord(Out, ScratchRecord, abbrCode, body); +} + bool Serializer::writeGenericParams(const GenericParamList *genericParams) { using namespace decls_block; @@ -3235,6 +3250,8 @@ void Serializer::writeDecl(const Decl *D) { if (auto errorConvention = fn->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); + writeInlinableBodyText(fn); + break; } @@ -3292,6 +3309,8 @@ void Serializer::writeDecl(const Decl *D) { if (auto errorConvention = fn->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); + writeInlinableBodyText(fn); + break; } @@ -3444,6 +3463,9 @@ void Serializer::writeDecl(const Decl *D) { if (auto errorConvention = ctor->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); + + writeInlinableBodyText(ctor); + break; } @@ -3460,6 +3482,7 @@ void Serializer::writeDecl(const Decl *D) { dtor->isObjC(), addGenericEnvironmentRef( dtor->getGenericEnvironment())); + writeInlinableBodyText(dtor); break; } @@ -4041,6 +4064,7 @@ void Serializer::writeAllDeclsAndTypes() { registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); + registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); diff --git a/lib/Serialization/Serialization.h b/lib/Serialization/Serialization.h index 92a09861ba278..143409f8d4abe 100644 --- a/lib/Serialization/Serialization.h +++ b/lib/Serialization/Serialization.h @@ -324,6 +324,10 @@ class Serializer { /// Writes a generic parameter list. bool writeGenericParams(const GenericParamList *genericParams); + /// Writes the body text of the provided funciton, if the function is + /// inlinable and has body text. + void writeInlinableBodyText(const AbstractFunctionDecl *decl); + /// Writes a list of protocol conformances. void writeConformances(ArrayRef conformances, const std::array &abbrCodes); From ed09d4023878ba3f1da92923306c550d20cf61e4 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Mon, 10 Sep 2018 17:35:24 -0700 Subject: [PATCH 07/16] Allow parser to parse accessor bodies in interfaces --- lib/Parse/ParseDecl.cpp | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 3c904dcf4efcf..93667df9e03fb 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4203,9 +4203,10 @@ struct Parser::ParsedAccessors { } }; -static bool parseAccessorIntroducer(Parser &P, bool parsingLimitedSyntax, - DeclAttributes &Attributes, AccessorKind &Kind, - AddressorKind &addressorKind, SourceLoc &Loc) { +static bool parseAccessorIntroducer(Parser &P, DeclAttributes &Attributes, + AccessorKind &Kind, + AddressorKind &addressorKind, + SourceLoc &Loc) { bool FoundCCToken; P.parseDeclAttributeList(Attributes, FoundCCToken); @@ -4260,20 +4261,8 @@ bool Parser::parseGetSet(ParseDeclOptions Flags, // SIL mode and textual interfaces use the same syntax. // Otherwise, we have a normal var or subscript declaration and we need // parse the full complement of specifiers, along with their bodies. - bool parsingLimitedSyntax = Flags.contains(PD_InProtocol); - if (!parsingLimitedSyntax) { - switch (SF.Kind) { - case SourceFileKind::Interface: - // FIXME: Textual interfaces /can/ have inlinable code but don't have to. - case SourceFileKind::SIL: - parsingLimitedSyntax = true; - break; - case SourceFileKind::Library: - case SourceFileKind::Main: - case SourceFileKind::REPL: - break; - } - } + bool parsingLimitedSyntax = Flags.contains(PD_InProtocol) || + SF.Kind == SourceFileKind::SIL; SyntaxParsingContext AccessorListCtx(SyntaxContext, SyntaxKind::AccessorBlock); @@ -4328,7 +4317,7 @@ bool Parser::parseGetSet(ParseDeclOptions Flags, AddressorKind addressorKind = AddressorKind::NotAddressor; SourceLoc Loc; bool NotAccessor = parseAccessorIntroducer( - *this, parsingLimitedSyntax, Attributes, Kind, addressorKind, Loc); + *this, Attributes, Kind, addressorKind, Loc); if (NotAccessor) { AccessorCtx->setTransparent(); AccessorCtx.reset(); @@ -4392,6 +4381,9 @@ bool Parser::parseGetSet(ParseDeclOptions Flags, // It's okay not to have a body if there's an external asm name. if (!Tok.is(tok::l_brace)) { + // Accessors don't need bodies in textual interfaces + if (SF.Kind == SourceFileKind::Interface) + continue; // _silgen_name'd accessors don't need bodies. if (!Attributes.hasAttribute()) { diagnose(Tok, diag::expected_lbrace_accessor, From f5809a36f905e64b32e9b97fc0aa0e21e80403b4 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Mon, 10 Sep 2018 21:13:34 -0700 Subject: [PATCH 08/16] Fix some tests --- lib/AST/ASTPrinter.cpp | 8 ++++++-- test/IDE/print_ast_tc_function_bodies.swift | 4 ++-- test/ModuleInterface/inlinable-function.swift | 12 ++++++------ test/PrintAsObjC/availability-real-sdk.swift | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index c773a544a47b1..e9c2fef1a76dc 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2537,12 +2537,16 @@ void PrintAST::visitAccessorDecl(AccessorDecl *decl) { if (auto BodyFunc = Options.FunctionBody) { BodyFunc(decl, Printer); indent(); - } else if (Options.FunctionDefinitions && decl->getBody()) { + return; + } + + Printer << " {"; + if (Options.FunctionDefinitions && decl->getBody()) if (printASTNodes(decl->getBody()->getElements())) { Printer.printNewline(); indent(); } - } + Printer << "}"; } void PrintAST::visitFuncDecl(FuncDecl *decl) { diff --git a/test/IDE/print_ast_tc_function_bodies.swift b/test/IDE/print_ast_tc_function_bodies.swift index 650383c4048b1..1d256966c3ff4 100644 --- a/test/IDE/print_ast_tc_function_bodies.swift +++ b/test/IDE/print_ast_tc_function_bodies.swift @@ -37,7 +37,7 @@ struct FooStruct { instanceVar = i + j } } -// CHECK-NEXT: {{^}} subscript(i: Int, j: Int) -> Double {{{$}} +// CHECK: {{^}} subscript(i: Int, j: Int) -> Double {{{$}} // CHECK-NEXT: {{^}} get {{{$}} // CHECK-NEXT: {{^}} return {{$}} // CHECK-NEXT: {{^}} }{{$}} @@ -139,7 +139,7 @@ class InClassVar1 { if true {} } } -// CHECK-NEXT: {{^}} var instanceVar2: Int {{{$}} +// CHECK: {{^}} var instanceVar2: Int {{{$}} // CHECK-NEXT: {{^}} get {{{$}} // CHECK-NEXT: {{^}} return {{$}} // CHECK-NEXT: {{^}} }{{$}} diff --git a/test/ModuleInterface/inlinable-function.swift b/test/ModuleInterface/inlinable-function.swift index 4a64e9540635f..367ecac08e0fd 100644 --- a/test/ModuleInterface/inlinable-function.swift +++ b/test/ModuleInterface/inlinable-function.swift @@ -14,7 +14,7 @@ public struct Foo: Hashable { get { return 3 } - // CHECK-NEXT: set{{$}} + // CHECK-NEXT: set[[NEWVALUE:(\(newValue\))?]]{{$}} set { print("I am set to \(newValue)") } @@ -26,7 +26,7 @@ public struct Foo: Hashable { // CHECK: public var hasDidSet: [[INT]] { public var hasDidSet: Int { // CHECK-NEXT: @_transparent get{{$}} - // CHECK-NEXT: set{{$}} + // CHECK-NEXT: set[[NEWVALUE]]{{$}} // CHECK-NOT: didSet didSet { print("b set to \(hasDidSet)") @@ -49,7 +49,7 @@ public struct Foo: Hashable { get { return 34 } - // CHECK-NEXT: @_transparent set { + // CHECK-NEXT: @_transparent set[[NEWVALUE]] { // CHECK-NOT: #if false // CHECK-NOT: print("I should not appear") // CHECK-NOT: #else @@ -83,7 +83,7 @@ public struct Foo: Hashable { return 32 } - // CHECK: set { + // CHECK: set[[NEWVALUE]] { // CHECK-NOT: #if true // CHECK: print("I am set to \(newValue)") // CHECK-NOT: #else @@ -114,7 +114,7 @@ public struct Foo: Hashable { } - // CHECK: @_transparent mutating public func transparentMethod() { + // CHECK: @_transparent [[ATTRS:(mutating public|public mutating)]] func transparentMethod() { // CHECK-NEXT: inlinableProperty = 4 // CHECK-NEXT: } @_transparent @@ -122,7 +122,7 @@ public struct Foo: Hashable { inlinableProperty = 4 } - // CHECK: @inline(__always) mutating public func inlineAlwaysMethod() { + // CHECK: @inline(__always) [[ATTRS]] func inlineAlwaysMethod() { // CHECK-NEXT: inlinableProperty = 4 // CHECK-NEXT: } @inline(__always) diff --git a/test/PrintAsObjC/availability-real-sdk.swift b/test/PrintAsObjC/availability-real-sdk.swift index 1838cce932aa0..8e9b14f976086 100644 --- a/test/PrintAsObjC/availability-real-sdk.swift +++ b/test/PrintAsObjC/availability-real-sdk.swift @@ -46,7 +46,7 @@ // CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; // CHECK-NEXT: - (nonnull instancetype)initWithObjects:(id _Nonnull const * _Nullable)objects count:(NSUInteger)cnt OBJC_DESIGNATED_INITIALIZER; -// CHECK-NEXT: - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +// CHECK-NEXT: - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull){{[a-zA-Z]+}} OBJC_DESIGNATED_INITIALIZER; // CHECK-NEXT: @end From 9864dbecdd00c485bb52c4573cba4a9d8bfbfa0e Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Tue, 11 Sep 2018 14:34:39 -0700 Subject: [PATCH 09/16] Fix remaining tests --- include/swift/AST/Decl.h | 25 ++++++++++++++----------- lib/AST/ASTPrinter.cpp | 8 +++++++- lib/AST/ASTVerifier.cpp | 1 + lib/AST/Decl.cpp | 8 +++++--- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 32a32990d7685..144689b0b48f6 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4975,7 +4975,10 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { TypeChecked, /// This is a memberwise initializer that will be synthesized by SILGen. - MemberwiseInitializer + MemberwiseInitializer, + + /// Function body was deserialized + Deserialized // This enum currently needs to fit in a 3-bit bitfield. }; @@ -4995,13 +4998,11 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { union { /// This enum member is active if getBodyKind() is BodyKind::Parsed or /// BodyKind::TypeChecked. - struct { - /// The AST node of the body. - BraceStmt *Node; + BraceStmt *Body; - /// The string representation of the body, if anything. - StringRef StringRepresentation; - } Body; + /// This enum member is active if getBodyKind() is BodyKind::Deserialized or + /// BodyKind::TypeChecked. + StringRef BodyStringRepresentation; /// This enum member is active if getBodyKind() == BodyKind::Synthesize. BodySynthesizer Synthesizer; @@ -5024,7 +5025,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { GenericParamList *GenericParams) : GenericContext(DeclContextKind::AbstractFunctionDecl, Parent), ValueDecl(Kind, Parent, Name, NameLoc), - Body({nullptr, {}}), ThrowsLoc(ThrowsLoc) { + Body(nullptr), ThrowsLoc(ThrowsLoc) { setBodyKind(BodyKind::None); setGenericParams(GenericParams); Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl; @@ -5112,7 +5113,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { } if (getBodyKind() == BodyKind::Parsed || getBodyKind() == BodyKind::TypeChecked) { - return Body.Node; + return Body; } return nullptr; } @@ -5120,7 +5121,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { assert(getBodyKind() != BodyKind::Skipped && "cannot set a body if it was skipped"); - Body.Node = S; + Body = S; setBodyKind(NewBodyKind); } @@ -5164,7 +5165,9 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { StringRef getBodyStringRepresentation(SmallVectorImpl &scratch) const; void setBodyStringRepresentation(StringRef body) { - Body.StringRepresentation = body; + assert(getBodyKind() == BodyKind::None); + setBodyKind(BodyKind::Deserialized); + BodyStringRepresentation = body; } bool isBodyTypeChecked() const { diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index e9c2fef1a76dc..f31c32db85b20 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -1656,6 +1656,8 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) { // Omit the 'get' keyword. Directly print getter if (auto BodyFunc = Options.FunctionBody) { BodyFunc(ASD->getGetter(), Printer); + indent(); + return; } Printer.printNewline(); indent(); @@ -1716,7 +1718,10 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) { Printer << " "; Printer << "}"; - Printer.printNewline(); + + if (!PrintAbstract) + Printer.printNewline(); + indent(); } @@ -2534,6 +2539,7 @@ void PrintAST::visitAccessorDecl(AccessorDecl *decl) { } }); } + if (auto BodyFunc = Options.FunctionBody) { BodyFunc(decl, Printer); indent(); diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 7eeaf89e15dd0..268e407ef5ed2 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -492,6 +492,7 @@ class Verifier : public ASTWalker { case AbstractFunctionDecl::BodyKind::MemberwiseInitializer: return true; + case AbstractFunctionDecl::BodyKind::Deserialized: case AbstractFunctionDecl::BodyKind::Unparsed: case AbstractFunctionDecl::BodyKind::Parsed: case AbstractFunctionDecl::BodyKind::Synthesize: diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 5ed3a0a2b8abe..19f534f3880e8 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5064,6 +5064,7 @@ SourceRange AbstractFunctionDecl::getBodySourceRange() const { switch (getBodyKind()) { case BodyKind::None: case BodyKind::MemberwiseInitializer: + case BodyKind::Deserialized: return SourceRange(); case BodyKind::Parsed: @@ -5420,7 +5421,7 @@ void AbstractFunctionDecl::computeType(AnyFunctionType::ExtInfo info) { } bool AbstractFunctionDecl::hasInlinableBodyText() const { - if (!Body.StringRepresentation.empty()) + if (getBodyKind() == BodyKind::Deserialized) return true; if (getBodyKind() != BodyKind::Parsed && getBodyKind() != BodyKind::TypeChecked) @@ -5433,8 +5434,9 @@ StringRef AbstractFunctionDecl::getBodyStringRepresentation( SmallVectorImpl &scratch) const { assert(hasInlinableBodyText() && "can't get string representation of function with no text"); - if (!Body.StringRepresentation.empty()) - return Body.StringRepresentation; + + if (getBodyKind() == BodyKind::Deserialized) + return BodyStringRepresentation; auto body = getBody(); return extractInlinableText(getASTContext().SourceMgr, body, scratch); From f1a5a338145b498e87f737f9f384c21bf29a8b1d Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Tue, 11 Sep 2018 14:59:48 -0700 Subject: [PATCH 10/16] Add tests for usableFromInline decls --- test/ModuleInterface/inlinable-function.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/ModuleInterface/inlinable-function.swift b/test/ModuleInterface/inlinable-function.swift index 367ecac08e0fd..856df200b352a 100644 --- a/test/ModuleInterface/inlinable-function.swift +++ b/test/ModuleInterface/inlinable-function.swift @@ -138,3 +138,21 @@ public struct Foo: Hashable { // CHECK: {{^}}} } + +// CHECK-NOT: private func topLevelPrivate() +private func topLevelPrivate() { + print("Ssshhhhh") +} + +// CHECK: internal func topLevelUsableFromInline(){{$}} +@usableFromInline +internal func topLevelUsableFromInline() { + topLevelPrivate() +} + +// CHECK: @inlinable public func topLevelInlinable() { +// CHECK-NEXT: topLevelUsableFromInline() +// CHECK-NEXT: } +@inlinable public func topLevelInlinable() { + topLevelUsableFromInline() +} From 9344ac0575539e42c2b43a30af8aba3457967a98 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Tue, 11 Sep 2018 15:04:27 -0700 Subject: [PATCH 11/16] Add comments --- include/swift/AST/Decl.h | 12 ++++++++++-- lib/AST/ASTPrinter.cpp | 2 +- lib/AST/Decl.cpp | 2 +- lib/Serialization/Serialization.cpp | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 144689b0b48f6..ea80fd2a1742e 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4977,7 +4977,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// This is a memberwise initializer that will be synthesized by SILGen. MemberwiseInitializer, - /// Function body was deserialized + /// Function body text was deserialized from a .swiftmodule. Deserialized // This enum currently needs to fit in a 3-bit bitfield. @@ -5098,6 +5098,9 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { return getBodyKind() != BodyKind::None; } + /// Returns true if the text of this function's body can be retrieved either + /// by extracting the text from the source buffer or reading the inlinable + /// body from a deserialized swiftmodule. bool hasInlinableBodyText() const; /// Returns the function body, if it was parsed, or nullptr otherwise. @@ -5163,7 +5166,12 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { setBodyKind(BodyKind::TypeChecked); } - StringRef getBodyStringRepresentation(SmallVectorImpl &scratch) const; + /// Gets the body of this function, stripping the unused portions of #if + /// configs inside the body. If this function was not deserialized from a + /// .swiftmodule, this body is reconstructed from the original + /// source buffer. + StringRef getInlinableBodyText(SmallVectorImpl &scratch) const; + void setBodyStringRepresentation(StringRef body) { assert(getBodyKind() == BodyKind::None); setBodyKind(BodyKind::Deserialized); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index f31c32db85b20..aefddbdd8c0a4 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -87,7 +87,7 @@ PrintOptions PrintOptions::printTextualInterfaceFile() { if (AFD->getResilienceExpansion() != ResilienceExpansion::Minimal) return; SmallString<128> scratch; - printer << " " << AFD->getBodyStringRepresentation(scratch); + printer << " " << AFD->getInlinableBodyText(scratch); }; class ShouldPrintForTextualInterface : public ShouldPrintChecker { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 19f534f3880e8..888ec674bc128 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5430,7 +5430,7 @@ bool AbstractFunctionDecl::hasInlinableBodyText() const { return body && !body->isImplicit(); } -StringRef AbstractFunctionDecl::getBodyStringRepresentation( +StringRef AbstractFunctionDecl::getInlinableBodyText( SmallVectorImpl &scratch) const { assert(hasInlinableBodyText() && "can't get string representation of function with no text"); diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 38490a3dbfb81..0f1d7de987078 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -1370,7 +1370,7 @@ void Serializer::writeInlinableBodyText(const AbstractFunctionDecl *AFD) { return; if (!AFD->hasInlinableBodyText()) return; SmallString<128> scratch; - auto body = AFD->getBodyStringRepresentation(scratch); + auto body = AFD->getInlinableBodyText(scratch); unsigned abbrCode = DeclTypeAbbrCodes[InlinableBodyTextLayout::Code]; InlinableBodyTextLayout::emitRecord(Out, ScratchRecord, abbrCode, body); From 3e26b2d123588b1d83cea9949096256a891b4bf4 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Tue, 11 Sep 2018 17:01:45 -0700 Subject: [PATCH 12/16] Clean up function body printing throughout --- include/swift/AST/Decl.h | 3 +- include/swift/Serialization/ModuleFormat.h | 2 +- lib/AST/ASTPrinter.cpp | 68 ++++++++----------- .../reconstruct_type_from_mangled_name.swift | 8 +-- test/ModuleInterface/inlinable-function.swift | 58 +++++++++++++++- .../DocSupport/doc_source_file.swift.response | 16 ++--- 6 files changed, 101 insertions(+), 54 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index ea80fd2a1742e..22897dd19a4c6 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5000,8 +5000,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// BodyKind::TypeChecked. BraceStmt *Body; - /// This enum member is active if getBodyKind() is BodyKind::Deserialized or - /// BodyKind::TypeChecked. + /// This enum member is active if getBodyKind() is BodyKind::Deserialized. StringRef BodyStringRepresentation; /// This enum member is active if getBodyKind() == BodyKind::Synthesize. diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index 7e3d6ed379a88..535e54c3905f4 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -983,7 +983,7 @@ namespace decls_block { // - its generic parameters, if any // - its parameter patterns, // - the foreign error convention, if any - // - inlinable bldy text, if any + // - inlinable body text, if any >; using VarLayout = BCRecordLayout< diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index aefddbdd8c0a4..99b3928d10a1a 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -654,6 +654,7 @@ class PrintAST : public ASTVisitor { void printAttributes(const Decl *D); void printTypedPattern(const TypedPattern *TP); + void printBraceStmt(const BraceStmt *stmt, bool newlineIfEmpty = true); public: void printPattern(const Pattern *pattern); @@ -695,6 +696,7 @@ class PrintAST : public ASTVisitor { void printGenericDeclGenericParams(GenericContext *decl); void printGenericDeclGenericRequirements(GenericContext *decl); void printInherited(const Decl *decl); + void printBodyIfNecessary(const AbstractFunctionDecl *decl); void printEnumElement(EnumElementDecl *elt); @@ -1480,6 +1482,29 @@ bool PrintAST::shouldPrint(const Decl *D, bool Notify) { return Result; } +void PrintAST::printBraceStmt(const BraceStmt *stmt, bool newlineIfEmpty) { + Printer << "{"; + if (printASTNodes(stmt->getElements()) || newlineIfEmpty) { + Printer.printNewline(); + indent(); + } + Printer << "}"; +} + +void PrintAST::printBodyIfNecessary(const AbstractFunctionDecl *decl) { + if (auto BodyFunc = Options.FunctionBody) { + BodyFunc(decl, Printer); + indent(); + return; + } + + if (!Options.FunctionDefinitions || !decl->getBody()) + return; + + Printer << " "; + printBraceStmt(decl->getBody(), /*newlineIfEmpty*/!isa(decl)); +} + static bool isAccessorAssumedNonMutating(AccessorKind kind) { switch (kind) { case AccessorKind::Get: @@ -2540,19 +2565,7 @@ void PrintAST::visitAccessorDecl(AccessorDecl *decl) { }); } - if (auto BodyFunc = Options.FunctionBody) { - BodyFunc(decl, Printer); - indent(); - return; - } - - Printer << " {"; - if (Options.FunctionDefinitions && decl->getBody()) - if (printASTNodes(decl->getBody()->getElements())) { - Printer.printNewline(); - indent(); - } - Printer << "}"; + printBodyIfNecessary(decl); } void PrintAST::visitFuncDecl(FuncDecl *decl) { @@ -2624,13 +2637,7 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) { printGenericDeclGenericRequirements(decl); } - if (auto BodyFunc = Options.FunctionBody) { - BodyFunc(decl, Printer); - indent(); - } else if (Options.FunctionDefinitions && decl->getBody()) { - Printer << " "; - visit(decl->getBody()); - } + printBodyIfNecessary(decl); } void PrintAST::printEnumElement(EnumElementDecl *elt) { @@ -2799,13 +2806,7 @@ void PrintAST::visitConstructorDecl(ConstructorDecl *decl) { printGenericDeclGenericRequirements(decl); - if (auto BodyFunc = Options.FunctionBody) { - BodyFunc(decl, Printer); - indent(); - } else if (Options.FunctionDefinitions && decl->getBody()) { - Printer << " "; - visit(decl->getBody()); - } + printBodyIfNecessary(decl); } void PrintAST::visitDestructorDecl(DestructorDecl *decl) { @@ -2817,12 +2818,7 @@ void PrintAST::visitDestructorDecl(DestructorDecl *decl) { Printer << "deinit"; }); - if (!Options.FunctionDefinitions || !decl->getBody()) { - return; - } - - Printer << " "; - visit(decl->getBody()); + printBodyIfNecessary(decl); } void PrintAST::visitInfixOperatorDecl(InfixOperatorDecl *decl) { @@ -2932,11 +2928,7 @@ void PrintAST::visitMissingMemberDecl(MissingMemberDecl *decl) { } void PrintAST::visitBraceStmt(BraceStmt *stmt) { - Printer << "{"; - printASTNodes(stmt->getElements()); - Printer.printNewline(); - indent(); - Printer << "}"; + printBraceStmt(stmt); } void PrintAST::visitReturnStmt(ReturnStmt *stmt) { diff --git a/test/IDE/reconstruct_type_from_mangled_name.swift b/test/IDE/reconstruct_type_from_mangled_name.swift index bf739a038b958..5410b81226e0b 100644 --- a/test/IDE/reconstruct_type_from_mangled_name.swift +++ b/test/IDE/reconstruct_type_from_mangled_name.swift @@ -291,11 +291,11 @@ fileprivate func privateFunction(_ d: VeryPrivateData) {} struct HasSubscript { // CHECK: decl: subscript(t: Int) -> Int { get set } subscript(_ t: Int) -> Int { - // CHECK: decl: get {} for '' usr=s:14swift_ide_test12HasSubscriptVyS2icig + // CHECK: decl: get for '' usr=s:14swift_ide_test12HasSubscriptVyS2icig get { return t } - // CHECK: decl: set {} for '' usr=s:14swift_ide_test12HasSubscriptVyS2icis + // CHECK: decl: set for '' usr=s:14swift_ide_test12HasSubscriptVyS2icis set {} } } @@ -310,14 +310,14 @@ struct HasGenericSubscript { // CHECK: decl: FAILURE for 't' subscript(_ t: T) -> U { - // CHECK: decl: get {} for '' usr=s:14swift_ide_test19HasGenericSubscriptVyqd__xcluig + // CHECK: decl: get for '' usr=s:14swift_ide_test19HasGenericSubscriptVyqd__xcluig // FIXME // CHECK: dref: FAILURE for 't' get { return t as! U } - // CHECK: decl: set {} for '' usr=s:14swift_ide_test19HasGenericSubscriptVyqd__xcluis + // CHECK: decl: set for '' usr=s:14swift_ide_test19HasGenericSubscriptVyqd__xcluis set {} } } diff --git a/test/ModuleInterface/inlinable-function.swift b/test/ModuleInterface/inlinable-function.swift index 856df200b352a..d25cfba9bf778 100644 --- a/test/ModuleInterface/inlinable-function.swift +++ b/test/ModuleInterface/inlinable-function.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -o %t/Test.swiftmodule -emit-interface-path %t/Test.swiftinterface -module-name Test %s // RUN: %FileCheck %s < %t/Test.swiftinterface -// RUN: %target-swift-frontend -emit-module -o /dev/null -merge-modules %t/Test.swiftmodule -emit-interface-path - -module-name Test | %FileCheck %s +// RUN: %target-swift-frontend -emit-module -o /dev/null -merge-modules %t/Test.swiftmodule -disable-objc-attr-requires-foundation-module -emit-interface-path - -module-name Test | %FileCheck %s // CHECK: public struct Foo : Hashable { public struct Foo: Hashable { @@ -136,6 +136,25 @@ public struct Foo: Hashable { print("Not inlinable") } + // CHECK: public init(value: [[INT]]) { + // CHECK-NEXT: topLevelUsableFromInline() + // CHECK-NEXT: noAccessors = value + // CHECK-NEXT: hasDidSet = value + // CHECK-NEXT: } + @inlinable public init(value: Int) { + topLevelUsableFromInline() + noAccessors = value + hasDidSet = value + } + + // CHECK: public init(){{$}} + // CHECK-NOT: noAccessors = 0 + // CHECK-NOT: hasDidSet = 0 + public init() { + noAccessors = 0 + hasDidSet = 0 + } + // CHECK: {{^}}} } @@ -156,3 +175,40 @@ internal func topLevelUsableFromInline() { @inlinable public func topLevelInlinable() { topLevelUsableFromInline() } + +// CHECK: public class HasInlinableDeinit { +public class HasInlinableDeinit { + // CHECK: public init(){{$}} + public init() {} + + // CHECK: @objc @inlinable deinit { + // CHECK-NEXT: print("goodbye") + // CHECK-NEXT: } + @inlinable deinit { + print("goodbye") + } + + // CHECK-NEXT: } +} + +// CHECK: public class HasStandardDeinit { +public class HasStandardDeinit { + // CHECK: public init(){{$}} + public init() {} + + // CHECK: @objc deinit{{$}} + deinit { + print("goodbye") + } + + // CHECK-NEXT: } +} + +// CHECK: public class HasDefaultDeinit { +public class HasDefaultDeinit { + // CHECK: public init(){{$}} + public init() {} + + // CHECK: @objc deinit{{$}} + // CHECK-NEXT: } +} diff --git a/test/SourceKit/DocSupport/doc_source_file.swift.response b/test/SourceKit/DocSupport/doc_source_file.swift.response index ce73543feeda8..59e8f3a02ed77 100644 --- a/test/SourceKit/DocSupport/doc_source_file.swift.response +++ b/test/SourceKit/DocSupport/doc_source_file.swift.response @@ -2025,7 +2025,7 @@ key.usr: "s:4main2CCC4extVSivg", key.offset: 748, key.length: 11, - key.fully_annotated_decl: "get {}" + key.fully_annotated_decl: "get" } ] }, @@ -2069,14 +2069,14 @@ key.usr: "s:4main16ComputedPropertyC5valueSivg", key.offset: 853, key.length: 51, - key.fully_annotated_decl: "get {}" + key.fully_annotated_decl: "get" }, { key.kind: source.lang.swift.decl.function.accessor.setter, key.usr: "s:4main16ComputedPropertyC5valueSivs", key.offset: 910, key.length: 49, - key.fully_annotated_decl: "set(newVal) {}" + key.fully_annotated_decl: "set(newVal)" }, { key.kind: source.lang.swift.decl.var.instance, @@ -2089,7 +2089,7 @@ key.usr: "s:4main16ComputedPropertyC8readOnlySivg", key.offset: 987, key.length: 11, - key.fully_annotated_decl: "get {}" + key.fully_annotated_decl: "get" } ] }, @@ -2205,14 +2205,14 @@ key.usr: "s:4main3CC2CyS2icig", key.offset: 1162, key.length: 25, - key.fully_annotated_decl: "get {}" + key.fully_annotated_decl: "get" }, { key.kind: source.lang.swift.decl.function.accessor.setter, key.usr: "s:4main3CC2CyS2icis", key.offset: 1193, key.length: 31, - key.fully_annotated_decl: "set(vvv) {}" + key.fully_annotated_decl: "set(vvv)" } ] }, @@ -2269,7 +2269,7 @@ key.usr: "s:4main12globReadOnlyAA2S2Vvg", key.offset: 1449, key.length: 25, - key.fully_annotated_decl: "get {}" + key.fully_annotated_decl: "get" }, { key.kind: source.lang.swift.decl.function.free, @@ -2395,7 +2395,7 @@ { key.kind: source.lang.swift.decl.function.accessor.getter, key.usr: "s:4main5Prot2P1pSivg", - key.fully_annotated_decl: "get {}" + key.fully_annotated_decl: "get" }, { key.kind: source.lang.swift.decl.function.method.instance, From 704a33da835779c83e538943d98d117c5d5cb281 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Tue, 11 Sep 2018 18:16:08 -0700 Subject: [PATCH 13/16] Add tests for subscripts --- test/ModuleInterface/inlinable-function.swift | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/ModuleInterface/inlinable-function.swift b/test/ModuleInterface/inlinable-function.swift index d25cfba9bf778..50fc6a3ea043e 100644 --- a/test/ModuleInterface/inlinable-function.swift +++ b/test/ModuleInterface/inlinable-function.swift @@ -136,6 +136,34 @@ public struct Foo: Hashable { print("Not inlinable") } + // CHECK: public subscript(i: [[INT]]) -> [[INT]] { + // CHECK-NEXT: get{{$}} + // CHECK-NEXT: @inlinable set[[NEWVALUE]] { print("set") } + // CHECK-NEXT: } + public subscript(i: Int) -> Int { + get { return 0 } + @inlinable set { print("set") } + } + + // CHECK: public subscript(j: [[INT]], k: [[INT]]) -> [[INT]] { + // CHECK-NEXT: @inlinable get { return 0 } + // CHECK-NEXT: set[[NEWVALUE]]{{$}} + // CHECK-NEXT: } + public subscript(j: Int, k: Int) -> Int { + @inlinable get { return 0 } + set { print("set") } + } + + // CHECK: @inlinable public subscript(l: [[INT]], m: [[INT]], n: [[INT]]) -> [[INT]] { + // CHECK-NEXT: get { return 0 } + // CHECK-NEXT: set[[NEWVALUE]] { print("set") } + // CHECK-NEXT: } + @inlinable + public subscript(l: Int, m: Int, n: Int) -> Int { + get { return 0 } + set { print("set") } + } + // CHECK: public init(value: [[INT]]) { // CHECK-NEXT: topLevelUsableFromInline() // CHECK-NEXT: noAccessors = value From f1f7be54d93be4cbdf2f2cdee4d77cf58a7d251f Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Tue, 11 Sep 2018 18:39:17 -0700 Subject: [PATCH 14/16] Remove comment about subscript inlinable text --- include/swift/Serialization/ModuleFormat.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index 535e54c3905f4..6646dc9d77d06 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -1162,7 +1162,6 @@ namespace decls_block { // Trailed by: // - generic parameters, if any // - the indices pattern - // - inlinable body text, if any >; using ExtensionLayout = BCRecordLayout< From f5e91acffa4fcd29ad05f4310ff792138c7570fa Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Tue, 11 Sep 2018 18:51:37 -0700 Subject: [PATCH 15/16] Address some comments --- lib/AST/ASTVerifier.cpp | 2 +- lib/AST/Decl.cpp | 16 +++++++++++----- lib/Serialization/Serialization.cpp | 14 ++++++-------- lib/Serialization/Serialization.h | 2 +- test/ModuleInterface/inlinable-function.swift | 9 ++++++--- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 268e407ef5ed2..ae1adc72a856b 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -490,9 +490,9 @@ class Verifier : public ASTWalker { case AbstractFunctionDecl::BodyKind::TypeChecked: case AbstractFunctionDecl::BodyKind::Skipped: case AbstractFunctionDecl::BodyKind::MemberwiseInitializer: + case AbstractFunctionDecl::BodyKind::Deserialized: return true; - case AbstractFunctionDecl::BodyKind::Deserialized: case AbstractFunctionDecl::BodyKind::Unparsed: case AbstractFunctionDecl::BodyKind::Parsed: case AbstractFunctionDecl::BodyKind::Synthesize: diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 888ec674bc128..1c13a98e01b13 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5421,13 +5421,19 @@ void AbstractFunctionDecl::computeType(AnyFunctionType::ExtInfo info) { } bool AbstractFunctionDecl::hasInlinableBodyText() const { - if (getBodyKind() == BodyKind::Deserialized) + switch (getBodyKind()) { + case BodyKind::Deserialized: return true; - if (getBodyKind() != BodyKind::Parsed && - getBodyKind() != BodyKind::TypeChecked) + case BodyKind::Parsed: + case BodyKind::TypeChecked: + return getBody() && !getBody()->isImplicit(); + case BodyKind::None: + case BodyKind::Unparsed: + case BodyKind::Synthesize: + case BodyKind::Skipped: + case BodyKind::MemberwiseInitializer: return false; - auto body = getBody(); - return body && !body->isImplicit(); + } } StringRef AbstractFunctionDecl::getInlinableBodyText( diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 0f1d7de987078..e1d1b5d6900a6 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -898,8 +898,6 @@ void Serializer::writeBlockInfoBlock() { decls_block::GENERIC_REQUIREMENT); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::LAYOUT_REQUIREMENT); - BLOCK_RECORD_WITH_NAMESPACE(sil_block, - decls_block::INLINABLE_BODY_TEXT); BLOCK(SIL_INDEX_BLOCK); BLOCK_RECORD(sil_index_block, SIL_FUNC_NAMES); @@ -1363,7 +1361,8 @@ void Serializer::writeGenericRequirements(ArrayRef requirements, } } -void Serializer::writeInlinableBodyText(const AbstractFunctionDecl *AFD) { +void Serializer::writeInlinableBodyTextIfNeeded( + const AbstractFunctionDecl *AFD) { using namespace decls_block; if (AFD->getResilienceExpansion() != swift::ResilienceExpansion::Minimal) @@ -3250,7 +3249,7 @@ void Serializer::writeDecl(const Decl *D) { if (auto errorConvention = fn->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); - writeInlinableBodyText(fn); + writeInlinableBodyTextIfNeeded(fn); break; } @@ -3309,7 +3308,7 @@ void Serializer::writeDecl(const Decl *D) { if (auto errorConvention = fn->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); - writeInlinableBodyText(fn); + writeInlinableBodyTextIfNeeded(fn); break; } @@ -3464,8 +3463,7 @@ void Serializer::writeDecl(const Decl *D) { if (auto errorConvention = ctor->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); - writeInlinableBodyText(ctor); - + writeInlinableBodyTextIfNeeded(ctor); break; } @@ -3482,7 +3480,7 @@ void Serializer::writeDecl(const Decl *D) { dtor->isObjC(), addGenericEnvironmentRef( dtor->getGenericEnvironment())); - writeInlinableBodyText(dtor); + writeInlinableBodyTextIfNeeded(dtor); break; } diff --git a/lib/Serialization/Serialization.h b/lib/Serialization/Serialization.h index 143409f8d4abe..ff401b43fc032 100644 --- a/lib/Serialization/Serialization.h +++ b/lib/Serialization/Serialization.h @@ -326,7 +326,7 @@ class Serializer { /// Writes the body text of the provided funciton, if the function is /// inlinable and has body text. - void writeInlinableBodyText(const AbstractFunctionDecl *decl); + void writeInlinableBodyTextIfNeeded(const AbstractFunctionDecl *decl); /// Writes a list of protocol conformances. void writeConformances(ArrayRef conformances, diff --git a/test/ModuleInterface/inlinable-function.swift b/test/ModuleInterface/inlinable-function.swift index 50fc6a3ea043e..882f9202a2391 100644 --- a/test/ModuleInterface/inlinable-function.swift +++ b/test/ModuleInterface/inlinable-function.swift @@ -18,6 +18,7 @@ public struct Foo: Hashable { set { print("I am set to \(newValue)") } + // CHECK-NEXT: {{^}} } } // CHECK: public var noAccessors: [[INT]]{{$}} @@ -31,13 +32,13 @@ public struct Foo: Hashable { didSet { print("b set to \(hasDidSet)") } - // CHECK-NEXT: } + // CHECK-NEXT: {{^}} } } // CHECK: @_transparent public var transparent: [[INT]] { - // CHECK: return 34 - // CHECK: } + // CHECK-NEXT: return 34 + // CHECK-NEXT: } @_transparent public var transparent: Int { return 34 @@ -59,6 +60,7 @@ public struct Foo: Hashable { // CHECK: print("I am set to \(newValue)") // CHECK-NOT: #endif // CHECK-NOT: #endif + // CHECK-NEXT: } @_transparent set { #if false @@ -97,6 +99,7 @@ public struct Foo: Hashable { print("I should not appear") #endif } + // CHECK-NEXT: } } // CHECK: @inlinable public func inlinableMethod() { From 23a70311fe26a62e764d6646c191d1f9c46c3c44 Mon Sep 17 00:00:00 2001 From: Harlan Date: Tue, 11 Sep 2018 20:51:57 -0700 Subject: [PATCH 16/16] Handle lack of @objc on Linux --- test/ModuleInterface/inlinable-function.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/ModuleInterface/inlinable-function.swift b/test/ModuleInterface/inlinable-function.swift index 882f9202a2391..86736f008c535 100644 --- a/test/ModuleInterface/inlinable-function.swift +++ b/test/ModuleInterface/inlinable-function.swift @@ -212,7 +212,7 @@ public class HasInlinableDeinit { // CHECK: public init(){{$}} public init() {} - // CHECK: @objc @inlinable deinit { + // CHECK: [[OBJC:(@objc )?]]@inlinable deinit { // CHECK-NEXT: print("goodbye") // CHECK-NEXT: } @inlinable deinit { @@ -227,7 +227,7 @@ public class HasStandardDeinit { // CHECK: public init(){{$}} public init() {} - // CHECK: @objc deinit{{$}} + // CHECK: [[OBJC]]deinit{{$}} deinit { print("goodbye") } @@ -240,6 +240,6 @@ public class HasDefaultDeinit { // CHECK: public init(){{$}} public init() {} - // CHECK: @objc deinit{{$}} + // CHECK: [[OBJC]]deinit{{$}} // CHECK-NEXT: } }