Skip to content

Clang function types v2: Electric Boogaloo (parsing + printing) #28737

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/AST/ASTPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define SWIFT_AST_ASTPRINTER_H

#include "swift/Basic/LLVM.h"
#include "swift/Basic/QuotedString.h"
#include "swift/Basic/UUID.h"
#include "swift/AST/Identifier.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -185,6 +186,8 @@ class ASTPrinter {
return *this;
}

ASTPrinter &operator<<(QuotedString s);

ASTPrinter &operator<<(unsigned long long N);
ASTPrinter &operator<<(UUID UU);

Expand Down
11 changes: 11 additions & 0 deletions include/swift/AST/ClangModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class CompilerInstance;
class Preprocessor;
class Sema;
class TargetInfo;
class Type;
} // namespace clang

namespace swift {
Expand Down Expand Up @@ -100,6 +101,16 @@ class ClangModuleLoader : public ModuleLoader {
lookupRelatedEntity(StringRef clangName, ClangTypeKind kind,
StringRef relatedEntityKind,
llvm::function_ref<void(TypeDecl *)> receiver) = 0;

/// Try to parse the string as a Clang function type.
///
/// Returns null if there was a parsing failure.
virtual const clang::Type *parseClangFunctionType(StringRef type,
SourceLoc loc) const = 0;

/// Print the Clang type.
virtual void printClangType(const clang::Type *type,
llvm::raw_ostream &os) const = 0;
};

} // namespace swift
Expand Down
7 changes: 7 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -3924,6 +3924,13 @@ ERROR(unsupported_convention,none,
"convention '%0' not supported", (StringRef))
ERROR(unreferenced_generic_parameter,none,
"generic parameter '%0' is not used in function signature", (StringRef))
ERROR(unexpected_ctype_for_non_c_convention,none,
"convention '%0' does not support the 'cType' argument label, did you "
"mean @convention(c, cType: \"%1\") or @convention(block, cType: \"%1\") "
"instead?", (StringRef, StringRef))
ERROR(unable_to_parse_c_function_type,none,
"unable to parse '%0'; it should be a C function pointer type or a "
"block pointer type", (StringRef))

// Opaque types
ERROR(unsupported_opaque_type,none,
Expand Down
21 changes: 18 additions & 3 deletions include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,8 +306,21 @@ struct PrintOptions {
/// List of decls that should be printed even if they are implicit and \c SkipImplicit is set to true.
std::vector<const Decl*> TreatAsExplicitDeclList;

enum class FunctionRepresentationMode : uint8_t {
/// Print the entire convention, including an arguments.
/// For example, this will print a cType argument label if applicable.
Full,
/// Print only the name of the convention, skipping extra argument labels.
NameOnly,
/// Skip printing the @convention(..) altogether.
None
};

/// Whether to print function @convention attribute on function types.
bool PrintFunctionRepresentationAttrs = true;
// FIXME: [clang-function-type-serialization] Once we start serializing Clang
// types, we should also start printing the full type in the swiftinterface.
FunctionRepresentationMode PrintFunctionRepresentationAttrs =
FunctionRepresentationMode::NameOnly;

/// Whether to print storage representation attributes on types, e.g.
/// '@sil_weak', '@sil_unmanaged'.
Expand Down Expand Up @@ -502,7 +515,8 @@ struct PrintOptions {
/// consistent and well-formed.
///
/// \see swift::emitSwiftInterface
static PrintOptions printSwiftInterfaceFile(bool preferTypeRepr);
static PrintOptions printSwiftInterfaceFile(bool preferTypeRepr,
bool printFullConvention);

/// Retrieve the set of options suitable for "Generated Interfaces", which
/// are a prettified representation of the public API of a module, to be
Expand Down Expand Up @@ -585,7 +599,8 @@ struct PrintOptions {
PO.SkipUnderscoredKeywords = true;
PO.EnumRawValues = EnumRawValueMode::Print;
PO.PrintImplicitAttrs = false;
PO.PrintFunctionRepresentationAttrs = false;
PO.PrintFunctionRepresentationAttrs =
PrintOptions::FunctionRepresentationMode::None;
PO.PrintDocumentationComments = false;
PO.ExcludeAttrList.push_back(DAK_Available);
PO.SkipPrivateStdlibDecls = true;
Expand Down
16 changes: 16 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class AssociatedTypeDecl;
class ASTContext;
enum BufferPointerTypeKind : unsigned;
class ClassDecl;
class ClangModuleLoader;
class DependentMemberType;
class GenericTypeParamDecl;
class GenericTypeParamType;
Expand Down Expand Up @@ -2950,6 +2951,11 @@ class AnyFunctionType : public TypeBase {

bool empty() const { return !ClangFunctionType; }
Uncommon(const clang::Type *type) : ClangFunctionType(type) {}

public:
/// Use the ClangModuleLoader to print the Clang type as a string.
void printClangFunctionType(ClangModuleLoader *cml,
llvm::raw_ostream &os);
};

private:
Expand Down Expand Up @@ -3894,6 +3900,11 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,

bool empty() const { return !ClangFunctionType; }
Uncommon(const clang::FunctionType *type) : ClangFunctionType(type) {}

public:
/// Analog of AnyFunctionType::ExtInfo::Uncommon::printClangFunctionType.
void printClangFunctionType(ClangModuleLoader *cml,
llvm::raw_ostream &os) const;
};

Uncommon Other;
Expand Down Expand Up @@ -3947,6 +3958,11 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
return getSILFunctionLanguage(getRepresentation());
}

/// Return the underlying Uncommon value if it is not the default value.
Optional<Uncommon> getUncommonInfo() const {
return Other.empty() ? Optional<Uncommon>() : Other;
}

bool hasSelfParam() const {
switch (getRepresentation()) {
case Representation::Thick:
Expand Down
6 changes: 6 additions & 0 deletions include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace clang {
class NamedDecl;
class Sema;
class TargetInfo;
class Type;
class VisibleDeclConsumer;
class DeclarationName;
}
Expand Down Expand Up @@ -416,6 +417,11 @@ class ClangImporter final : public ClangModuleLoader {
/// with -import-objc-header option.
getPCHFilename(const ClangImporterOptions &ImporterOptions,
StringRef SwiftPCHHash, bool &isExplicit);

const clang::Type *parseClangFunctionType(StringRef type,
SourceLoc loc) const override;
void printClangType(const clang::Type *type,
llvm::raw_ostream &os) const override;
};

ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Frontend/ModuleInterfaceSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ struct ModuleInterfaceOptions {
/// interface, or should we fully-qualify them?
bool PreserveTypesAsWritten = false;

/// Should we emit the cType when printing @convention(c) or no?
/// FIXME: [clang-function-type-serialization] This check should go away.
bool PrintFullConvention = false;

/// Copy of all the command-line flags passed at .swiftinterface
/// generation time, re-applied to CompilerInvocation when reading
/// back .swiftinterface and reconstructing .swiftmodule.
Expand Down
5 changes: 5 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,11 @@ def module_interface_preserve_types_as_written :
HelpText<"When emitting a module interface, preserve types as they were "
"written in the source">;

def experimental_print_full_convention :
Flag<["-"], "experimental-print-full-convention">,
HelpText<"When emitting a module interface, emit additional @convention "
"arguments, regardless of whether they were written in the source">;

def prebuilt_module_cache_path :
Separate<["-"], "prebuilt-module-cache-path">,
HelpText<"Directory of prebuilt modules for loading module interfaces">;
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3156,6 +3156,11 @@ ArrayRef<Requirement> GenericFunctionType::getRequirements() const {
return Signature->getRequirements();
}

void SILFunctionType::ExtInfo::Uncommon::printClangFunctionType(
ClangModuleLoader *cml, llvm::raw_ostream &os) const {
cml->printClangType(ClangFunctionType, os);
}

void SILFunctionType::Profile(
llvm::FoldingSetNodeID &id,
GenericSignature genericParams,
Expand Down
76 changes: 64 additions & 12 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "swift/AST/ASTMangler.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/Attr.h"
#include "swift/AST/ClangModuleLoader.h"
#include "swift/AST/Comment.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
Expand Down Expand Up @@ -98,7 +99,8 @@ static bool contributesToParentTypeStorage(const AbstractStorageDecl *ASD) {
return !ND->isResilient() && ASD->hasStorage() && !ASD->isStatic();
}

PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr) {
PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr,
bool printFullConvention) {
PrintOptions result;
result.PrintLongAttrsOnSeparateLines = true;
result.TypeDefinitions = true;
Expand All @@ -115,6 +117,9 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr) {
result.OpaqueReturnTypePrinting =
OpaqueReturnTypePrintingMode::StableReference;
result.PreferTypeRepr = preferTypeRepr;
if (printFullConvention)
result.PrintFunctionRepresentationAttrs =
PrintOptions::FunctionRepresentationMode::Full;

// We should print __consuming, __owned, etc for the module interface file.
result.SkipUnderscoredKeywords = false;
Expand Down Expand Up @@ -321,6 +326,14 @@ void ASTPrinter::callPrintDeclPre(const Decl *D,
printDeclPre(D, Bracket);
}

ASTPrinter &ASTPrinter::operator<<(QuotedString s) {
llvm::SmallString<32> Str;
llvm::raw_svector_ostream OS(Str);
OS << s;
printTextImpl(OS.str());
return *this;
}

ASTPrinter &ASTPrinter::operator<<(unsigned long long N) {
llvm::SmallString<32> Str;
llvm::raw_svector_ostream OS(Str);
Expand Down Expand Up @@ -3462,6 +3475,15 @@ void Pattern::print(llvm::raw_ostream &OS, const PrintOptions &Options) const {
// Type Printing
//===----------------------------------------------------------------------===//

template <typename ExtInfo>
void printCType(ASTContext &Ctx, ASTPrinter &Printer, ExtInfo &info) {
auto *cml = Ctx.getClangModuleLoader();
SmallString<64> buf;
llvm::raw_svector_ostream os(buf);
info.getUncommonInfo().getValue().printClangFunctionType(cml, os);
Printer << ", cType: " << QuotedString(os.str());
}

namespace {
class TypePrinter : public TypeVisitor<TypePrinter> {
using super = TypeVisitor;
Expand Down Expand Up @@ -3824,7 +3846,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
visit(staticSelfT);
}

void printFunctionExtInfo(AnyFunctionType::ExtInfo info) {
void printFunctionExtInfo(ASTContext &Ctx, AnyFunctionType::ExtInfo info) {
if (Options.SkipAttributes)
return;

Expand All @@ -3837,9 +3859,18 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
}
}

if (Options.PrintFunctionRepresentationAttrs &&
!Options.excludeAttrKind(TAK_convention) &&
info.getSILRepresentation() != SILFunctionType::Representation::Thick) {
SmallString<64> buf;
switch (Options.PrintFunctionRepresentationAttrs) {
case PrintOptions::FunctionRepresentationMode::None:
return;
case PrintOptions::FunctionRepresentationMode::Full:
case PrintOptions::FunctionRepresentationMode::NameOnly:
if (Options.excludeAttrKind(TAK_convention) ||
info.getSILRepresentation() == SILFunctionType::Representation::Thick)
return;

bool printNameOnly = Options.PrintFunctionRepresentationAttrs ==
PrintOptions::FunctionRepresentationMode::NameOnly;
Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute);
Printer.printAttrName("@convention");
Printer << "(";
Expand All @@ -3855,6 +3886,11 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
break;
case SILFunctionType::Representation::CFunctionPointer:
Printer << "c";
// FIXME: [clang-function-type-serialization] Once we start serializing
// Clang function types, we should be able to remove the second check.
if (printNameOnly || !info.getUncommonInfo().hasValue())
break;
printCType(Ctx, Printer, info);
break;
case SILFunctionType::Representation::Method:
Printer << "method";
Expand All @@ -3875,7 +3911,8 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
}
}

void printFunctionExtInfo(SILFunctionType::ExtInfo info,
void printFunctionExtInfo(ASTContext &Ctx,
SILFunctionType::ExtInfo info,
ProtocolConformanceRef witnessMethodConformance) {
if (Options.SkipAttributes)
return;
Expand All @@ -3889,9 +3926,19 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
}
}

if (Options.PrintFunctionRepresentationAttrs &&
!Options.excludeAttrKind(TAK_convention) &&
info.getRepresentation() != SILFunctionType::Representation::Thick) {

SmallString<64> buf;
switch (Options.PrintFunctionRepresentationAttrs) {
case PrintOptions::FunctionRepresentationMode::None:
break;
case PrintOptions::FunctionRepresentationMode::NameOnly:
case PrintOptions::FunctionRepresentationMode::Full:
if (Options.excludeAttrKind(TAK_convention) ||
info.getRepresentation() == SILFunctionType::Representation::Thick)
break;

bool printNameOnly = Options.PrintFunctionRepresentationAttrs ==
PrintOptions::FunctionRepresentationMode::NameOnly;
Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute);
Printer.printAttrName("@convention");
Printer << "(";
Expand All @@ -3906,6 +3953,11 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
break;
case SILFunctionType::Representation::CFunctionPointer:
Printer << "c";
// FIXME: [clang-function-type-serialization] Once we start serializing
// Clang function types, we should be able to remove the second check.
if (printNameOnly || !info.getUncommonInfo().hasValue())
break;
printCType(Ctx, Printer, info);
break;
case SILFunctionType::Representation::Method:
Printer << "method";
Expand Down Expand Up @@ -3975,7 +4027,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
Printer.printStructurePost(PrintStructureKind::FunctionType);
};

printFunctionExtInfo(T->getExtInfo());
printFunctionExtInfo(T->getASTContext(), T->getExtInfo());

// If we're stripping argument labels from types, do it when printing.
visitAnyFunctionTypeParams(T->getParams(), /*printLabels*/false);
Expand Down Expand Up @@ -4012,7 +4064,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
Printer.printStructurePost(PrintStructureKind::FunctionType);
};

printFunctionExtInfo(T->getExtInfo());
printFunctionExtInfo(T->getASTContext(), T->getExtInfo());
printGenericSignature(T->getGenericSignature(),
PrintAST::PrintParams |
PrintAST::PrintRequirements);
Expand Down Expand Up @@ -4065,7 +4117,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {

void visitSILFunctionType(SILFunctionType *T) {
printSILCoroutineKind(T->getCoroutineKind());
printFunctionExtInfo(T->getExtInfo(),
printFunctionExtInfo(T->getASTContext(), T->getExtInfo(),
T->getWitnessMethodConformanceOrInvalid());
printCalleeConvention(T->getCalleeConvention());

Expand Down
6 changes: 6 additions & 0 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "swift/AST/Types.h"
#include "ForeignRepresentationInfo.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ClangModuleLoader.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/ReferenceCounting.h"
#include "swift/AST/TypeCheckRequests.h"
Expand Down Expand Up @@ -3239,6 +3240,11 @@ Type ProtocolCompositionType::get(const ASTContext &C,
return build(C, CanTypes, HasExplicitAnyObject);
}

void AnyFunctionType::ExtInfo::Uncommon::printClangFunctionType(
ClangModuleLoader *cml, llvm::raw_ostream &os) {
cml->printClangType(ClangFunctionType, os);
}

void
AnyFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) {
#ifndef NDEBUG
Expand Down
Loading