@@ -2497,37 +2497,55 @@ class Lowering::PatternMatchContext {
2497
2497
PatternMatchEmission &Emission;
2498
2498
};
2499
2499
2500
+ namespace {
2501
+
2502
+ struct UnexpectedEnumCaseInfo {
2503
+ CanType subjectTy;
2504
+ ManagedValue metatype;
2505
+ ManagedValue rawValue;
2506
+ NullablePtr<const EnumDecl> singleObjCEnum;
2507
+
2508
+ UnexpectedEnumCaseInfo (CanType subjectTy, ManagedValue metatype,
2509
+ ManagedValue rawValue, const EnumDecl *singleObjCEnum)
2510
+ : subjectTy(subjectTy), metatype(metatype), rawValue(rawValue),
2511
+ singleObjCEnum (singleObjCEnum) {
2512
+ assert (isa<MetatypeInst>(metatype));
2513
+ assert (bool (rawValue) && isa<UncheckedTrivialBitCastInst>(rawValue));
2514
+ assert (singleObjCEnum->hasRawType ());
2515
+ }
2516
+
2517
+ UnexpectedEnumCaseInfo (CanType subjectTy, ManagedValue valueMetatype)
2518
+ : subjectTy(subjectTy), metatype(valueMetatype), rawValue(),
2519
+ singleObjCEnum() {
2520
+ assert (isa<ValueMetatypeInst>(valueMetatype));
2521
+ }
2522
+
2523
+ bool isSingleObjCEnum () const { return singleObjCEnum.isNonNull (); }
2524
+
2525
+ void cleanupInstsIfUnused () {
2526
+ auto f = [](SILValue v) {
2527
+ if (!v->use_empty ())
2528
+ return ;
2529
+ cast<SingleValueInstruction>(v)->eraseFromParent ();
2530
+ };
2531
+ f (metatype.getValue ());
2532
+ if (rawValue)
2533
+ f (rawValue.getValue ());
2534
+ }
2535
+ };
2536
+
2537
+ } // end anonymous namespace
2538
+
2500
2539
static void emitDiagnoseOfUnexpectedEnumCaseValue (SILGenFunction &SGF,
2501
2540
SILLocation loc,
2502
- ManagedValue value,
2503
- Type subjectTy,
2504
- const EnumDecl *enumDecl) {
2541
+ UnexpectedEnumCaseInfo ueci) {
2505
2542
ASTContext &ctx = SGF.getASTContext ();
2506
2543
auto diagnoseFailure = ctx.getDiagnoseUnexpectedEnumCaseValue ();
2507
2544
if (!diagnoseFailure) {
2508
2545
SGF.B .createBuiltinTrap (loc);
2509
2546
return ;
2510
2547
}
2511
2548
2512
- assert (enumDecl->isObjC ());
2513
- assert (enumDecl->hasRawType ());
2514
- assert (value.getType ().isTrivial (SGF.F ));
2515
-
2516
- // Get the enum type as an Any.Type value.
2517
- SILType metatypeType = SGF.getLoweredType (
2518
- AbstractionPattern::getOpaque (),
2519
- MetatypeType::get (subjectTy));
2520
- SILValue metatype = SGF.B .createMetatype (loc, metatypeType);
2521
-
2522
- // Bitcast the enum value to its raw type. (This is only safe for @objc
2523
- // enums.)
2524
- SILType loweredRawType = SGF.getLoweredType (enumDecl->getRawType ());
2525
- assert (loweredRawType.isTrivial (SGF.F ));
2526
- assert (loweredRawType.isObject ());
2527
- auto rawValue = SGF.B .createUncheckedTrivialBitCast (loc, value,
2528
- loweredRawType);
2529
- auto materializedRawValue = rawValue.materialize (SGF, loc);
2530
-
2531
2549
auto genericSig = diagnoseFailure->getGenericSignature ();
2532
2550
auto subs = SubstitutionMap::get (
2533
2551
genericSig,
@@ -2537,49 +2555,40 @@ static void emitDiagnoseOfUnexpectedEnumCaseValue(SILGenFunction &SGF,
2537
2555
assert (genericParam->getIndex () < 2 );
2538
2556
switch (genericParam->getIndex ()) {
2539
2557
case 0 :
2540
- return subjectTy;
2558
+ return ueci. subjectTy ;
2541
2559
2542
2560
case 1 :
2543
- return enumDecl ->getRawType ();
2561
+ return ueci. singleObjCEnum . get () ->getRawType ();
2544
2562
2545
2563
default :
2546
2564
llvm_unreachable (" wrong generic signature for expected case value" );
2547
2565
}
2548
2566
},
2549
2567
LookUpConformanceInSignature (*genericSig));
2550
2568
2551
- SGF.emitApplyOfLibraryIntrinsic (loc, diagnoseFailure, subs,
2552
- {ManagedValue::forUnmanaged (metatype),
2553
- materializedRawValue},
2554
- SGFContext ());
2569
+ SGF.emitApplyOfLibraryIntrinsic (
2570
+ loc, diagnoseFailure, subs,
2571
+ {ueci.metatype , ueci.rawValue .materialize (SGF, loc)}, SGFContext ());
2555
2572
}
2556
2573
2557
2574
static void emitDiagnoseOfUnexpectedEnumCase (SILGenFunction &SGF,
2558
2575
SILLocation loc,
2559
- ManagedValue value,
2560
- Type subjectTy) {
2576
+ UnexpectedEnumCaseInfo ueci) {
2561
2577
ASTContext &ctx = SGF.getASTContext ();
2562
2578
auto diagnoseFailure = ctx.getDiagnoseUnexpectedEnumCase ();
2563
2579
if (!diagnoseFailure) {
2564
2580
SGF.B .createBuiltinTrap (loc);
2565
2581
return ;
2566
2582
}
2567
2583
2568
- // Get the switched-upon value's type.
2569
- SILType metatypeType = SGF.getLoweredType (
2570
- AbstractionPattern::getOpaque (),
2571
- MetatypeType::get (subjectTy)->getCanonicalType ());
2572
- ManagedValue metatype = SGF.B .createValueMetatype (loc, metatypeType, value);
2573
-
2574
2584
auto diagnoseSignature = diagnoseFailure->getGenericSignature ();
2575
2585
auto genericArgsMap = SubstitutionMap::get (
2576
2586
diagnoseSignature,
2577
- [&](SubstitutableType *type) -> Type { return subjectTy; },
2587
+ [&](SubstitutableType *type) -> Type { return ueci. subjectTy ; },
2578
2588
LookUpConformanceInSignature (*diagnoseSignature));
2579
2589
2580
2590
SGF.emitApplyOfLibraryIntrinsic (loc, diagnoseFailure, genericArgsMap,
2581
- metatype,
2582
- SGFContext ());
2591
+ ueci.metatype , SGFContext ());
2583
2592
}
2584
2593
2585
2594
static void switchCaseStmtSuccessCallback (SILGenFunction &SGF,
@@ -2778,6 +2787,38 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2778
2787
return {subjectMV.copy (*this , S), CastConsumptionKind::TakeAlways};
2779
2788
}());
2780
2789
2790
+ // If we need to diagnose an unexpected enum case or unexpected enum case
2791
+ // value, we need access to a value metatype for the subject. Emit this state
2792
+ // now before we emit the actual switch to ensure that the subject has not
2793
+ // been consumed.
2794
+ auto unexpectedEnumCaseInfo = ([&]() -> UnexpectedEnumCaseInfo {
2795
+ SILLocation loc = RegularLocation::getAutoGeneratedLocation ();
2796
+ CanType canSubjectTy = subjectTy->getCanonicalType ();
2797
+ CanType metatypeType = MetatypeType::get (canSubjectTy)->getCanonicalType ();
2798
+ SILType loweredMetatypeType =
2799
+ getLoweredType (AbstractionPattern::getOpaque (), metatypeType);
2800
+ ManagedValue value = subject.getFinalManagedValue ();
2801
+
2802
+ if (auto *singleEnumDecl = canSubjectTy->getEnumOrBoundGenericEnum ()) {
2803
+ if (singleEnumDecl->isObjC ()) {
2804
+ auto metatype = ManagedValue::forUnmanaged (
2805
+ B.createMetatype (loc, loweredMetatypeType));
2806
+
2807
+ // Bitcast the enum value to its raw type. (This is only safe for @objc
2808
+ // enums.)
2809
+ SILType loweredRawType = getLoweredType (singleEnumDecl->getRawType ());
2810
+ assert (loweredRawType.isTrivial (F));
2811
+ assert (loweredRawType.isObject ());
2812
+ auto rawValue =
2813
+ B.createUncheckedTrivialBitCast (loc, value, loweredRawType);
2814
+ return {canSubjectTy, metatype, rawValue, singleEnumDecl};
2815
+ }
2816
+ }
2817
+
2818
+ return {canSubjectTy,
2819
+ B.createValueMetatype (loc, loweredMetatypeType, value)};
2820
+ }());
2821
+
2781
2822
auto failure = [&](SILLocation location) {
2782
2823
// If we fail to match anything, we trap. This can happen with a switch
2783
2824
// over an @objc enum, which may contain any value of its underlying type,
@@ -2786,18 +2827,12 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2786
2827
SWIFT_DEFER { B.createUnreachable (location); };
2787
2828
2788
2829
// Special case: if it's a single @objc enum, we can print the raw value.
2789
- CanType ty = S->getSubjectExpr ()->getType ()->getCanonicalType ();
2790
- if (auto *singleEnumDecl = ty->getEnumOrBoundGenericEnum ()) {
2791
- if (singleEnumDecl->isObjC ()) {
2792
- emitDiagnoseOfUnexpectedEnumCaseValue (*this , location,
2793
- subject.getFinalManagedValue (),
2794
- subjectTy, singleEnumDecl);
2795
- return ;
2796
- }
2830
+ if (unexpectedEnumCaseInfo.isSingleObjCEnum ()) {
2831
+ emitDiagnoseOfUnexpectedEnumCaseValue (*this , location,
2832
+ unexpectedEnumCaseInfo);
2833
+ return ;
2797
2834
}
2798
- emitDiagnoseOfUnexpectedEnumCase (*this , location,
2799
- subject.getFinalManagedValue (),
2800
- subjectTy);
2835
+ emitDiagnoseOfUnexpectedEnumCase (*this , location, unexpectedEnumCaseInfo);
2801
2836
};
2802
2837
2803
2838
// Set up an initial clause matrix.
@@ -2823,6 +2858,10 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2823
2858
} else {
2824
2859
B.emitBlock (contBB);
2825
2860
}
2861
+
2862
+ // Now that we have emitted everything, see if our unexpected enum case info
2863
+ // metatypes were actually used. If not, delete them.
2864
+ unexpectedEnumCaseInfo.cleanupInstsIfUnused ();
2826
2865
}
2827
2866
2828
2867
void SILGenFunction::emitSwitchFallthrough (FallthroughStmt *S) {
0 commit comments