@@ -523,7 +523,8 @@ class PatternMatchEmission {
523
523
const FailureHandler &failure);
524
524
525
525
void emitGuardBranch (SILLocation loc, Expr *guard,
526
- const FailureHandler &failure);
526
+ const FailureHandler &failure,
527
+ const ClauseRow &row, ArgArray args);
527
528
528
529
// Bind copyable variable bindings as independent variables.
529
530
void bindIrrefutablePatterns (const ClauseRow &row, ArgArray args,
@@ -1183,25 +1184,21 @@ void PatternMatchEmission::emitWildcardDispatch(ClauseMatrix &clauses,
1183
1184
1184
1185
if (auto ownership = getNoncopyableOwnership ()) {
1185
1186
// A noncopyable pattern match always happens over a borrow first.
1186
- // If there is a guard expression, then we also have to match pattern
1187
- // variables as borrows while executing the guard. This ensures
1188
- // the guard can't consume or modify the value without us committing to this
1189
- // case branch. If the final pattern match is only borrowing as well,
1187
+ // If the final pattern match is only borrowing as well,
1190
1188
// we can bind the variables immediately here too.
1191
- if (hasGuard || *ownership <= ValueOwnership::Shared) {
1189
+ if (*ownership <= ValueOwnership::Shared) {
1192
1190
bindIrrefutableBorrows (clauses[row], args);
1193
1191
}
1194
1192
1195
1193
if (hasGuard) {
1196
- this ->emitGuardBranch (guardExpr, guardExpr, failure);
1194
+ // The guard will bind borrows locally if necessary.
1195
+ this ->emitGuardBranch (guardExpr, guardExpr, failure,
1196
+ clauses[row], args);
1197
1197
}
1198
1198
1199
1199
if (*ownership > ValueOwnership::Shared) {
1200
- // Unbind the variables and unborrow the subject so we can consume it
1201
- // later.
1202
1200
unbindAndEndBorrows (clauses[row], args);
1203
1201
}
1204
-
1205
1202
} else {
1206
1203
// Bind the rest of the patterns.
1207
1204
// For noncopyable bindings, this will bind them as borrows initially if there
@@ -1211,7 +1208,8 @@ void PatternMatchEmission::emitWildcardDispatch(ClauseMatrix &clauses,
1211
1208
1212
1209
// Emit the guard branch, if it exists.
1213
1210
if (guardExpr) {
1214
- this ->emitGuardBranch (guardExpr, guardExpr, failure);
1211
+ this ->emitGuardBranch (guardExpr, guardExpr, failure,
1212
+ clauses[row], args);
1215
1213
}
1216
1214
}
1217
1215
@@ -1244,7 +1242,8 @@ bindRefutablePatterns(const ClauseRow &row, ArgArray args,
1244
1242
FullExpr scope (SGF.Cleanups , CleanupLocation (pattern));
1245
1243
bindVariable (pattern, exprPattern->getMatchVar (), args[i],
1246
1244
/* isForSuccess*/ false , /* hasMultipleItems */ false );
1247
- emitGuardBranch (pattern, exprPattern->getMatchExpr (), failure);
1245
+ emitGuardBranch (pattern, exprPattern->getMatchExpr (), failure,
1246
+ row, args);
1248
1247
break ;
1249
1248
}
1250
1249
default :
@@ -1391,21 +1390,39 @@ void PatternMatchEmission::bindBorrow(Pattern *pattern, VarDecl *var,
1391
1390
ConsumableManagedValue value) {
1392
1391
assert (value.getFinalConsumption () == CastConsumptionKind::BorrowAlways);
1393
1392
1394
- SGF.VarLocs [var] = SILGenFunction::VarLoc::get (
1395
- value.asBorrowedOperand2 (SGF, pattern).getValue ());
1393
+ auto bindValue = value.asBorrowedOperand2 (SGF, pattern).getFinalManagedValue ();
1394
+ if (bindValue.getType ().isMoveOnly ()) {
1395
+ if (bindValue.getType ().isObject ()) {
1396
+ // Create a notional copy for the borrow checker to use.
1397
+ bindValue = bindValue.copy (SGF, pattern);
1398
+ }
1399
+ bindValue = SGF.B .createMarkUnresolvedNonCopyableValueInst (pattern, bindValue,
1400
+ MarkUnresolvedNonCopyableValueInst::CheckKind::NoConsumeOrAssign);
1401
+ }
1402
+ SGF.VarLocs [var] = SILGenFunction::VarLoc::get (bindValue.getValue ());
1396
1403
}
1397
1404
1398
1405
// / Evaluate a guard expression and, if it returns false, branch to
1399
1406
// / the given destination.
1400
1407
void PatternMatchEmission::emitGuardBranch (SILLocation loc, Expr *guard,
1401
- const FailureHandler &failure) {
1408
+ const FailureHandler &failure,
1409
+ const ClauseRow &row, ArgArray args){
1402
1410
SILBasicBlock *falseBB = SGF.B .splitBlockForFallthrough ();
1403
1411
SILBasicBlock *trueBB = SGF.B .splitBlockForFallthrough ();
1404
1412
1405
1413
// Emit the match test.
1406
1414
SILValue testBool;
1407
1415
{
1408
1416
FullExpr scope (SGF.Cleanups , CleanupLocation (guard));
1417
+
1418
+ // If the final pattern match is destructive, then set up borrow bindings
1419
+ // to evaluate the guard expression without allowing it to destruct the
1420
+ // subject yet.
1421
+ if (auto ownership = getNoncopyableOwnership ()) {
1422
+ if (*ownership > ValueOwnership::Shared) {
1423
+ bindIrrefutableBorrows (row, args);
1424
+ }
1425
+ }
1409
1426
testBool = SGF.emitRValueAsSingleValue (guard).getUnmanagedValue ();
1410
1427
}
1411
1428
@@ -2720,33 +2737,28 @@ void PatternMatchEmission::emitDestructiveCaseBlocks() {
2720
2737
CleanupState::PersistentlyActive);
2721
2738
}
2722
2739
2723
- {
2724
- // Create a scope to break down the subject value.
2725
- Scope caseScope (SGF, pattern);
2726
-
2727
- // Clone the original subject's cleanup state so that it will be reliably
2728
- // consumed in this scope, while leaving the original for other case
2729
- // blocks to re-consume.
2730
- ManagedValue subject = SGF.emitManagedRValueWithCleanup (
2731
- NoncopyableConsumableValue.forward (SGF));
2732
-
2733
- // TODO: handle fallthroughs and multiple cases bindings
2734
- // In those cases we'd need to forward bindings through the shared case
2735
- // destination blocks.
2736
- assert (!stmt->hasFallthroughDest ()
2737
- && stmt->getCaseLabelItems ().size () == 1 );
2738
-
2739
- // Bind variables from the pattern.
2740
- if (stmt->hasCaseBodyVariables ()) {
2741
- ConsumingPatternBindingVisitor (*this , stmt)
2742
- .visit (pattern, subject);
2743
- }
2744
-
2745
- // By this point, whatever parts of the value we bound are forwarded into
2746
- // variables, so we can pop the scope and destroy the remainder before
2747
- // entering the case body (TODO: or common block).
2748
- }
2740
+ // Create a scope to break down the subject value.
2741
+ Scope caseScope (SGF, pattern);
2749
2742
2743
+ // Clone the original subject's cleanup state so that it will be reliably
2744
+ // consumed in this scope, while leaving the original for other case
2745
+ // blocks to re-consume.
2746
+ ManagedValue subject = SGF.emitManagedRValueWithCleanup (
2747
+ NoncopyableConsumableValue.forward (SGF));
2748
+
2749
+ // TODO: handle fallthroughs and multiple cases bindings
2750
+ // In those cases we'd need to forward bindings through the shared case
2751
+ // destination blocks.
2752
+ assert (!stmt->hasFallthroughDest ()
2753
+ && stmt->getCaseLabelItems ().size () == 1 );
2754
+
2755
+ // Bind variables from the pattern.
2756
+ if (stmt->hasCaseBodyVariables ()) {
2757
+ ConsumingPatternBindingVisitor (*this , stmt)
2758
+ .visit (pattern, subject);
2759
+ }
2760
+
2761
+ // Emit the case body.
2750
2762
emitCaseBody (stmt);
2751
2763
}
2752
2764
}
0 commit comments