|
22 | 22 | #include "swift/AST/DiagnosticsSIL.h"
|
23 | 23 | #include "swift/AST/Pattern.h"
|
24 | 24 | #include "swift/AST/SILOptions.h"
|
| 25 | +#include "swift/AST/SubstitutionMap.h" |
25 | 26 | #include "swift/AST/Types.h"
|
| 27 | +#include "swift/Basic/Defer.h" |
26 | 28 | #include "swift/Basic/ProfileCounter.h"
|
27 | 29 | #include "swift/Basic/STLExtras.h"
|
28 | 30 | #include "swift/SIL/DynamicCasts.h"
|
@@ -2555,19 +2557,78 @@ void SILGenFunction::usingImplicitVariablesForPattern(Pattern *pattern, CaseStmt
|
2555 | 2557 | variableSwapper();
|
2556 | 2558 | }
|
2557 | 2559 |
|
| 2560 | +static void emitDiagnoseOfUnexpectedEnumCaseValue(SILGenFunction &SGF, |
| 2561 | + SILLocation loc, |
| 2562 | + ManagedValue value, |
| 2563 | + const EnumDecl *enumDecl) { |
| 2564 | + ASTContext &ctx = SGF.getASTContext(); |
| 2565 | + auto diagnoseFailure = ctx.getDiagnoseUnexpectedEnumCaseValue(nullptr); |
| 2566 | + if (!diagnoseFailure) { |
| 2567 | + SGF.B.createBuiltinTrap(loc); |
| 2568 | + return; |
| 2569 | + } |
| 2570 | + |
| 2571 | + assert(enumDecl->isObjC()); |
| 2572 | + assert(enumDecl->hasRawType()); |
| 2573 | + assert(value.getType().isTrivial(SGF.getModule())); |
| 2574 | + |
| 2575 | + // Get the enum type as an Any.Type value. |
| 2576 | + CanType switchedValueSwiftType = value.getType().getSwiftRValueType(); |
| 2577 | + SILType metatypeType = SGF.getLoweredType( |
| 2578 | + CanMetatypeType::get(switchedValueSwiftType, |
| 2579 | + MetatypeRepresentation::Thick)); |
| 2580 | + SILValue metatype = SGF.B.createMetatype(loc, metatypeType); |
| 2581 | + |
| 2582 | + // Bitcast the enum value to its raw type. (This is only safe for @objc |
| 2583 | + // enums.) |
| 2584 | + SILType loweredRawType = SGF.getLoweredType(enumDecl->getRawType()); |
| 2585 | + assert(loweredRawType.isTrivial(SGF.getModule())); |
| 2586 | + assert(loweredRawType.isObject()); |
| 2587 | + auto rawValue = SGF.B.createUncheckedTrivialBitCast(loc, value, |
| 2588 | + loweredRawType); |
| 2589 | + auto materializedRawValue = rawValue.materialize(SGF, loc); |
| 2590 | + |
| 2591 | + Substitution subs[] = { |
| 2592 | + {switchedValueSwiftType, /*Conformances*/None}, |
| 2593 | + {enumDecl->getRawType(), /*Conformances*/None}, |
| 2594 | + }; |
| 2595 | + |
| 2596 | + SGF.emitApplyOfLibraryIntrinsic(loc, diagnoseFailure, subs, |
| 2597 | + {ManagedValue::forUnmanaged(metatype), |
| 2598 | + materializedRawValue}, |
| 2599 | + SGFContext()); |
| 2600 | +} |
| 2601 | + |
| 2602 | +static void emitDiagnoseOfUnexpectedEnumCase(SILGenFunction &SGF, |
| 2603 | + SILLocation loc, |
| 2604 | + ManagedValue value) { |
| 2605 | + ASTContext &ctx = SGF.getASTContext(); |
| 2606 | + auto diagnoseFailure = ctx.getDiagnoseUnexpectedEnumCase(nullptr); |
| 2607 | + if (!diagnoseFailure) { |
| 2608 | + SGF.B.createBuiltinTrap(loc); |
| 2609 | + return; |
| 2610 | + } |
| 2611 | + |
| 2612 | + // Get the switched-upon value's type. |
| 2613 | + CanType switchedValueSwiftType = value.getType().getSwiftRValueType(); |
| 2614 | + SILType metatypeType = SGF.getLoweredType( |
| 2615 | + CanMetatypeType::get(switchedValueSwiftType, |
| 2616 | + MetatypeRepresentation::Thick)); |
| 2617 | + ManagedValue metatype = SGF.B.createValueMetatype(loc, metatypeType, value); |
| 2618 | + |
| 2619 | + Substitution sub{switchedValueSwiftType, /*Conformances*/None}; |
| 2620 | + auto genericArgsMap = |
| 2621 | + diagnoseFailure->getGenericSignature()->getSubstitutionMap(sub); |
| 2622 | + |
| 2623 | + SGF.emitApplyOfLibraryIntrinsic(loc, diagnoseFailure, sub, |
| 2624 | + metatype, |
| 2625 | + SGFContext()); |
| 2626 | +} |
| 2627 | + |
2558 | 2628 | void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
|
2559 | 2629 | DEBUG(llvm::dbgs() << "emitting switch stmt\n";
|
2560 | 2630 | S->print(llvm::dbgs());
|
2561 | 2631 | llvm::dbgs() << '\n');
|
2562 |
| - auto failure = [this](SILLocation location) { |
2563 |
| - // If we fail to match anything, we trap. This can happen with a switch |
2564 |
| - // over an @objc enum, which may contain any value of its underlying type. |
2565 |
| - // FIXME: Even if we can't say what the invalid value was, we should at |
2566 |
| - // least mention that this was because of a non-exhaustive enum. |
2567 |
| - B.createBuiltinTrap(location); |
2568 |
| - B.createUnreachable(location); |
2569 |
| - }; |
2570 |
| - |
2571 | 2632 | // If the subject expression is uninhabited, we're already dead.
|
2572 | 2633 | // Emit an unreachable in place of the switch statement.
|
2573 | 2634 | if (S->getSubjectExpr()->getType()->isStructurallyUninhabited()) {
|
@@ -2651,10 +2712,7 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
|
2651 | 2712 | PatternMatchEmission emission(*this, S, completionHandler);
|
2652 | 2713 |
|
2653 | 2714 | // Add a row for each label of each case.
|
2654 |
| - // |
2655 |
| - // We use std::vector because it supports emplace_back; moving a ClauseRow is |
2656 |
| - // expensive. |
2657 |
| - std::vector<ClauseRow> clauseRows; |
| 2715 | + SmallVector<ClauseRow, 8> clauseRows; |
2658 | 2716 | clauseRows.reserve(S->getRawCases().size());
|
2659 | 2717 | bool hasFallthrough = false;
|
2660 | 2718 | for (auto caseBlock : S->getCases()) {
|
@@ -2695,6 +2753,27 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
|
2695 | 2753 | ManagedValue subjectMV = emitRValueAsSingleValue(S->getSubjectExpr());
|
2696 | 2754 | auto subject = ConsumableManagedValue::forOwned(subjectMV);
|
2697 | 2755 |
|
| 2756 | + auto failure = [&](SILLocation location) { |
| 2757 | + // If we fail to match anything, we trap. This can happen with a switch |
| 2758 | + // over an @objc enum, which may contain any value of its underlying type, |
| 2759 | + // or a switch over a non-frozen Swift enum when the user hasn't written a |
| 2760 | + // catch-all case. |
| 2761 | + SWIFT_DEFER { B.createUnreachable(location); }; |
| 2762 | + |
| 2763 | + // Special case: if it's a single @objc enum, we can print the raw value. |
| 2764 | + CanType ty = S->getSubjectExpr()->getType()->getCanonicalType(); |
| 2765 | + if (auto *singleEnumDecl = ty->getEnumOrBoundGenericEnum()) { |
| 2766 | + if (singleEnumDecl->isObjC()) { |
| 2767 | + emitDiagnoseOfUnexpectedEnumCaseValue(*this, location, |
| 2768 | + subject.getFinalManagedValue(), |
| 2769 | + singleEnumDecl); |
| 2770 | + return; |
| 2771 | + } |
| 2772 | + } |
| 2773 | + emitDiagnoseOfUnexpectedEnumCase(*this, location, |
| 2774 | + subject.getFinalManagedValue()); |
| 2775 | + }; |
| 2776 | + |
2698 | 2777 | // Set up an initial clause matrix.
|
2699 | 2778 | ClauseMatrix clauses(clauseRows);
|
2700 | 2779 |
|
|
0 commit comments