Revert "Simpler implementation for multiple matching patterns in case with variable bindings"

This reverts commit 9508fdc8a7 from #5094. Reemitting
case bodies doesn't work if the body contains nested closures or
declarations, since SILGen expects these to only ever be visited once.
This commit is contained in:
Joe Groff
2016-11-16 13:00:18 -08:00
parent d7cc1fd81e
commit 9348059b6d
2 changed files with 107 additions and 62 deletions

View File

@@ -1017,15 +1017,15 @@ void PatternMatchEmission::emitWildcardDispatch(ClauseMatrix &clauses,
// Bind the rest of the patterns.
bindIrrefutablePatterns(clauses[row], args, !hasGuard, hasMultipleItems);
SGF.usingImplicitVariablesForPattern(clauses[row].getCasePattern(), dyn_cast<CaseStmt>(stmt), [&]{
// Emit the guard branch, if it exists.
if (guardExpr) {
// Emit the guard branch, if it exists.
if (guardExpr) {
SGF.usingImplicitVariablesForPattern(clauses[row].getCasePattern(), dyn_cast<CaseStmt>(stmt), [&]{
this->emitGuardBranch(guardExpr, guardExpr, failure);
}
});
}
// Enter the row.
CompletionHandler(*this, args, clauses[row]);
});
// Enter the row.
CompletionHandler(*this, args, clauses[row]);
assert(!SGF.B.hasValidInsertionPoint());
}
@@ -1168,6 +1168,13 @@ void PatternMatchEmission::bindVariable(SILLocation loc, VarDecl *var,
CanType formalValueType,
bool isIrrefutable,
bool hasMultipleItems) {
// If this binding is one of multiple patterns, each individual binding
// will just be let, and then the chosen value will get forwarded into
// a var box in the final shared case block.
bool forcedLet = hasMultipleItems && !var->isLet();
if (forcedLet)
var->setLet(true);
// Initialize the variable value.
InitializationPtr init = SGF.emitInitializationForVarDecl(var);
@@ -1177,6 +1184,9 @@ void PatternMatchEmission::bindVariable(SILLocation loc, VarDecl *var,
} else {
std::move(rv).copyInto(SGF, loc, init.get());
}
if (forcedLet)
var->setLet(false);
}
/// Evaluate a guard expression and, if it returns false, branch to
@@ -2092,7 +2102,7 @@ void SILGenFunction::usingImplicitVariablesForPattern(Pattern *pattern, CaseStmt
ArrayRef<CaseLabelItem> labelItems = stmt->getCaseLabelItems();
auto expectedPattern = labelItems[0].getPattern();
if (labelItems.size() <= 1 || pattern == expectedPattern) {
f();
return;
@@ -2100,28 +2110,27 @@ void SILGenFunction::usingImplicitVariablesForPattern(Pattern *pattern, CaseStmt
// Remap vardecls that the case body is expecting to the pattern var locations
// for the given pattern, emit whatever, and switch back.
SmallVector<VarDecl *, 4> expectedVars;
SmallVector<VarLoc, 4> savedVarLocs;
expectedPattern->collectVariables(expectedVars);
for (auto expected : expectedVars)
savedVarLocs.push_back(VarLocs[expected]);
SmallVector<VarDecl *, 4> Vars;
expectedPattern->collectVariables(Vars);
pattern->forEachVariable([&](VarDecl *VD) {
if (!VD->hasName())
return;
for (auto expected : expectedVars) {
if (expected->hasName() && expected->getName() == VD->getName()) {
VarLocs[expected] = VarLocs[VD];
auto variableSwapper = [&] {
pattern->forEachVariable([&](VarDecl *VD) {
if (!VD->hasName())
return;
for (auto expected : Vars) {
if (expected->hasName() && expected->getName() == VD->getName()) {
auto swap = VarLocs[expected];
VarLocs[expected] = VarLocs[VD];
VarLocs[VD] = swap;
return;
}
}
}
});
});
};
variableSwapper();
f();
for (unsigned index = 0; index < savedVarLocs.size(); index++)
VarLocs[expectedVars[index]] = savedVarLocs[index];
variableSwapper();
}
void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
@@ -2148,6 +2157,41 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
JumpDest sharedDest = emission.getSharedCaseBlockDest(caseBlock,
row.hasFallthroughTo());
Cleanups.emitBranchAndCleanups(sharedDest, caseBlock);
} else if (caseBlock->getCaseLabelItems().size() > 1) {
JumpDest sharedDest = emission.getSharedCaseBlockDest(caseBlock,
row.hasFallthroughTo());
// Generate the arguments from this row's pattern in the case block's expected order,
// and keep those arguments from being cleaned up, as we're passing the +1 along to
// the shared case block dest. (The cleanups still happen, as they are threaded through
// here messily, but the explicit retains here counteract them, and then the
// retain/release pair gets optimized out.)
ArrayRef<CaseLabelItem> labelItems = caseBlock->getCaseLabelItems();
SmallVector<SILValue, 4> args;
SmallVector<VarDecl *, 4> expectedVarOrder;
SmallVector<VarDecl *, 4> Vars;
labelItems[0].getPattern()->collectVariables(expectedVarOrder);
row.getCasePattern()->collectVariables(Vars);
for (auto expected : expectedVarOrder) {
if (!expected->hasName())
continue;
for (auto var : Vars) {
if (var->hasName() && var->getName() == expected->getName()) {
auto value = VarLocs[var].value;
for (auto cmv : argArray) {
if (cmv.getValue() == value) {
value = B.emitCopyValueOperation(CurrentSILLoc, value);
break;
}
}
args.push_back(value);
break;
}
}
}
Cleanups.emitBranchAndCleanups(sharedDest, caseBlock, args);
} else {
// However, if we don't have a fallthrough or a multi-pattern 'case', we
// can just emit the body inline and save some dead blocks.