@@ -403,27 +403,55 @@ static bool loadSpecialReferenceStorage(HeapObject *owner,
403
403
OpaqueValue *fieldData,
404
404
const FieldType fieldType,
405
405
Mirror *outMirror) {
406
- // TODO: Switch over the other kinds of reference storage here:
407
- // - unowned(safe)
408
- // - unowned(unsafe)
409
- // - class-bound existentials
410
- // - Optional existential types
411
- // This will require a change in the two low flag bits in the field type
412
- // returned from the field type accessor generated by IRGen.
413
-
414
406
// isWeak() implies a reference type via Sema.
415
407
if (!fieldType.isWeak ())
416
408
return false ;
417
409
410
+ auto type = fieldType.getType ();
411
+ assert (type->getKind () == MetadataKind::Optional);
412
+
418
413
auto weakField = reinterpret_cast <WeakReference *>(fieldData);
419
414
auto strongValue = swift_unknownWeakLoadStrong (weakField);
420
- fieldData = reinterpret_cast <OpaqueValue *>(&strongValue);
415
+
416
+ // Now that we have a strong reference, we need to create a temporary buffer
417
+ // from which to copy the whole value, which might be a native class-bound
418
+ // existential, which means we also need to copy n witness tables, for
419
+ // however many protocols are in the protocol composition. For example, if we
420
+ // are copying a:
421
+ // weak var myWeakProperty : (Protocol1 & Protocol2)?
422
+ // then we need to copy three values:
423
+ // - the instance
424
+ // - the witness table for Protocol1
425
+ // - the witness table for Protocol2
426
+
427
+ auto weakContainer =
428
+ reinterpret_cast <WeakClassExistentialContainer *>(fieldData);
429
+
430
+ // Create a temporary existential where we can put the strong reference.
431
+ // The allocateBuffer value witness requires a ValueBuffer to own the
432
+ // allocated storage.
433
+ ValueBuffer temporaryBuffer;
434
+
435
+ auto temporaryValue =
436
+ reinterpret_cast <ClassExistentialContainer *>(
437
+ type->vw_allocateBuffer (&temporaryBuffer));
438
+
439
+ // Now copy the entire value out of the parent, which will include the
440
+ // witness tables.
441
+ temporaryValue->Value = strongValue;
442
+ auto valueWitnessesSize = type->getValueWitnesses ()->getSize () -
443
+ sizeof (WeakClassExistentialContainer);
444
+ memcpy (temporaryValue->getWitnessTables (), weakContainer->getWitnessTables (),
445
+ valueWitnessesSize);
421
446
422
447
// This MagicMirror constructor creates a box to hold the loaded refernce
423
448
// value, which becomes the new owner for the value.
424
- new (outMirror) MagicMirror (fieldData, fieldType.getType (), /* take*/ true );
449
+ new (outMirror) MagicMirror (reinterpret_cast <OpaqueValue *>(temporaryValue),
450
+ type, /* take*/ true );
451
+
452
+ type->vw_deallocateBuffer (&temporaryBuffer);
425
453
426
- // However, swift_StructMirror_subscript and swift_ClassMirror_subscript
454
+ // swift_StructMirror_subscript and swift_ClassMirror_subscript
427
455
// requires that the owner be consumed. Since we have the new heap box as the
428
456
// owner now, we need to release the old owner to maintain the contract.
429
457
if (owner->metadata ->isAnyClass ())
0 commit comments