mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Add error reporting when looking up types by demangled name.
This commit is contained in:
@@ -18,10 +18,12 @@
|
||||
#ifndef SWIFT_DEMANGLING_TYPEDECODER_H
|
||||
#define SWIFT_DEMANGLING_TYPEDECODER_H
|
||||
|
||||
#include "TypeLookupError.h"
|
||||
#include "swift/ABI/MetadataValues.h"
|
||||
#include "swift/Basic/LLVM.h"
|
||||
#include "swift/Demangling/Demangler.h"
|
||||
#include "swift/Demangling/NamespaceMacros.h"
|
||||
#include "swift/Basic/LLVM.h"
|
||||
#include "swift/Runtime/Portability.h"
|
||||
#include "swift/Runtime/Unreachable.h"
|
||||
#include "swift/Strings.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
@@ -317,6 +319,14 @@ getObjCClassOrProtocolName(NodePointer node) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MAKE_NODE_TYPE_ERROR(Node, Fmt, ...) \
|
||||
TypeLookupError("TypeDecoder.h:%d: Node kind %u \"%.*s\" - " Fmt, __LINE__, \
|
||||
Node->getKind(), \
|
||||
Node->hasText() ? (int)Node->getText().size() : 0, \
|
||||
Node->hasText() ? Node->getText().data() : "", __VA_ARGS__)
|
||||
|
||||
#define MAKE_NODE_TYPE_ERROR0(Node, Str) MAKE_NODE_TYPE_ERROR(Node, "%s", Str)
|
||||
|
||||
/// Decode a mangled type to construct an abstract type, forming such
|
||||
/// types by invoking a custom builder.
|
||||
template <typename BuilderType>
|
||||
@@ -333,24 +343,25 @@ class TypeDecoder {
|
||||
: Builder(Builder) {}
|
||||
|
||||
/// Given a demangle tree, attempt to turn it into a type.
|
||||
BuiltType decodeMangledType(NodePointer Node) {
|
||||
if (!Node) return BuiltType();
|
||||
TypeLookupErrorOr<BuiltType> decodeMangledType(NodePointer Node) {
|
||||
if (!Node)
|
||||
return TypeLookupError("Node is NULL");
|
||||
|
||||
using NodeKind = Demangle::Node::Kind;
|
||||
switch (Node->getKind()) {
|
||||
case NodeKind::Global:
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children.");
|
||||
|
||||
return decodeMangledType(Node->getChild(0));
|
||||
case NodeKind::TypeMangling:
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children.");
|
||||
|
||||
return decodeMangledType(Node->getChild(0));
|
||||
case NodeKind::Type:
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children.");
|
||||
|
||||
return decodeMangledType(Node->getChild(0));
|
||||
case NodeKind::Class:
|
||||
@@ -369,8 +380,8 @@ class TypeDecoder {
|
||||
BuiltTypeDecl typeDecl = BuiltTypeDecl();
|
||||
BuiltType parent = BuiltType();
|
||||
bool typeAlias = false;
|
||||
if (!decodeMangledTypeDecl(Node, typeDecl, parent, typeAlias))
|
||||
return BuiltType();
|
||||
if (auto error = decodeMangledTypeDecl(Node, typeDecl, parent, typeAlias))
|
||||
return *error;
|
||||
|
||||
if (typeAlias)
|
||||
return Builder.createTypeAliasType(typeDecl, parent);
|
||||
@@ -384,19 +395,21 @@ class TypeDecoder {
|
||||
case NodeKind::BoundGenericTypeAlias:
|
||||
case NodeKind::BoundGenericOtherNominalType: {
|
||||
if (Node->getNumChildren() < 2)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node,
|
||||
"fewer children (%u) than required (2)",
|
||||
Node->getNumChildren());
|
||||
|
||||
llvm::SmallVector<BuiltType, 8> args;
|
||||
|
||||
const auto &genericArgs = Node->getChild(1);
|
||||
if (genericArgs->getKind() != NodeKind::TypeList)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(genericArgs, "is not TypeList");
|
||||
|
||||
for (auto genericArg : *genericArgs) {
|
||||
auto paramType = decodeMangledType(genericArg);
|
||||
if (!paramType)
|
||||
return BuiltType();
|
||||
args.push_back(paramType);
|
||||
if (paramType.isError())
|
||||
return paramType;
|
||||
args.push_back(paramType.getType());
|
||||
}
|
||||
|
||||
auto ChildNode = Node->getChild(0);
|
||||
@@ -413,9 +426,9 @@ class TypeDecoder {
|
||||
BuiltTypeDecl typeDecl = BuiltTypeDecl();
|
||||
BuiltType parent = BuiltType();
|
||||
bool typeAlias = false;
|
||||
if (!decodeMangledTypeDecl(ChildNode, typeDecl,
|
||||
parent, typeAlias))
|
||||
return BuiltType();
|
||||
if (auto error =
|
||||
decodeMangledTypeDecl(ChildNode, typeDecl, parent, typeAlias))
|
||||
return *error;
|
||||
|
||||
return Builder.createBoundGenericType(typeDecl, args, parent);
|
||||
}
|
||||
@@ -445,11 +458,15 @@ class TypeDecoder {
|
||||
// But when resolving it to a type, we want to *keep* the argument
|
||||
// so that the parent type becomes 'S' and not 'P'.
|
||||
if (Node->getNumChildren() < 2)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node,
|
||||
"fewer children (%u) than required (2)",
|
||||
Node->getNumChildren());
|
||||
|
||||
const auto &genericArgs = Node->getChild(1);
|
||||
if (genericArgs->getNumChildren() != 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(genericArgs,
|
||||
"expected 1 generic argument, saw %u",
|
||||
genericArgs->getNumChildren());
|
||||
|
||||
return decodeMangledType(genericArgs->getChild(0));
|
||||
}
|
||||
@@ -469,7 +486,7 @@ class TypeDecoder {
|
||||
auto reprNode = Node->getChild(i++);
|
||||
if (reprNode->getKind() != NodeKind::MetatypeRepresentation ||
|
||||
!reprNode->hasText())
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(reprNode, "wrong node kind or no text");
|
||||
if (reprNode->getText() == "@thin")
|
||||
repr = ImplMetatypeRepresentation::Thin;
|
||||
else if (reprNode->getText() == "@thick")
|
||||
@@ -477,26 +494,28 @@ class TypeDecoder {
|
||||
else if (reprNode->getText() == "@objc_metatype")
|
||||
repr = ImplMetatypeRepresentation::ObjC;
|
||||
} else if (Node->getNumChildren() < 1) {
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
}
|
||||
|
||||
auto instance = decodeMangledType(Node->getChild(i));
|
||||
if (!instance)
|
||||
return BuiltType();
|
||||
if (instance.isError())
|
||||
return instance;
|
||||
if (Node->getKind() == NodeKind::Metatype) {
|
||||
return Builder.createMetatypeType(instance, repr);
|
||||
return Builder.createMetatypeType(instance.getType(), repr);
|
||||
} else if (Node->getKind() == NodeKind::ExistentialMetatype) {
|
||||
return Builder.createExistentialMetatypeType(instance, repr);
|
||||
return Builder.createExistentialMetatypeType(instance.getType(), repr);
|
||||
} else {
|
||||
assert(false);
|
||||
return nullptr;
|
||||
return MAKE_NODE_TYPE_ERROR0(Node,
|
||||
"Metatype/ExistentialMetatype Node "
|
||||
"had a different kind when re-checked");
|
||||
}
|
||||
}
|
||||
case NodeKind::ProtocolList:
|
||||
case NodeKind::ProtocolListWithAnyObject:
|
||||
case NodeKind::ProtocolListWithClass: {
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
|
||||
// Find the protocol list.
|
||||
llvm::SmallVector<BuiltProtocolDecl, 8> Protocols;
|
||||
@@ -511,7 +530,8 @@ class TypeDecoder {
|
||||
if (auto Protocol = decodeMangledProtocolType(componentType))
|
||||
Protocols.push_back(Protocol);
|
||||
else
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(componentType,
|
||||
"failed to decode protocol type");
|
||||
}
|
||||
|
||||
// Superclass or AnyObject, if present.
|
||||
@@ -519,11 +539,15 @@ class TypeDecoder {
|
||||
auto Superclass = BuiltType();
|
||||
if (Node->getKind() == NodeKind::ProtocolListWithClass) {
|
||||
if (Node->getNumChildren() < 2)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node,
|
||||
"fewer children (%u) than required (2)",
|
||||
Node->getNumChildren());
|
||||
|
||||
auto superclassNode = Node->getChild(1);
|
||||
Superclass = decodeMangledType(superclassNode);
|
||||
if (!Superclass) return BuiltType();
|
||||
auto result = decodeMangledType(superclassNode);
|
||||
if (result.isError())
|
||||
return result;
|
||||
Superclass = result.getType();
|
||||
|
||||
IsClassBound = true;
|
||||
} else if (Node->getKind() == NodeKind::ProtocolListWithAnyObject) {
|
||||
@@ -541,17 +565,18 @@ class TypeDecoder {
|
||||
/*IsClassBound=*/false);
|
||||
}
|
||||
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "failed to decode protocol type");
|
||||
}
|
||||
case NodeKind::DynamicSelf: {
|
||||
if (Node->getNumChildren() != 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node, "expected 1 child, saw %u",
|
||||
Node->getNumChildren());
|
||||
|
||||
auto selfType = decodeMangledType(Node->getChild(0));
|
||||
if (!selfType)
|
||||
return BuiltType();
|
||||
if (selfType.isError())
|
||||
return selfType;
|
||||
|
||||
return Builder.createDynamicSelfType(selfType);
|
||||
return Builder.createDynamicSelfType(selfType.getType());
|
||||
}
|
||||
case NodeKind::DependentGenericParamType: {
|
||||
auto depth = Node->getChild(0)->getIndex();
|
||||
@@ -571,7 +596,9 @@ class TypeDecoder {
|
||||
case NodeKind::EscapingLinearFunctionType:
|
||||
case NodeKind::FunctionType: {
|
||||
if (Node->getNumChildren() < 2)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node,
|
||||
"fewer children (%u) than required (2)",
|
||||
Node->getNumChildren());
|
||||
|
||||
FunctionTypeFlags flags;
|
||||
if (Node->getKind() == NodeKind::ObjCBlock ||
|
||||
@@ -611,13 +638,16 @@ class TypeDecoder {
|
||||
flags = flags.withAsync(isAsync).withThrows(isThrow);
|
||||
|
||||
if (Node->getNumChildren() < firstChildIdx + 2)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node,
|
||||
"fewer children (%u) than required (%u)",
|
||||
Node->getNumChildren(), firstChildIdx + 2);
|
||||
|
||||
bool hasParamFlags = false;
|
||||
llvm::SmallVector<FunctionParam<BuiltType>, 8> parameters;
|
||||
if (!decodeMangledFunctionInputType(Node->getChild(firstChildIdx),
|
||||
parameters, hasParamFlags))
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node->getChild(firstChildIdx),
|
||||
"failed to decode function type");
|
||||
flags =
|
||||
flags.withNumParameters(parameters.size())
|
||||
.withParameterFlags(hasParamFlags)
|
||||
@@ -631,8 +661,9 @@ class TypeDecoder {
|
||||
NodeKind::EscapingLinearFunctionType);
|
||||
|
||||
auto result = decodeMangledType(Node->getChild(firstChildIdx+1));
|
||||
if (!result) return BuiltType();
|
||||
return Builder.createFunctionType(parameters, result, flags);
|
||||
if (result.isError())
|
||||
return result;
|
||||
return Builder.createFunctionType(parameters, result.getType(), flags);
|
||||
}
|
||||
case NodeKind::ImplFunctionType: {
|
||||
auto calleeConvention = ImplParameterConvention::Direct_Unowned;
|
||||
@@ -646,7 +677,7 @@ class TypeDecoder {
|
||||
|
||||
if (child->getKind() == NodeKind::ImplConvention) {
|
||||
if (!child->hasText())
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(child, "expected text");
|
||||
|
||||
if (child->getText() == "@convention(thin)") {
|
||||
flags =
|
||||
@@ -656,7 +687,7 @@ class TypeDecoder {
|
||||
}
|
||||
} else if (child->getKind() == NodeKind::ImplFunctionAttribute) {
|
||||
if (!child->hasText())
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(child, "expected text");
|
||||
|
||||
StringRef text = child->getText();
|
||||
if (text == "@convention(c)") {
|
||||
@@ -676,15 +707,18 @@ class TypeDecoder {
|
||||
flags = flags.withEscaping();
|
||||
} else if (child->getKind() == NodeKind::ImplParameter) {
|
||||
if (decodeImplFunctionParam(child, parameters))
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(child,
|
||||
"failed to decode function parameter");
|
||||
} else if (child->getKind() == NodeKind::ImplResult) {
|
||||
if (decodeImplFunctionParam(child, results))
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(child,
|
||||
"failed to decode function parameter");
|
||||
} else if (child->getKind() == NodeKind::ImplErrorResult) {
|
||||
if (decodeImplFunctionPart(child, errorResults))
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(child,
|
||||
"failed to decode function part");
|
||||
} else {
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(child, "unexpected kind");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -696,7 +730,8 @@ class TypeDecoder {
|
||||
errorResult = errorResults.front();
|
||||
break;
|
||||
default:
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node, "got %zu errors",
|
||||
errorResults.size());
|
||||
}
|
||||
|
||||
// TODO: Some cases not handled above, but *probably* they cannot
|
||||
@@ -711,13 +746,13 @@ class TypeDecoder {
|
||||
|
||||
case NodeKind::ArgumentTuple:
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
|
||||
return decodeMangledType(Node->getChild(0));
|
||||
|
||||
case NodeKind::ReturnType:
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
|
||||
return decodeMangledType(Node->getChild(0));
|
||||
|
||||
@@ -726,12 +761,13 @@ class TypeDecoder {
|
||||
std::string labels;
|
||||
for (auto &element : *Node) {
|
||||
if (element->getKind() != NodeKind::TupleElement)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "unexpected kind");
|
||||
|
||||
// If the tuple element is labeled, add its label to 'labels'.
|
||||
unsigned typeChildIndex = 0;
|
||||
if (element->getChild(typeChildIndex)->getKind() == NodeKind::VariadicMarker) {
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(element->getChild(typeChildIndex),
|
||||
"no children");
|
||||
}
|
||||
if (element->getChild(typeChildIndex)->getKind() == NodeKind::TupleElementName) {
|
||||
// Add spaces to terminate all the previous labels if this
|
||||
@@ -749,22 +785,23 @@ class TypeDecoder {
|
||||
}
|
||||
|
||||
// Decode the element type.
|
||||
BuiltType elementType =
|
||||
decodeMangledType(element->getChild(typeChildIndex));
|
||||
if (!elementType)
|
||||
return BuiltType();
|
||||
auto elementType = decodeMangledType(element->getChild(typeChildIndex));
|
||||
if (elementType.isError())
|
||||
return elementType;
|
||||
|
||||
elements.push_back(elementType);
|
||||
elements.push_back(elementType.getType());
|
||||
}
|
||||
return Builder.createTupleType(elements, std::move(labels));
|
||||
}
|
||||
case NodeKind::TupleElement:
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
|
||||
if (Node->getChild(0)->getKind() == NodeKind::TupleElementName) {
|
||||
if (Node->getNumChildren() < 2)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node,
|
||||
"fewer children (%u) than required (2)",
|
||||
Node->getNumChildren());
|
||||
|
||||
return decodeMangledType(Node->getChild(1));
|
||||
}
|
||||
@@ -772,68 +809,75 @@ class TypeDecoder {
|
||||
|
||||
case NodeKind::DependentGenericType: {
|
||||
if (Node->getNumChildren() < 2)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node,
|
||||
"fewer children (%u) than required (2)",
|
||||
Node->getNumChildren());
|
||||
|
||||
return decodeMangledType(Node->getChild(1));
|
||||
}
|
||||
case NodeKind::DependentMemberType: {
|
||||
if (Node->getNumChildren() < 2)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node,
|
||||
"fewer children (%u) than required (2)",
|
||||
Node->getNumChildren());
|
||||
|
||||
auto base = decodeMangledType(Node->getChild(0));
|
||||
if (!base)
|
||||
return BuiltType();
|
||||
if (base.isError())
|
||||
return base;
|
||||
auto assocTypeChild = Node->getChild(1);
|
||||
auto member = assocTypeChild->getFirstChild()->getText();
|
||||
if (assocTypeChild->getNumChildren() < 2)
|
||||
return Builder.createDependentMemberType(member.str(), base);
|
||||
return Builder.createDependentMemberType(member.str(), base.getType());
|
||||
|
||||
auto protocol = decodeMangledProtocolType(assocTypeChild->getChild(1));
|
||||
if (!protocol)
|
||||
return BuiltType();
|
||||
return Builder.createDependentMemberType(member.str(), base, protocol);
|
||||
return Builder.createDependentMemberType(member.str(), base.getType(),
|
||||
protocol);
|
||||
}
|
||||
case NodeKind::DependentAssociatedTypeRef: {
|
||||
if (Node->getNumChildren() < 2)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node,
|
||||
"fewer children (%u) than required (2)",
|
||||
Node->getNumChildren());
|
||||
|
||||
return decodeMangledType(Node->getChild(1));
|
||||
}
|
||||
case NodeKind::Unowned: {
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
|
||||
auto base = decodeMangledType(Node->getChild(0));
|
||||
if (!base)
|
||||
return BuiltType();
|
||||
return Builder.createUnownedStorageType(base);
|
||||
if (base.isError())
|
||||
return base;
|
||||
return Builder.createUnownedStorageType(base.getType());
|
||||
}
|
||||
case NodeKind::Unmanaged: {
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
|
||||
auto base = decodeMangledType(Node->getChild(0));
|
||||
if (!base)
|
||||
return BuiltType();
|
||||
return Builder.createUnmanagedStorageType(base);
|
||||
if (base.isError())
|
||||
return base;
|
||||
return Builder.createUnmanagedStorageType(base.getType());
|
||||
}
|
||||
case NodeKind::Weak: {
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
|
||||
auto base = decodeMangledType(Node->getChild(0));
|
||||
if (!base)
|
||||
return BuiltType();
|
||||
return Builder.createWeakStorageType(base);
|
||||
if (base.isError())
|
||||
return base;
|
||||
return Builder.createWeakStorageType(base.getType());
|
||||
}
|
||||
case NodeKind::SILBoxType: {
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
|
||||
auto base = decodeMangledType(Node->getChild(0));
|
||||
if (!base)
|
||||
return BuiltType();
|
||||
return Builder.createSILBoxType(base);
|
||||
if (base.isError())
|
||||
return base;
|
||||
return Builder.createSILBoxType(base.getType());
|
||||
}
|
||||
case NodeKind::SILBoxTypeWithLayout: {
|
||||
// TODO: Implement SILBoxTypeRefs with layout. As a stopgap, specify the
|
||||
@@ -842,57 +886,62 @@ class TypeDecoder {
|
||||
}
|
||||
case NodeKind::SugaredOptional: {
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
|
||||
auto base = decodeMangledType(Node->getChild(0));
|
||||
if (!base)
|
||||
return BuiltType();
|
||||
if (base.isError())
|
||||
return base;
|
||||
|
||||
return Builder.createOptionalType(base);
|
||||
return Builder.createOptionalType(base.getType());
|
||||
}
|
||||
case NodeKind::SugaredArray: {
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
|
||||
auto base = decodeMangledType(Node->getChild(0));
|
||||
if (!base)
|
||||
return BuiltType();
|
||||
if (base.isError())
|
||||
return base;
|
||||
|
||||
return Builder.createArrayType(base);
|
||||
return Builder.createArrayType(base.getType());
|
||||
}
|
||||
case NodeKind::SugaredDictionary: {
|
||||
if (Node->getNumChildren() < 2)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node,
|
||||
"fewer children (%u) than required (2)",
|
||||
Node->getNumChildren());
|
||||
|
||||
auto key = decodeMangledType(Node->getChild(0));
|
||||
if (!key)
|
||||
return BuiltType();
|
||||
if (key.isError())
|
||||
return key;
|
||||
|
||||
auto value = decodeMangledType(Node->getChild(1));
|
||||
if (!key)
|
||||
return BuiltType();
|
||||
if (value.isError())
|
||||
return value;
|
||||
|
||||
return Builder.createDictionaryType(key, value);
|
||||
return Builder.createDictionaryType(key.getType(), value.getType());
|
||||
}
|
||||
case NodeKind::SugaredParen: {
|
||||
if (Node->getNumChildren() < 1)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
|
||||
|
||||
auto base = decodeMangledType(Node->getChild(0));
|
||||
if (!base)
|
||||
return BuiltType();
|
||||
if (base.isError())
|
||||
return base;
|
||||
|
||||
return Builder.createParenType(base);
|
||||
return Builder.createParenType(base.getType());
|
||||
}
|
||||
case NodeKind::OpaqueType: {
|
||||
if (Node->getNumChildren() < 3)
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR(Node,
|
||||
"fewer children (%u) than required (3)",
|
||||
Node->getNumChildren());
|
||||
auto descriptor = Node->getChild(0);
|
||||
auto ordinalNode = Node->getChild(1);
|
||||
|
||||
if (ordinalNode->getKind() != NodeKind::Index
|
||||
|| !ordinalNode->hasIndex())
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(ordinalNode,
|
||||
"unexpected kind or no index");
|
||||
auto ordinal = ordinalNode->getIndex();
|
||||
|
||||
std::vector<BuiltType> genericArgsBuf;
|
||||
@@ -905,9 +954,9 @@ class TypeDecoder {
|
||||
break;
|
||||
for (auto argNode : *genericsNode) {
|
||||
auto arg = decodeMangledType(argNode);
|
||||
if (!arg)
|
||||
return BuiltType();
|
||||
genericArgsBuf.push_back(arg);
|
||||
if (arg.isError())
|
||||
return arg;
|
||||
genericArgsBuf.push_back(arg.getType());
|
||||
}
|
||||
}
|
||||
genericArgsLevels.push_back(genericArgsBuf.size());
|
||||
@@ -923,7 +972,7 @@ class TypeDecoder {
|
||||
// TODO: Handle OpaqueReturnType, when we're in the middle of reconstructing
|
||||
// the defining decl
|
||||
default:
|
||||
return BuiltType();
|
||||
return MAKE_NODE_TYPE_ERROR0(Node, "unexpected kind");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -943,11 +992,11 @@ private:
|
||||
T::getConventionFromString(conventionString);
|
||||
if (!convention)
|
||||
return true;
|
||||
BuiltType type = decodeMangledType(node->getChild(1));
|
||||
if (!type)
|
||||
auto type = decodeMangledType(node->getChild(1));
|
||||
if (type.isError())
|
||||
return true;
|
||||
|
||||
results.emplace_back(type, *convention);
|
||||
results.emplace_back(type.getType(), *convention);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -968,8 +1017,8 @@ private:
|
||||
auto convention = T::getConventionFromString(conventionString);
|
||||
if (!convention)
|
||||
return true;
|
||||
BuiltType type = decodeMangledType(typeNode);
|
||||
if (!type)
|
||||
auto result = decodeMangledType(typeNode);
|
||||
if (result.isError())
|
||||
return true;
|
||||
|
||||
auto diffKind = T::DifferentiabilityType::DifferentiableOrNotApplicable;
|
||||
@@ -984,14 +1033,13 @@ private:
|
||||
diffKind = *optDiffKind;
|
||||
}
|
||||
|
||||
results.emplace_back(type, *convention, diffKind);
|
||||
results.emplace_back(result.getType(), *convention, diffKind);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool decodeMangledTypeDecl(Demangle::NodePointer node,
|
||||
BuiltTypeDecl &typeDecl,
|
||||
BuiltType &parent,
|
||||
bool &typeAlias) {
|
||||
llvm::Optional<TypeLookupError>
|
||||
decodeMangledTypeDecl(Demangle::NodePointer node, BuiltTypeDecl &typeDecl,
|
||||
BuiltType &parent, bool &typeAlias) {
|
||||
if (node->getKind() == NodeKind::Type)
|
||||
return decodeMangledTypeDecl(node->getChild(0), typeDecl,
|
||||
parent, typeAlias);
|
||||
@@ -1002,7 +1050,9 @@ private:
|
||||
declNode = node;
|
||||
} else {
|
||||
if (node->getNumChildren() < 2)
|
||||
return false;
|
||||
return MAKE_NODE_TYPE_ERROR(
|
||||
node, "Number of node children (%u) less than required (2)",
|
||||
node->getNumChildren());
|
||||
|
||||
auto parentContext = node->getChild(0);
|
||||
|
||||
@@ -1018,11 +1068,14 @@ private:
|
||||
case Node::Kind::Extension:
|
||||
// Decode the type being extended.
|
||||
if (parentContext->getNumChildren() < 2)
|
||||
return false;
|
||||
return MAKE_NODE_TYPE_ERROR(parentContext,
|
||||
"Number of parentContext children (%u) "
|
||||
"less than required (2)",
|
||||
node->getNumChildren());
|
||||
parentContext = parentContext->getChild(1);
|
||||
LLVM_FALLTHROUGH;
|
||||
default:
|
||||
parent = decodeMangledType(parentContext);
|
||||
parent = decodeMangledType(parentContext).getType();
|
||||
// Remove any generic arguments from the context node, producing a
|
||||
// node that references the nominal type declaration.
|
||||
declNode = Demangle::getUnspecialized(node, Builder.getNodeFactory());
|
||||
@@ -1030,9 +1083,10 @@ private:
|
||||
}
|
||||
}
|
||||
typeDecl = Builder.createTypeDecl(declNode, typeAlias);
|
||||
if (!typeDecl) return false;
|
||||
if (!typeDecl)
|
||||
return TypeLookupError("Failed to create type decl");
|
||||
|
||||
return true;
|
||||
return llvm::None;
|
||||
}
|
||||
|
||||
BuiltProtocolDecl decodeMangledProtocolType(Demangle::NodePointer node) {
|
||||
@@ -1097,10 +1151,10 @@ private:
|
||||
}
|
||||
|
||||
auto paramType = decodeMangledType(node);
|
||||
if (!paramType)
|
||||
if (paramType.isError())
|
||||
return false;
|
||||
|
||||
param.setType(paramType);
|
||||
param.setType(paramType.getType());
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -1158,14 +1212,12 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename BuilderType>
|
||||
inline typename BuilderType::BuiltType
|
||||
decodeMangledType(BuilderType &Builder,
|
||||
NodePointer Node) {
|
||||
template <typename BuilderType>
|
||||
inline TypeLookupErrorOr<typename BuilderType::BuiltType>
|
||||
decodeMangledType(BuilderType &Builder, NodePointer Node) {
|
||||
return TypeDecoder<BuilderType>(Builder).decodeMangledType(Node);
|
||||
}
|
||||
|
||||
|
||||
SWIFT_END_INLINE_NAMESPACE
|
||||
} // end namespace Demangle
|
||||
} // end namespace swift
|
||||
|
||||
198
include/swift/Demangling/TypeLookupError.h
Normal file
198
include/swift/Demangling/TypeLookupError.h
Normal file
@@ -0,0 +1,198 @@
|
||||
//===--- TypeLookupError.h - Type lookup error value. -----------*- C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Provides the TypeLookupError class, which represents errors when demangling
|
||||
// or looking up types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_DEMANGLING_TypeLookupError_H
|
||||
#define SWIFT_DEMANGLING_TypeLookupError_H
|
||||
|
||||
#include "swift/Basic/TaggedUnion.h"
|
||||
#include "swift/Runtime/Portability.h"
|
||||
|
||||
namespace swift {
|
||||
|
||||
/// An error that occurred while looking up a type at runtime from a mangled
|
||||
/// name.
|
||||
/// ///
|
||||
/// This ultimately just provides a string, but is built to take up minimal
|
||||
/// space when passed around, and perform as much work lazily as possible. We
|
||||
/// don't want to spend a lot of time building strings when the caller is going
|
||||
/// to handle the error gracefully and try a fallback. We only want to waste
|
||||
/// time/space on that when the error message is actually relevant, so build it
|
||||
/// as late as possible.
|
||||
/// ///
|
||||
/// To be as compact as possible, this type holds a context pointer and a
|
||||
/// callback function. The callback function uses the context pointer to return
|
||||
/// an error string when requested. The callback function also does quadruple
|
||||
/// duty to copy/destroy the context as needed, and free the returned error
|
||||
/// string if needed. Commands are passed to the callback to request the
|
||||
/// different operations, which means we only have to store one function pointer
|
||||
/// instead of four.
|
||||
class TypeLookupError {
|
||||
public:
|
||||
/// The commands that can be passed to the callback function.
|
||||
enum class Command {
|
||||
/// Return the error string to the caller, as a char *.
|
||||
CopyErrorString,
|
||||
|
||||
/// Destroy the error string returned from CopyErrorString, if necessary.
|
||||
/// The return value is ignored.
|
||||
DestroyErrorString,
|
||||
|
||||
/// Return a copy of the context pointer (used for copying TypeLookupError
|
||||
/// objects.)
|
||||
CopyContext,
|
||||
|
||||
/// Destroy the context pointer. The return value is ignored.
|
||||
DestroyContext,
|
||||
};
|
||||
|
||||
/// The callback used to respond to the commands. The parameters are:
|
||||
/// - `context`: the context that the value was initialized with, or the
|
||||
/// context returned from a CopyContext call
|
||||
/// - `command`: the command to respond to
|
||||
/// - `param`: when `command` is `DestroyErrorString`, the string pointer to
|
||||
/// destroy, otherwise NULL
|
||||
using Callback = void *(*)(void *context, Command command, void *param);
|
||||
|
||||
private:
|
||||
void *Context;
|
||||
Callback Fn;
|
||||
|
||||
/// A no-op callback used to avoid a bunch of `if (Fn)` checks.
|
||||
static void *nop(void *context, Command command, void *param) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Helper functions for getting a C string from a lambda. These allow us to
|
||||
/// wrap lambdas returning `char *` or `std::string` and standardize them on
|
||||
/// `char *`.
|
||||
static char *getCString(char *str) { return str; }
|
||||
|
||||
static char *getCString(const std::string &str) {
|
||||
return strdup(str.c_str());
|
||||
}
|
||||
|
||||
public:
|
||||
TypeLookupError(const TypeLookupError &other) {
|
||||
Fn = other.Fn;
|
||||
Context = other.Fn(other.Context, Command::CopyContext, nullptr);
|
||||
}
|
||||
|
||||
TypeLookupError(TypeLookupError &&other) {
|
||||
Fn = other.Fn;
|
||||
Context = other.Context;
|
||||
|
||||
other.Fn = nop;
|
||||
other.Context = nullptr;
|
||||
}
|
||||
|
||||
~TypeLookupError() { Fn(Context, Command::DestroyContext, nullptr); }
|
||||
|
||||
TypeLookupError(void *context, Callback fn) : Context(context), Fn(fn ? fn : nop) {}
|
||||
|
||||
TypeLookupError &operator=(const TypeLookupError &other) {
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
Fn(Context, Command::DestroyContext, nullptr);
|
||||
Fn = other.Fn;
|
||||
Context = Fn(Context, Command::CopyContext, nullptr);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Construct a TypeLookupError that just returns a constant C string.
|
||||
TypeLookupError(const char *str)
|
||||
: TypeLookupError([=] { return const_cast<char *>(str); }) {}
|
||||
|
||||
/// Construct a TypeLookupError that creates a string using asprintf. The passed-in
|
||||
/// format string and arguments are passed directly to swift_asprintf when
|
||||
/// the string is requested. The arguments are captured and the string is only
|
||||
/// formatted when needed.
|
||||
template <typename... Args>
|
||||
TypeLookupError(const char *fmt, Args... args)
|
||||
: TypeLookupError([=] {
|
||||
char *str;
|
||||
swift_asprintf(&str, fmt, args...);
|
||||
return str;
|
||||
}) {}
|
||||
|
||||
/// Construct a TypeLookupError that wraps a function returning a string. The
|
||||
/// passed-in function can return either a `std::string` or `char *`. If it
|
||||
/// returns `char *` then the string will be destroyed with `free()`.
|
||||
template <typename F> TypeLookupError(const F &fn) {
|
||||
Context = new F(fn);
|
||||
Fn = [](void *context, Command command, void *param) -> void * {
|
||||
auto castContext = reinterpret_cast<F *>(context);
|
||||
switch (command) {
|
||||
case Command::CopyErrorString: {
|
||||
return TypeLookupError::getCString((*castContext)());
|
||||
}
|
||||
case Command::DestroyErrorString:
|
||||
free(param);
|
||||
return nullptr;
|
||||
case Command::CopyContext:
|
||||
return new F(*castContext);
|
||||
case Command::DestroyContext:
|
||||
delete castContext;
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Get the error string from the error value. The value must be passed to
|
||||
/// `freeErrorString` when done. (Unless you're just calling a `fatalError`
|
||||
/// in which case there's no point.)
|
||||
char *copyErrorString() {
|
||||
return reinterpret_cast<char *>(
|
||||
Fn(Context, Command::CopyErrorString, nullptr));
|
||||
}
|
||||
|
||||
/// Free an error string previously obtained from `copyErrorString`.
|
||||
void freeErrorString(char *str) {
|
||||
Fn(Context, Command::DestroyErrorString, str);
|
||||
}
|
||||
};
|
||||
|
||||
/// A value that's either a `TypeLookupError` or some parameterized type value `T`. A
|
||||
/// convenience wrapper around `TaggedUnion<T, TypeLookupError>`.
|
||||
template <typename T> class TypeLookupErrorOr {
|
||||
TaggedUnion<T, TypeLookupError> Value;
|
||||
|
||||
public:
|
||||
TypeLookupErrorOr(const T &t) : Value(t) {
|
||||
if (!t)
|
||||
Value = TypeLookupError("unknown error");
|
||||
}
|
||||
|
||||
TypeLookupErrorOr(const TypeLookupError &te) : Value(te) {}
|
||||
|
||||
T getType() {
|
||||
if (auto *ptr = Value.template dyn_cast<T>())
|
||||
return *ptr;
|
||||
return T();
|
||||
}
|
||||
|
||||
TypeLookupError *getError() {
|
||||
return Value.template dyn_cast<TypeLookupError>();
|
||||
}
|
||||
|
||||
bool isError() { return getError() != nullptr; }
|
||||
};
|
||||
|
||||
} // namespace swift
|
||||
|
||||
#endif // SWIFT_DEMANGLING_TypeLookupError_H
|
||||
Reference in New Issue
Block a user