mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
ASTDemangler: Add support for lowered function types
This commit is contained in:
@@ -82,6 +82,13 @@ public:
|
||||
Type createFunctionType(ArrayRef<Demangle::FunctionParam<Type>> params,
|
||||
Type output, FunctionTypeFlags flags);
|
||||
|
||||
Type createImplFunctionType(
|
||||
Demangle::ImplParameterConvention calleeConvention,
|
||||
ArrayRef<Demangle::ImplFunctionParam<Type>> params,
|
||||
ArrayRef<Demangle::ImplFunctionResult<Type>> results,
|
||||
Optional<Demangle::ImplFunctionResult<Type>> errorResult,
|
||||
ImplFunctionTypeFlags flags);
|
||||
|
||||
Type createProtocolCompositionType(ArrayRef<ProtocolDecl *> protocols,
|
||||
Type superclass,
|
||||
bool isClassBound);
|
||||
|
||||
@@ -77,6 +77,147 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum class ImplParameterConvention {
|
||||
Indirect_In,
|
||||
Indirect_In_Constant,
|
||||
Indirect_In_Guaranteed,
|
||||
Indirect_Inout,
|
||||
Indirect_InoutAliasable,
|
||||
Direct_Owned,
|
||||
Direct_Unowned,
|
||||
Direct_Guaranteed,
|
||||
};
|
||||
|
||||
/// Describe a lowered function parameter, parameterized on the type
|
||||
/// representation.
|
||||
template <typename BuiltType>
|
||||
class ImplFunctionParam {
|
||||
ImplParameterConvention Convention;
|
||||
BuiltType Type;
|
||||
|
||||
public:
|
||||
using ConventionType = ImplParameterConvention;
|
||||
|
||||
static Optional<ConventionType>
|
||||
getConventionFromString(StringRef conventionString) {
|
||||
if (conventionString == "@in")
|
||||
return ConventionType::Indirect_In;
|
||||
if (conventionString == "@indirect_in_constant")
|
||||
return ConventionType::Indirect_In_Constant;
|
||||
if (conventionString == "@in_guaranteed")
|
||||
return ConventionType::Indirect_In_Guaranteed;
|
||||
if (conventionString == "@inout")
|
||||
return ConventionType::Indirect_Inout;
|
||||
if (conventionString == "@inout_aliasable")
|
||||
return ConventionType::Indirect_InoutAliasable;
|
||||
if (conventionString == "@owned")
|
||||
return ConventionType::Direct_Owned;
|
||||
if (conventionString == "@unowned")
|
||||
return ConventionType::Direct_Unowned;
|
||||
if (conventionString == "@guaranteed")
|
||||
return ConventionType::Direct_Guaranteed;
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
ImplFunctionParam(ImplParameterConvention convention, BuiltType type)
|
||||
: Convention(convention), Type(type) {}
|
||||
|
||||
ImplParameterConvention getConvention() const { return Convention; }
|
||||
|
||||
BuiltType getType() const { return Type; }
|
||||
};
|
||||
|
||||
enum class ImplResultConvention {
|
||||
Indirect,
|
||||
Owned,
|
||||
Unowned,
|
||||
UnownedInnerPointer,
|
||||
Autoreleased,
|
||||
};
|
||||
|
||||
/// Describe a lowered function result, parameterized on the type
|
||||
/// representation.
|
||||
template <typename BuiltType>
|
||||
class ImplFunctionResult {
|
||||
ImplResultConvention Convention;
|
||||
BuiltType Type;
|
||||
|
||||
public:
|
||||
using ConventionType = ImplResultConvention;
|
||||
|
||||
static Optional<ConventionType>
|
||||
getConventionFromString(StringRef conventionString) {
|
||||
if (conventionString == "@out")
|
||||
return ConventionType::Indirect;
|
||||
if (conventionString == "@owned")
|
||||
return ConventionType::Owned;
|
||||
if (conventionString == "@unowned")
|
||||
return ConventionType::Unowned;
|
||||
if (conventionString == "@unowned_inner_pointer")
|
||||
return ConventionType::UnownedInnerPointer;
|
||||
if (conventionString == "@autoreleased")
|
||||
return ConventionType::Autoreleased;
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
ImplFunctionResult(ImplResultConvention convention, BuiltType type)
|
||||
: Convention(convention), Type(type) {}
|
||||
|
||||
ImplResultConvention getConvention() const { return Convention; }
|
||||
|
||||
BuiltType getType() const { return Type; }
|
||||
};
|
||||
|
||||
enum class ImplFunctionRepresentation {
|
||||
Thick,
|
||||
Block,
|
||||
Thin,
|
||||
CFunctionPointer,
|
||||
Method,
|
||||
ObjCMethod,
|
||||
WitnessMethod,
|
||||
Closure
|
||||
};
|
||||
|
||||
class ImplFunctionTypeFlags {
|
||||
unsigned Rep : 3;
|
||||
unsigned Pseudogeneric : 1;
|
||||
unsigned Escaping : 1;
|
||||
|
||||
public:
|
||||
ImplFunctionTypeFlags() : Rep(0), Pseudogeneric(0), Escaping(0) {}
|
||||
|
||||
ImplFunctionTypeFlags(ImplFunctionRepresentation rep,
|
||||
bool pseudogeneric, bool noescape)
|
||||
: Rep(unsigned(rep)), Pseudogeneric(pseudogeneric), Escaping(noescape) {}
|
||||
|
||||
ImplFunctionTypeFlags
|
||||
withRepresentation(ImplFunctionRepresentation rep) const {
|
||||
return ImplFunctionTypeFlags(rep, Pseudogeneric, Escaping);
|
||||
}
|
||||
|
||||
ImplFunctionTypeFlags
|
||||
withEscaping() const {
|
||||
return ImplFunctionTypeFlags(ImplFunctionRepresentation(Rep),
|
||||
Pseudogeneric, true);
|
||||
}
|
||||
|
||||
ImplFunctionTypeFlags
|
||||
withPseudogeneric() const {
|
||||
return ImplFunctionTypeFlags(ImplFunctionRepresentation(Rep),
|
||||
true, Escaping);
|
||||
}
|
||||
|
||||
ImplFunctionRepresentation getRepresentation() const {
|
||||
return ImplFunctionRepresentation(Rep);
|
||||
}
|
||||
|
||||
bool isEscaping() const { return Escaping; }
|
||||
|
||||
bool isPseudogeneric() const { return Pseudogeneric; }
|
||||
};
|
||||
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
/// For a mangled node that refers to an Objective-C class or protocol,
|
||||
@@ -391,12 +532,11 @@ class TypeDecoder {
|
||||
return Builder.createFunctionType(parameters, result, flags);
|
||||
}
|
||||
case NodeKind::ImplFunctionType: {
|
||||
// Minimal support for lowered function types. These come up in
|
||||
// reflection as capture types. For the reflection library's
|
||||
// purposes, the only part that matters is the convention.
|
||||
//
|
||||
// TODO: Do we want to reflect @escaping?
|
||||
FunctionTypeFlags flags;
|
||||
auto calleeConvention = ImplParameterConvention::Direct_Unowned;
|
||||
std::vector<ImplFunctionParam<BuiltType>> parameters;
|
||||
std::vector<ImplFunctionResult<BuiltType>> results;
|
||||
std::vector<ImplFunctionResult<BuiltType>> errorResults;
|
||||
ImplFunctionTypeFlags flags;
|
||||
|
||||
for (unsigned i = 0; i < Node->getNumChildren(); i++) {
|
||||
auto child = Node->getChild(i);
|
||||
@@ -407,7 +547,9 @@ class TypeDecoder {
|
||||
|
||||
if (child->getText() == "@convention(thin)") {
|
||||
flags =
|
||||
flags.withConvention(FunctionMetadataConvention::Thin);
|
||||
flags.withRepresentation(ImplFunctionRepresentation::Thin);
|
||||
} else if (child->getText() == "@callee_guaranteed") {
|
||||
calleeConvention = ImplParameterConvention::Direct_Guaranteed;
|
||||
}
|
||||
} else if (child->getKind() == NodeKind::ImplFunctionAttribute) {
|
||||
if (!child->hasText())
|
||||
@@ -416,24 +558,46 @@ class TypeDecoder {
|
||||
StringRef text = child->getText();
|
||||
if (text == "@convention(c)") {
|
||||
flags =
|
||||
flags.withConvention(FunctionMetadataConvention::CFunctionPointer);
|
||||
flags.withRepresentation(ImplFunctionRepresentation::CFunctionPointer);
|
||||
} else if (text == "@convention(block)") {
|
||||
flags =
|
||||
flags.withConvention(FunctionMetadataConvention::Block);
|
||||
flags.withRepresentation(ImplFunctionRepresentation::Block);
|
||||
}
|
||||
} else if (child->getKind() == NodeKind::ImplEscaping) {
|
||||
flags = flags.withEscaping(true);
|
||||
flags = flags.withEscaping();
|
||||
} else if (child->getKind() == NodeKind::ImplParameter) {
|
||||
if (decodeImplFunctionPart(child, parameters))
|
||||
return BuiltType();
|
||||
} else if (child->getKind() == NodeKind::ImplResult) {
|
||||
if (decodeImplFunctionPart(child, results))
|
||||
return BuiltType();
|
||||
} else if (child->getKind() == NodeKind::ImplErrorResult) {
|
||||
if (decodeImplFunctionPart(child, errorResults))
|
||||
return BuiltType();
|
||||
} else {
|
||||
return BuiltType();
|
||||
}
|
||||
}
|
||||
|
||||
// Completely punt on argument types and results.
|
||||
std::vector<FunctionParam<BuiltType>> parameters;
|
||||
Optional<ImplFunctionResult<BuiltType>> errorResult;
|
||||
switch (errorResults.size()) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
errorResult = errorResults.front();
|
||||
break;
|
||||
default:
|
||||
return BuiltType();
|
||||
}
|
||||
|
||||
std::vector<BuiltType> elements;
|
||||
std::string labels;
|
||||
auto result = Builder.createTupleType(elements, std::move(labels), false);
|
||||
|
||||
return Builder.createFunctionType(parameters, result, flags);
|
||||
// TODO: Some cases not handled above, but *probably* they cannot
|
||||
// appear as the types of values in SIL (yet?):
|
||||
// - functions with yield returns
|
||||
// - functions with generic signatures
|
||||
// - foreign error conventions
|
||||
return Builder.createImplFunctionType(calleeConvention,
|
||||
parameters, results,
|
||||
errorResult, flags);
|
||||
}
|
||||
|
||||
case NodeKind::ArgumentTuple:
|
||||
@@ -577,6 +741,29 @@ class TypeDecoder {
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
bool decodeImplFunctionPart(Demangle::NodePointer node,
|
||||
std::vector<T> &results) {
|
||||
if (node->getNumChildren() != 2)
|
||||
return true;
|
||||
|
||||
if (node->getChild(0)->getKind() != Node::Kind::ImplConvention ||
|
||||
node->getChild(1)->getKind() != Node::Kind::Type)
|
||||
return true;
|
||||
|
||||
StringRef conventionString = node->getChild(0)->getText();
|
||||
Optional<typename T::ConventionType> convention =
|
||||
T::getConventionFromString(conventionString);
|
||||
if (!convention)
|
||||
return true;
|
||||
BuiltType type = decodeMangledType(node->getChild(1));
|
||||
if (!type)
|
||||
return true;
|
||||
|
||||
results.emplace_back(*convention, type);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool decodeMangledTypeDecl(Demangle::NodePointer node,
|
||||
BuiltTypeDecl &typeDecl,
|
||||
BuiltType &parent,
|
||||
|
||||
@@ -275,6 +275,39 @@ public:
|
||||
return FunctionTypeRef::create(*this, params, result, flags);
|
||||
}
|
||||
|
||||
const FunctionTypeRef *createImplFunctionType(
|
||||
Demangle::ImplParameterConvention calleeConvention,
|
||||
ArrayRef<Demangle::ImplFunctionParam<const TypeRef *>> params,
|
||||
ArrayRef<Demangle::ImplFunctionResult<const TypeRef *>> results,
|
||||
Optional<Demangle::ImplFunctionResult<const TypeRef *>> errorResult,
|
||||
ImplFunctionTypeFlags flags) {
|
||||
// Minimal support for lowered function types. These come up in
|
||||
// reflection as capture types. For the reflection library's
|
||||
// purposes, the only part that matters is the convention.
|
||||
FunctionTypeFlags funcFlags;
|
||||
switch (flags.getRepresentation()) {
|
||||
case Demangle::ImplFunctionRepresentation::Thick:
|
||||
case Demangle::ImplFunctionRepresentation::Closure:
|
||||
funcFlags = funcFlags.withConvention(FunctionMetadataConvention::Swift);
|
||||
break;
|
||||
case Demangle::ImplFunctionRepresentation::Thin:
|
||||
case Demangle::ImplFunctionRepresentation::Method:
|
||||
case Demangle::ImplFunctionRepresentation::ObjCMethod:
|
||||
case Demangle::ImplFunctionRepresentation::WitnessMethod:
|
||||
funcFlags = funcFlags.withConvention(FunctionMetadataConvention::Thin);
|
||||
break;
|
||||
case Demangle::ImplFunctionRepresentation::CFunctionPointer:
|
||||
funcFlags = funcFlags.withConvention(FunctionMetadataConvention::CFunctionPointer);
|
||||
break;
|
||||
case Demangle::ImplFunctionRepresentation::Block:
|
||||
funcFlags = funcFlags.withConvention(FunctionMetadataConvention::Block);
|
||||
break;
|
||||
}
|
||||
|
||||
auto result = createTupleType({}, "", false);
|
||||
return FunctionTypeRef::create(*this, {}, result, funcFlags);
|
||||
}
|
||||
|
||||
const ProtocolCompositionTypeRef *
|
||||
createProtocolCompositionType(ArrayRef<BuiltProtocolDecl> protocols,
|
||||
BuiltType superclass,
|
||||
|
||||
@@ -313,6 +313,115 @@ Type ASTBuilder::createFunctionType(
|
||||
return FunctionType::get(funcParams, output, einfo);
|
||||
}
|
||||
|
||||
static ParameterConvention
|
||||
getParameterConvention(ImplParameterConvention conv) {
|
||||
switch (conv) {
|
||||
case Demangle::ImplParameterConvention::Indirect_In:
|
||||
return ParameterConvention::Indirect_In;
|
||||
case Demangle::ImplParameterConvention::Indirect_In_Constant:
|
||||
return ParameterConvention::Indirect_In_Constant;
|
||||
case Demangle::ImplParameterConvention::Indirect_In_Guaranteed:
|
||||
return ParameterConvention::Indirect_In_Guaranteed;
|
||||
case Demangle::ImplParameterConvention::Indirect_Inout:
|
||||
return ParameterConvention::Indirect_Inout;
|
||||
case Demangle::ImplParameterConvention::Indirect_InoutAliasable:
|
||||
return ParameterConvention::Indirect_InoutAliasable;
|
||||
case Demangle::ImplParameterConvention::Direct_Owned:
|
||||
return ParameterConvention::Direct_Owned;
|
||||
case Demangle::ImplParameterConvention::Direct_Unowned:
|
||||
return ParameterConvention::Direct_Unowned;
|
||||
case Demangle::ImplParameterConvention::Direct_Guaranteed:
|
||||
return ParameterConvention::Direct_Guaranteed;
|
||||
}
|
||||
}
|
||||
|
||||
static ResultConvention getResultConvention(ImplResultConvention conv) {
|
||||
switch (conv) {
|
||||
case Demangle::ImplResultConvention::Indirect:
|
||||
return ResultConvention::Indirect;
|
||||
case Demangle::ImplResultConvention::Owned:
|
||||
return ResultConvention::Owned;
|
||||
case Demangle::ImplResultConvention::Unowned:
|
||||
return ResultConvention::Unowned;
|
||||
case Demangle::ImplResultConvention::UnownedInnerPointer:
|
||||
return ResultConvention::UnownedInnerPointer;
|
||||
case Demangle::ImplResultConvention::Autoreleased:
|
||||
return ResultConvention::Autoreleased;
|
||||
}
|
||||
}
|
||||
|
||||
Type ASTBuilder::createImplFunctionType(
|
||||
Demangle::ImplParameterConvention calleeConvention,
|
||||
ArrayRef<Demangle::ImplFunctionParam<Type>> params,
|
||||
ArrayRef<Demangle::ImplFunctionResult<Type>> results,
|
||||
Optional<Demangle::ImplFunctionResult<Type>> errorResult,
|
||||
ImplFunctionTypeFlags flags) {
|
||||
GenericSignature *genericSig = nullptr;
|
||||
|
||||
SILCoroutineKind funcCoroutineKind = SILCoroutineKind::None;
|
||||
ParameterConvention funcCalleeConvention =
|
||||
getParameterConvention(calleeConvention);
|
||||
|
||||
SILFunctionTypeRepresentation representation;
|
||||
switch (flags.getRepresentation()) {
|
||||
case ImplFunctionRepresentation::Thick:
|
||||
representation = SILFunctionTypeRepresentation::Thick;
|
||||
break;
|
||||
case ImplFunctionRepresentation::Block:
|
||||
representation = SILFunctionTypeRepresentation::Block;
|
||||
break;
|
||||
case ImplFunctionRepresentation::Thin:
|
||||
representation = SILFunctionTypeRepresentation::Thin;
|
||||
break;
|
||||
case ImplFunctionRepresentation::CFunctionPointer:
|
||||
representation = SILFunctionTypeRepresentation::CFunctionPointer;
|
||||
break;
|
||||
case ImplFunctionRepresentation::Method:
|
||||
representation = SILFunctionTypeRepresentation::Method;
|
||||
break;
|
||||
case ImplFunctionRepresentation::ObjCMethod:
|
||||
representation = SILFunctionTypeRepresentation::ObjCMethod;
|
||||
break;
|
||||
case ImplFunctionRepresentation::WitnessMethod:
|
||||
representation = SILFunctionTypeRepresentation::WitnessMethod;
|
||||
break;
|
||||
case ImplFunctionRepresentation::Closure:
|
||||
representation = SILFunctionTypeRepresentation::Closure;
|
||||
break;
|
||||
}
|
||||
|
||||
auto einfo = SILFunctionType::ExtInfo(representation,
|
||||
flags.isPseudogeneric(),
|
||||
!flags.isEscaping());
|
||||
|
||||
llvm::SmallVector<SILParameterInfo, 8> funcParams;
|
||||
llvm::SmallVector<SILYieldInfo, 8> funcYields;
|
||||
llvm::SmallVector<SILResultInfo, 8> funcResults;
|
||||
Optional<SILResultInfo> funcErrorResult;
|
||||
|
||||
for (const auto ¶m : params) {
|
||||
auto type = param.getType()->getCanonicalType();
|
||||
auto conv = getParameterConvention(param.getConvention());
|
||||
funcParams.emplace_back(type, conv);
|
||||
}
|
||||
|
||||
for (const auto &result : results) {
|
||||
auto type = result.getType()->getCanonicalType();
|
||||
auto conv = getResultConvention(result.getConvention());
|
||||
funcResults.emplace_back(type, conv);
|
||||
}
|
||||
|
||||
if (errorResult) {
|
||||
auto type = errorResult->getType()->getCanonicalType();
|
||||
auto conv = getResultConvention(errorResult->getConvention());
|
||||
funcErrorResult.emplace(type, conv);
|
||||
}
|
||||
|
||||
return SILFunctionType::get(genericSig, einfo, funcCoroutineKind,
|
||||
funcCalleeConvention, funcParams, funcYields,
|
||||
funcResults, funcErrorResult, Ctx);
|
||||
}
|
||||
|
||||
Type ASTBuilder::createProtocolCompositionType(
|
||||
ArrayRef<ProtocolDecl *> protocols,
|
||||
Type superclass,
|
||||
|
||||
@@ -1167,6 +1167,16 @@ public:
|
||||
result);
|
||||
}
|
||||
|
||||
BuiltType createImplFunctionType(
|
||||
Demangle::ImplParameterConvention calleeConvention,
|
||||
ArrayRef<Demangle::ImplFunctionParam<BuiltType>> params,
|
||||
ArrayRef<Demangle::ImplFunctionResult<BuiltType>> results,
|
||||
Optional<Demangle::ImplFunctionResult<BuiltType>> errorResult,
|
||||
ImplFunctionTypeFlags flags) {
|
||||
// We can't realize the metadata for a SILFunctionType.
|
||||
return BuiltType();
|
||||
}
|
||||
|
||||
BuiltType createTupleType(ArrayRef<BuiltType> elements,
|
||||
std::string labels,
|
||||
bool variadic) const {
|
||||
|
||||
27
test/TypeDecoder/lowered_function_types.swift
Normal file
27
test/TypeDecoder/lowered_function_types.swift
Normal file
@@ -0,0 +1,27 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
|
||||
// RUN: %target-build-swift -emit-executable %s -g -o %t/lowered_function_types -emit-module
|
||||
// RUN: sed -ne '/\/\/ *DEMANGLE: /s/\/\/ *DEMANGLE: *//p' < %s > %t/input
|
||||
// RUN: %lldb-moduleimport-test %t/lowered_function_types -type-from-mangled=%t/input | %FileCheck %s
|
||||
|
||||
func blackHole(_: Any...) {}
|
||||
|
||||
class Class {}
|
||||
|
||||
do {
|
||||
let fn: (Int, Class, __owned Class, Any, inout Int) -> (Int, Class, Any) = {
|
||||
_, _, _, _, _ in fatalError()
|
||||
}
|
||||
blackHole(fn)
|
||||
}
|
||||
|
||||
do {
|
||||
let fn: () throws -> () = {}
|
||||
blackHole(fn)
|
||||
}
|
||||
|
||||
// DEMANGLE: $sSi22lowered_function_types5ClassCACypS2iACypIegygxnldor_D
|
||||
// DEMANGLE: $ss5Error_pIegzo_D
|
||||
|
||||
// CHECK: @callee_guaranteed (Int, @guaranteed Class, @owned Class, @in_guaranteed Any, @inout Int) -> (Int, @owned Class, @out Any)
|
||||
// CHECK: @callee_guaranteed () -> @error Error
|
||||
Reference in New Issue
Block a user