Make c++ defer looks like a swift one

This commit is contained in:
Bartosz Przybylski
2015-12-04 11:03:39 +01:00
parent b08610bc3e
commit 0e5c7ddfb8
6 changed files with 30 additions and 23 deletions

View File

@@ -18,11 +18,12 @@
#ifndef __SWIFT_DEFER_H
#define __SWIFT_DEFER_H
#include <type_traits>
namespace swift {
template <typename F>
class DoAtScopeExit {
F &Fn;
DoAtScopeExit(DoAtScopeExit&) = delete;
void operator=(DoAtScopeExit&) = delete;
public:
DoAtScopeExit(F &Fn) : Fn(Fn){}
@@ -30,8 +31,17 @@ namespace swift {
Fn();
}
};
namespace detail {
struct DeferTask {};
template<typename F>
DoAtScopeExit<typename std::decay<F>::type> operator+(DeferTask, F&& fn) {
return DoAtScopeExit<typename std::decay<F>::type>(fn);
}
}
}
#define DEFER_CONCAT_IMPL(x, y) x##y
#define DEFER_MACRO_CONCAT(x, y) DEFER_CONCAT_IMPL(x, y)
@@ -39,16 +49,13 @@ namespace swift {
/// This macro is used to register a function / lambda to be run on exit from a
/// scope. Its typical use looks like:
///
/// defer([&]{
/// defer {
/// stuff
/// })
/// };
///
#define defer(x) \
auto DEFER_MACRO_CONCAT(defer_func, __LINE__) = (x); \
swift::DoAtScopeExit<decltype(DEFER_MACRO_CONCAT(defer_func, __LINE__))> \
DEFER_MACRO_CONCAT(defer_local, __LINE__)\
(DEFER_MACRO_CONCAT(defer_func, __LINE__));
#define defer \
auto DEFER_MACRO_CONCAT(defer_func, __COUNTER__) = \
::swift::detail::DeferTask() + [&]()
#endif

View File

@@ -3643,7 +3643,7 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
// No matter what error path we take, make sure the
// PatternBindingDecl/TopLevel code block are added.
defer([&]{
defer {
// If we didn't parse any patterns, don't create the pattern binding decl.
if (PBDEntries.empty())
return;
@@ -3683,7 +3683,7 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
// specific spot to get it in before any accessors, which SILGen seems to
// want.
Decls.insert(Decls.begin()+NumDeclsInResult, PBD);
});
};
do {
Pattern *pattern;

View File

@@ -84,7 +84,7 @@ void IterativeTypeChecker::satisfy(TypeCheckRequest request) {
// Add this request to the stack of active requests.
ActiveRequests.push_back(request);
defer([&] { ActiveRequests.pop_back(); });
defer { ActiveRequests.pop_back(); };
while (true) {
// Process this requirement, enumerating dependencies if anything else needs

View File

@@ -356,7 +356,7 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
{
bool iBTC = decl->isBeingTypeChecked();
decl->setIsBeingTypeChecked();
defer([&]{decl->setIsBeingTypeChecked(iBTC); });
defer {decl->setIsBeingTypeChecked(iBTC); };
// Validate the type.
if (validateType(inherited, DC, options, resolver)) {
@@ -1219,9 +1219,9 @@ static void validatePatternBindingDecl(TypeChecker &tc,
// On any path out of this function, make sure to mark the binding as done
// being type checked.
defer([&]{
defer {
binding->setIsBeingTypeChecked(false);
});
};
// Resolve the pattern.
auto *pattern = tc.resolvePattern(binding->getPattern(entryNumber),
@@ -6239,7 +6239,7 @@ static Type checkExtensionGenericParams(
};
ext->setIsBeingTypeChecked(true);
defer([ext] { ext->setIsBeingTypeChecked(false); });
defer { ext->setIsBeingTypeChecked(false); };
// Validate the generic type signature.
bool invalid = false;

View File

@@ -890,7 +890,7 @@ namespace {
}
// Recursively check the transitive captures.
capturePath.push_back(func);
defer([&]{ capturePath.pop_back(); });
defer { capturePath.pop_back(); };
for (auto capture : func->getCaptureInfo().getCaptures())
if (!validateForwardCapture(capture.getDecl()))
return false;

View File

@@ -2922,9 +2922,9 @@ void ConformanceChecker::resolveTypeWitnesses() {
// Track when we are checking type witnesses.
ProtocolConformanceState initialState = Conformance->getState();
Conformance->setState(ProtocolConformanceState::CheckingTypeWitnesses);
defer([&] {
defer {
Conformance->setState(initialState);
});
};
for (auto member : Proto->getMembers()) {
auto assocType = dyn_cast<AssociatedTypeDecl>(member);
@@ -3251,11 +3251,11 @@ void ConformanceChecker::resolveTypeWitnesses() {
valueWitnesses.push_back({inferredReq.first, witnessReq.Witness});
if (witnessReq.Witness->getDeclContext()->isProtocolExtensionContext())
++numValueWitnessesInProtocolExtensions;
defer([&]{
defer {
if (witnessReq.Witness->getDeclContext()->isProtocolExtensionContext())
--numValueWitnessesInProtocolExtensions;
valueWitnesses.pop_back();
});
};
// Introduce each of the type witnesses into the hash table.
bool failed = false;
@@ -3635,7 +3635,7 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) {
// Note that we're resolving this witness.
assert(ResolvingWitnesses.count(requirement) == 0 && "Currently resolving");
ResolvingWitnesses.insert(requirement);
defer([&]{ ResolvingWitnesses.erase(requirement); });
defer { ResolvingWitnesses.erase(requirement); };
// Make sure we've validated the requirement.
if (!requirement->hasType())
@@ -3934,7 +3934,7 @@ checkConformsToProtocol(TypeChecker &TC,
// Note that we are checking this conformance now.
conformance->setState(ProtocolConformanceState::Checking);
defer([&] { conformance->setState(ProtocolConformanceState::Complete); });
defer { conformance->setState(ProtocolConformanceState::Complete); };
// If the protocol requires a class, non-classes are a non-starter.
if (Proto->requiresClass() && !canT->getClassOrBoundGenericClass()) {