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
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
@@ -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"
@@ -185,6 +186,8 @@ class ASTPrinter {
return *this;
}

ASTPrinter &operator<<(QuotedString s);

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

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

namespace swift {
@@ -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
7 changes: 7 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
@@ -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,
21 changes: 18 additions & 3 deletions include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
@@ -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'.
@@ -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
@@ -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;
16 changes: 16 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
@@ -59,6 +59,7 @@ class AssociatedTypeDecl;
class ASTContext;
enum BufferPointerTypeKind : unsigned;
class ClassDecl;
class ClangModuleLoader;
class DependentMemberType;
class GenericTypeParamDecl;
class GenericTypeParamType;
@@ -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:
@@ -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;
@@ -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:
6 changes: 6 additions & 0 deletions include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ namespace clang {
class NamedDecl;
class Sema;
class TargetInfo;
class Type;
class VisibleDeclConsumer;
class DeclarationName;
}
@@ -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,
4 changes: 4 additions & 0 deletions include/swift/Frontend/ModuleInterfaceSupport.h
Original file line number Diff line number Diff line change
@@ -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.
5 changes: 5 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
@@ -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">;
5 changes: 5 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
@@ -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,
76 changes: 64 additions & 12 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
@@ -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"
@@ -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;
@@ -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;
@@ -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);
@@ -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;
@@ -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;

@@ -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 << "(";
@@ -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";
@@ -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;
@@ -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 << "(";
@@ -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";
@@ -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);
@@ -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);
@@ -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());

6 changes: 6 additions & 0 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
@@ -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"
@@ -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
Loading