Skip to content

Make c++ defer looks like a swift one #166

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 1 commit into from
Dec 6, 2015
Merged
Show file tree
Hide file tree
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
25 changes: 16 additions & 9 deletions include/swift/Basic/Defer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,44 @@
#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){}
~DoAtScopeExit() {
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)


/// 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


4 changes: 2 additions & 2 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/IterativeTypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 6 additions & 6 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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()) {
Expand Down