@@ -523,7 +523,8 @@ class PatternMatchEmission {
523523 const FailureHandler &failure);
524524
525525 void emitGuardBranch (SILLocation loc, Expr *guard,
526- const FailureHandler &failure);
526+ const FailureHandler &failure,
527+ const ClauseRow &row, ArgArray args);
527528
528529 // Bind copyable variable bindings as independent variables.
529530 void bindIrrefutablePatterns (const ClauseRow &row, ArgArray args,
@@ -1183,25 +1184,21 @@ void PatternMatchEmission::emitWildcardDispatch(ClauseMatrix &clauses,
11831184
11841185 if (auto ownership = getNoncopyableOwnership ()) {
11851186 // 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,
11901188 // we can bind the variables immediately here too.
1191- if (hasGuard || *ownership <= ValueOwnership::Shared) {
1189+ if (*ownership <= ValueOwnership::Shared) {
11921190 bindIrrefutableBorrows (clauses[row], args);
11931191 }
11941192
11951193 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);
11971197 }
11981198
11991199 if (*ownership > ValueOwnership::Shared) {
1200- // Unbind the variables and unborrow the subject so we can consume it
1201- // later.
12021200 unbindAndEndBorrows (clauses[row], args);
12031201 }
1204-
12051202 } else {
12061203 // Bind the rest of the patterns.
12071204 // For noncopyable bindings, this will bind them as borrows initially if there
@@ -1211,7 +1208,8 @@ void PatternMatchEmission::emitWildcardDispatch(ClauseMatrix &clauses,
12111208
12121209 // Emit the guard branch, if it exists.
12131210 if (guardExpr) {
1214- this ->emitGuardBranch (guardExpr, guardExpr, failure);
1211+ this ->emitGuardBranch (guardExpr, guardExpr, failure,
1212+ clauses[row], args);
12151213 }
12161214 }
12171215
@@ -1244,7 +1242,8 @@ bindRefutablePatterns(const ClauseRow &row, ArgArray args,
12441242 FullExpr scope (SGF.Cleanups , CleanupLocation (pattern));
12451243 bindVariable (pattern, exprPattern->getMatchVar (), args[i],
12461244 /* isForSuccess*/ false , /* hasMultipleItems */ false );
1247- emitGuardBranch (pattern, exprPattern->getMatchExpr (), failure);
1245+ emitGuardBranch (pattern, exprPattern->getMatchExpr (), failure,
1246+ row, args);
12481247 break ;
12491248 }
12501249 default :
@@ -1391,21 +1390,39 @@ void PatternMatchEmission::bindBorrow(Pattern *pattern, VarDecl *var,
13911390 ConsumableManagedValue value) {
13921391 assert (value.getFinalConsumption () == CastConsumptionKind::BorrowAlways);
13931392
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 ());
13961403}
13971404
13981405// / Evaluate a guard expression and, if it returns false, branch to
13991406// / the given destination.
14001407void PatternMatchEmission::emitGuardBranch (SILLocation loc, Expr *guard,
1401- const FailureHandler &failure) {
1408+ const FailureHandler &failure,
1409+ const ClauseRow &row, ArgArray args){
14021410 SILBasicBlock *falseBB = SGF.B .splitBlockForFallthrough ();
14031411 SILBasicBlock *trueBB = SGF.B .splitBlockForFallthrough ();
14041412
14051413 // Emit the match test.
14061414 SILValue testBool;
14071415 {
14081416 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+ }
14091426 testBool = SGF.emitRValueAsSingleValue (guard).getUnmanagedValue ();
14101427 }
14111428
@@ -2720,33 +2737,28 @@ void PatternMatchEmission::emitDestructiveCaseBlocks() {
27202737 CleanupState::PersistentlyActive);
27212738 }
27222739
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);
27492742
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.
27502762 emitCaseBody (stmt);
27512763 }
27522764}
0 commit comments