@@ -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,38 @@ 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 ().isObject ()) {
1395+ // Create a notional copy for the borrow checker to use.
1396+ bindValue = bindValue.copy (SGF, pattern);
1397+ }
1398+ bindValue = SGF.B .createMarkUnresolvedNonCopyableValueInst (pattern, bindValue,
1399+ MarkUnresolvedNonCopyableValueInst::CheckKind::NoConsumeOrAssign);
1400+
1401+ SGF.VarLocs [var] = SILGenFunction::VarLoc::get (bindValue.getValue ());
13961402}
13971403
13981404// / Evaluate a guard expression and, if it returns false, branch to
13991405// / the given destination.
14001406void PatternMatchEmission::emitGuardBranch (SILLocation loc, Expr *guard,
1401- const FailureHandler &failure) {
1407+ const FailureHandler &failure,
1408+ const ClauseRow &row, ArgArray args){
14021409 SILBasicBlock *falseBB = SGF.B .splitBlockForFallthrough ();
14031410 SILBasicBlock *trueBB = SGF.B .splitBlockForFallthrough ();
14041411
14051412 // Emit the match test.
14061413 SILValue testBool;
14071414 {
14081415 FullExpr scope (SGF.Cleanups , CleanupLocation (guard));
1416+
1417+ // If the final pattern match is destructive, then set up borrow bindings
1418+ // to evaluate the guard expression without allowing it to destruct the
1419+ // subject yet.
1420+ if (auto ownership = getNoncopyableOwnership ()) {
1421+ if (*ownership > ValueOwnership::Shared) {
1422+ bindIrrefutableBorrows (row, args);
1423+ }
1424+ }
14091425 testBool = SGF.emitRValueAsSingleValue (guard).getUnmanagedValue ();
14101426 }
14111427
@@ -2720,33 +2736,28 @@ void PatternMatchEmission::emitDestructiveCaseBlocks() {
27202736 CleanupState::PersistentlyActive);
27212737 }
27222738
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- }
2739+ // Create a scope to break down the subject value.
2740+ Scope caseScope (SGF, pattern);
27492741
2742+ // Clone the original subject's cleanup state so that it will be reliably
2743+ // consumed in this scope, while leaving the original for other case
2744+ // blocks to re-consume.
2745+ ManagedValue subject = SGF.emitManagedRValueWithCleanup (
2746+ NoncopyableConsumableValue.forward (SGF));
2747+
2748+ // TODO: handle fallthroughs and multiple cases bindings
2749+ // In those cases we'd need to forward bindings through the shared case
2750+ // destination blocks.
2751+ assert (!stmt->hasFallthroughDest ()
2752+ && stmt->getCaseLabelItems ().size () == 1 );
2753+
2754+ // Bind variables from the pattern.
2755+ if (stmt->hasCaseBodyVariables ()) {
2756+ ConsumingPatternBindingVisitor (*this , stmt)
2757+ .visit (pattern, subject);
2758+ }
2759+
2760+ // Emit the case body.
27502761 emitCaseBody (stmt);
27512762 }
27522763}
0 commit comments