@@ -459,147 +459,145 @@ ManagedValue SILGenFunction::emitExistentialErasure(
459
459
// If we're erasing to the 'Error' type, we might be able to get an NSError
460
460
// representation more efficiently.
461
461
auto &ctx = getASTContext ();
462
- auto nsError = ctx.getNSErrorDecl ();
463
- if (allowEmbeddedNSError && nsError &&
464
- existentialTL.getSemanticType ().getSwiftRValueType ()->getAnyNominal () ==
465
- ctx.getErrorDecl ()) {
466
- // Check whether the concrete type conforms to the _BridgedStoredNSError
467
- // protocol. In that case, call the _nsError witness getter to extract the
468
- // NSError directly.
469
- auto conformance =
470
- SGM.getConformanceToBridgedStoredNSError (loc, concreteFormalType);
471
-
472
- CanType nsErrorType =
473
- nsError->getDeclaredInterfaceType ()->getCanonicalType ();
474
-
475
- ProtocolConformanceRef nsErrorConformances[1 ] = {
476
- ProtocolConformanceRef (SGM.getNSErrorConformanceToError ())
477
- };
478
-
479
- if (conformance && nsError && SGM.getNSErrorConformanceToError ()) {
480
- if (auto witness =
481
- conformance->getWitness (SGM.getNSErrorRequirement (loc), nullptr )) {
482
- // Create a reference to the getter witness.
483
- SILDeclRef getter =
484
- getGetterDeclRef (cast<VarDecl>(witness.getDecl ()),
485
- /* isDirectAccessorUse=*/ true );
486
-
487
- // Compute the substitutions.
488
- ArrayRef<Substitution> substitutions =
489
- concreteFormalType->gatherAllSubstitutions (
490
- SGM.SwiftModule , nullptr );
491
-
492
- // Emit the erasure, through the getter to _nsError.
493
- return emitExistentialErasure (
494
- loc, nsErrorType,
495
- getTypeLowering (nsErrorType),
496
- existentialTL,
497
- ctx.AllocateCopy (nsErrorConformances),
498
- C,
499
- [&](SGFContext innerC) -> ManagedValue {
500
- // Call the getter.
501
- return emitGetAccessor (loc, getter, substitutions,
502
- ArgumentSource (loc,
503
- RValue (*this , loc,
504
- concreteFormalType,
505
- F (SGFContext ()))),
506
- /* isSuper=*/ false ,
507
- /* isDirectAccessorUse=*/ true ,
508
- RValue (), innerC)
509
- .getAsSingleValue (*this , loc);
510
- });
462
+ if (conformances.size () == 1 &&
463
+ conformances[0 ].getRequirement () == ctx.getErrorDecl () &&
464
+ ctx.getNSErrorDecl ()) {
465
+ auto nsErrorDecl = ctx.getNSErrorDecl ();
466
+
467
+ // If the concrete type is NSError or a subclass thereof, just erase it
468
+ // directly.
469
+ auto nsErrorType = nsErrorDecl->getDeclaredType ()->getCanonicalType ();
470
+ if (nsErrorType->isExactSuperclassOf (concreteFormalType, nullptr )) {
471
+ ManagedValue nsError = F (SGFContext ());
472
+ if (nsErrorType != concreteFormalType) {
473
+ nsError = ManagedValue (B.createUpcast (loc, nsError.getValue (),
474
+ getLoweredType (nsErrorType)),
475
+ nsError.getCleanup ());
511
476
}
477
+ return emitBridgedToNativeError (loc, nsError);
512
478
}
513
479
514
- // Check whether the concrete type is an archetype. If so, call the
515
- // _getEmbeddedNSError() witness to try to dig out the embedded NSError.
516
- if (auto archetypeType = concreteFormalType->getAs <ArchetypeType>()) {
517
- if (std::find (archetypeType->getConformsTo ().begin (),
518
- archetypeType->getConformsTo ().end (),
519
- ctx.getErrorDecl ())
520
- != archetypeType->getConformsTo ().end ()) {
521
- auto contBB = createBasicBlock ();
522
- auto isNotPresentBB = createBasicBlock ();
523
- auto isPresentBB = createBasicBlock ();
524
-
525
- SILValue existentialResult =
526
- contBB->createBBArg (existentialTL.getLoweredType ());
527
-
528
- ProtocolConformanceRef trivialErrorConformances[1 ] = {
529
- ProtocolConformanceRef (ctx.getErrorDecl ())
530
- };
531
-
532
- Substitution substitutions[1 ] = {
533
- Substitution (concreteFormalType,
534
- ctx.AllocateCopy (trivialErrorConformances))
535
- };
536
-
537
- // Call swift_stdlib_getErrorEmbeddedNSError to attempt to extract an
538
- // NSError from the value.
539
- ManagedValue concreteValue = F (SGFContext ());
540
- ManagedValue potentialNSError =
541
- emitApplyOfLibraryIntrinsic (loc,
542
- SGM.getGetErrorEmbeddedNSError (loc),
543
- ctx.AllocateCopy (substitutions),
544
- { concreteValue },
545
- SGFContext ())
546
- .getAsSingleValue (*this , loc);
547
-
548
- // Check whether we got an NSError back.
549
- SILValue hasNSError =
550
- emitDoesOptionalHaveValue (loc, potentialNSError.getValue ());
551
-
552
- B.createCondBranch (loc, hasNSError, isPresentBB, isNotPresentBB);
553
-
554
- // If we did get an NSError, emit the existential erasure from that
555
- // NSError.
556
- B.emitBlock (isPresentBB);
557
- SILValue branchArg;
558
- {
559
- // Don't allow cleanups to escape the conditional block.
560
- FullExpr presentScope (Cleanups, CleanupLocation::get (loc));
561
-
562
- // Emit the existential erasure from the NSError.
563
- branchArg = emitExistentialErasure (
564
- loc, nsErrorType,
565
- getTypeLowering (nsErrorType),
566
- existentialTL,
567
- ctx.AllocateCopy (nsErrorConformances),
568
- C,
569
- [&](SGFContext innerC) -> ManagedValue {
570
- // Pull the NSError object out of the optional result.
571
- auto &inputTL = getTypeLowering (potentialNSError.getType ());
572
- auto nsErrorValue =
573
- emitUncheckedGetOptionalValueFrom (loc, potentialNSError,
574
- inputTL);
575
-
576
-
577
- // Perform an unchecked cast down to NSError, because it was typed
578
- // as 'AnyObject' for layering reasons.
579
- return ManagedValue (B.createUncheckedRefCast (
580
- loc,
581
- nsErrorValue.getValue (),
582
- getLoweredType (nsErrorType)),
583
- nsErrorValue.getCleanup ());
584
-
585
- }).forward (*this );
480
+ // If the concrete type is known to conform to _BridgedStoredNSError,
481
+ // call the _nsError witness getter to extract the NSError directly,
482
+ // then just erase the NSError.
483
+ if (auto storedNSErrorConformance =
484
+ SGM.getConformanceToBridgedStoredNSError (loc, concreteFormalType)) {
485
+ auto nsErrorVar = SGM.getNSErrorRequirement (loc);
486
+ if (!nsErrorVar) return emitUndef (loc, existentialTL.getLoweredType ());
487
+
488
+ ArrayRef<Substitution> nsErrorVarSubstitutions;
489
+
490
+ // Devirtualize. Maybe this should be done implicitly by
491
+ // emitPropertyLValue?
492
+ if (storedNSErrorConformance->isConcrete ()) {
493
+ if (auto witnessVar = storedNSErrorConformance->getConcrete ()
494
+ ->getWitness (nsErrorVar, nullptr )) {
495
+ nsErrorVar = cast<VarDecl>(witnessVar.getDecl ());
496
+ nsErrorVarSubstitutions = witnessVar.getSubstitutions ();
586
497
}
587
- B. createBranch (loc, contBB, branchArg);
498
+ }
588
499
589
- // If we did not get an NSError, just directly emit the existential
590
- // (recursively).
591
- B.emitBlock (isNotPresentBB);
500
+ auto nativeError = F (SGFContext ());
501
+
502
+ WritebackScope writebackScope (*this );
503
+ auto nsError =
504
+ emitRValueForPropertyLoad (loc, nativeError, concreteFormalType,
505
+ /* super*/ false , nsErrorVar,
506
+ nsErrorVarSubstitutions,
507
+ AccessSemantics::Ordinary, nsErrorType,
508
+ SGFContext ())
509
+ .getAsSingleValue (*this , loc);
510
+
511
+ return emitBridgedToNativeError (loc, nsError);
512
+ }
513
+
514
+ // Otherwise, if it's an archetype, try calling the _getEmbeddedNSError()
515
+ // witness to try to dig out the embedded NSError. But don't do this
516
+ // when we're being called recursively.
517
+ if (isa<ArchetypeType>(concreteFormalType) && allowEmbeddedNSError) {
518
+ auto contBB = createBasicBlock ();
519
+ auto isNotPresentBB = createBasicBlock ();
520
+ auto isPresentBB = createBasicBlock ();
521
+
522
+ // Call swift_stdlib_getErrorEmbeddedNSError to attempt to extract an
523
+ // NSError from the value.
524
+ auto getEmbeddedNSErrorFn = SGM.getGetErrorEmbeddedNSError (loc);
525
+ if (!getEmbeddedNSErrorFn)
526
+ return emitUndef (loc, existentialTL.getLoweredType ());
527
+
528
+ Substitution getEmbeddedNSErrorSubstitutions[1 ] = {
529
+ Substitution (concreteFormalType, conformances)
530
+ };
531
+
532
+ ManagedValue concreteValue = F (SGFContext ());
533
+ ManagedValue potentialNSError =
534
+ emitApplyOfLibraryIntrinsic (loc,
535
+ getEmbeddedNSErrorFn,
536
+ getEmbeddedNSErrorSubstitutions,
537
+ { concreteValue.copy (*this , loc) },
538
+ SGFContext ())
539
+ .getAsSingleValue (*this , loc);
540
+
541
+ // We're going to consume 'concreteValue' in exactly one branch,
542
+ // so kill its cleanup now and recreate it on both branches.
543
+ (void ) concreteValue.forward (*this );
544
+
545
+ // Check whether we got an NSError back.
546
+ std::pair<EnumElementDecl*, SILBasicBlock*> cases[] = {
547
+ { ctx.getOptionalSomeDecl (), isPresentBB },
548
+ { ctx.getOptionalNoneDecl (), isNotPresentBB }
549
+ };
550
+ B.createSwitchEnum (loc, potentialNSError.forward (*this ),
551
+ /* default*/ nullptr , cases);
552
+
553
+ // If we did get an NSError, emit the existential erasure from that
554
+ // NSError.
555
+ B.emitBlock (isPresentBB);
556
+ SILValue branchArg;
557
+ {
558
+ // Don't allow cleanups to escape the conditional block.
559
+ FullExpr presentScope (Cleanups, CleanupLocation::get (loc));
560
+ enterDestroyCleanup (concreteValue.getValue ());
561
+
562
+ // Receive the error value. It's typed as an 'AnyObject' for
563
+ // layering reasons, so perform an unchecked cast down to NSError.
564
+ OptionalTypeKind optKind;
565
+ SILType anyObjectTy =
566
+ potentialNSError.getType ().getAnyOptionalObjectType (SGM.M , optKind);
567
+ SILValue nsError = isPresentBB->createBBArg (anyObjectTy);
568
+ nsError = B.createUncheckedRefCast (loc, nsError,
569
+ getLoweredType (nsErrorType));
570
+
571
+ branchArg = emitBridgedToNativeError (loc,
572
+ emitManagedRValueWithCleanup (nsError))
573
+ .forward (*this );
574
+ }
575
+ B.createBranch (loc, contBB, branchArg);
576
+
577
+ // If we did not get an NSError, just directly emit the existential.
578
+ // Since this is a recursive call, make sure we don't end up in this
579
+ // path again.
580
+ B.emitBlock (isNotPresentBB);
581
+ {
582
+ FullExpr presentScope (Cleanups, CleanupLocation::get (loc));
583
+ concreteValue = emitManagedRValueWithCleanup (concreteValue.getValue ());
592
584
branchArg = emitExistentialErasure (loc, concreteFormalType, concreteTL,
593
585
existentialTL, conformances,
594
- SGFContext (), F,
586
+ SGFContext (),
587
+ [&](SGFContext C) {
588
+ return concreteValue;
589
+ },
595
590
/* allowEmbeddedNSError=*/ false )
596
591
.forward (*this );
597
- B.createBranch (loc, contBB, branchArg);
598
-
599
- // Continue.
600
- B.emitBlock (contBB);
601
- return emitManagedRValueWithCleanup (existentialResult, existentialTL);
602
592
}
593
+ B.createBranch (loc, contBB, branchArg);
594
+
595
+ // Continue.
596
+ B.emitBlock (contBB);
597
+
598
+ SILValue existentialResult =
599
+ contBB->createBBArg (existentialTL.getLoweredType ());
600
+ return emitManagedRValueWithCleanup (existentialResult, existentialTL);
603
601
}
604
602
}
605
603
@@ -641,14 +639,12 @@ ManagedValue SILGenFunction::emitExistentialErasure(
641
639
concreteTL.getLoweredType (),
642
640
existential);
643
641
// Initialize the concrete value in-place.
644
- InitializationPtr init (
645
- new ExistentialInitialization (existential, valueAddr, concreteFormalType,
646
- ExistentialRepresentation::Boxed,
647
- *this ));
648
- ManagedValue mv = F (SGFContext (init.get ()));
642
+ ExistentialInitialization init (existential, valueAddr, concreteFormalType,
643
+ ExistentialRepresentation::Boxed, *this );
644
+ ManagedValue mv = F (SGFContext (&init));
649
645
if (!mv.isInContext ()) {
650
- mv.forwardInto (*this , loc, init-> getAddress ());
651
- init-> finishInitialization (*this );
646
+ mv.forwardInto (*this , loc, init. getAddress ());
647
+ init. finishInitialization (*this );
652
648
}
653
649
654
650
return emitManagedRValueWithCleanup (existential);
0 commit comments