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

View File

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

View File

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

View File

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

View File

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

View File

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