@@ -326,7 +326,8 @@ void SILGenFunction::emitCaptures(SILLocation loc,
326
326
Diags.diagnose (capture.getLoc (), diag::value_captured_here);
327
327
328
328
// Emit an 'undef' of the correct type.
329
- switch (SGM.Types .getDeclCaptureKind (capture, expansion)) {
329
+ auto captureKind = SGM.Types .getDeclCaptureKind (capture, expansion);
330
+ switch (captureKind) {
330
331
case CaptureKind::Constant:
331
332
capturedArgs.push_back (emitUndef (getLoweredType (type)));
332
333
break ;
@@ -338,13 +339,15 @@ void SILGenFunction::emitCaptures(SILLocation loc,
338
339
capturedArgs.push_back (emitUndef (ty));
339
340
break ;
340
341
}
342
+ case CaptureKind::ImmutableBox:
341
343
case CaptureKind::Box: {
344
+ bool isMutable = captureKind == CaptureKind::Box;
342
345
auto boxTy = SGM.Types .getContextBoxTypeForCapture (
343
346
vd,
344
347
SGM.Types .getLoweredRValueType (TypeExpansionContext::minimal (),
345
348
type),
346
349
FunctionDC->getGenericEnvironmentOfContext (),
347
- /* mutable*/ true );
350
+ /* mutable*/ isMutable );
348
351
capturedArgs.push_back (emitUndef (boxTy));
349
352
break ;
350
353
}
@@ -497,6 +500,57 @@ void SILGenFunction::emitCaptures(SILLocation loc,
497
500
498
501
break ;
499
502
}
503
+ case CaptureKind::ImmutableBox: {
504
+ auto entryValue = getAddressValue (Entry.value );
505
+ // LValues are captured as both the box owning the value and the
506
+ // address of the value.
507
+ assert (entryValue->getType ().isAddress () &&
508
+ " no address for captured var!" );
509
+ // Boxes of opaque return values stay opaque.
510
+ auto minimalLoweredType = SGM.Types .getLoweredRValueType (
511
+ TypeExpansionContext::minimal (), type->getCanonicalType ());
512
+ // If this is a boxed variable, we can use it directly.
513
+ if (Entry.box &&
514
+ entryValue->getType ().getASTType () == minimalLoweredType) {
515
+ // We can guarantee our own box to the callee.
516
+ if (canGuarantee) {
517
+ capturedArgs.push_back (
518
+ ManagedValue::forUnmanaged (Entry.box ).borrow (*this , loc));
519
+ } else {
520
+ capturedArgs.push_back (emitManagedRetain (loc, Entry.box ));
521
+ }
522
+ if (captureCanEscape)
523
+ escapesToMark.push_back (entryValue);
524
+ } else {
525
+ // Address only 'let' values are passed by box. This isn't great, in
526
+ // that a variable captured by multiple closures will be boxed for each
527
+ // one. This could be improved by doing an "isCaptured" analysis when
528
+ // emitting address-only let constants, and emit them into an alloc_box
529
+ // like a variable instead of into an alloc_stack.
530
+ //
531
+ // TODO: This might not be profitable anymore with guaranteed captures,
532
+ // since we could conceivably forward the copied value into the
533
+ // closure context and pass it down to the partially applied function
534
+ // in-place.
535
+ // TODO: Use immutable box for immutable captures.
536
+ auto boxTy = SGM.Types .getContextBoxTypeForCapture (
537
+ vd, minimalLoweredType,
538
+ FunctionDC->getGenericEnvironmentOfContext (),
539
+ /* mutable*/ false );
540
+
541
+ AllocBoxInst *allocBox = B.createAllocBox (loc, boxTy);
542
+ ProjectBoxInst *boxAddress = B.createProjectBox (loc, allocBox, 0 );
543
+ B.createCopyAddr (loc, entryValue, boxAddress, IsNotTake,
544
+ IsInitialization);
545
+ if (canGuarantee)
546
+ capturedArgs.push_back (
547
+ emitManagedRValueWithCleanup (allocBox).borrow (*this , loc));
548
+ else
549
+ capturedArgs.push_back (emitManagedRValueWithCleanup (allocBox));
550
+ }
551
+
552
+ break ;
553
+ }
500
554
}
501
555
}
502
556
0 commit comments