Skip to content

Commit 93f9a17

Browse files
authored
Merge pull request swiftlang#75872 from swiftlang/elsh/pkg-switch-enum
2 parents 4fc85d7 + fadf6ec commit 93f9a17

File tree

5 files changed

+418
-177
lines changed

5 files changed

+418
-177
lines changed

include/swift/AST/Decl.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4741,6 +4741,15 @@ class EnumDecl final : public NominalTypeDecl {
47414741
/// \sa isEffectivelyExhaustive
47424742
bool isFormallyExhaustive(const DeclContext *useDC) const;
47434743

4744+
/// True if \s isFormallyExhaustive is true or the use site's module belongs
4745+
/// to the same package as this enum's defining module. If in same package
4746+
/// even though `isFormallyExhaustive` is false, we can skip requiring
4747+
/// `@unknown default` at the use site switch stmts because package modules
4748+
/// are expected to be built together whether they are resiliently built or
4749+
/// not. Used for diagnostics during typechecks only; if
4750+
/// `isFormallyExhaustive` is false, it should be reflected in SILgen.
4751+
bool treatAsExhaustiveForDiags(const DeclContext *useDC) const;
4752+
47444753
/// True if the enum can be exhaustively switched within a function defined
47454754
/// within \p M, with \p expansion specifying whether the function is
47464755
/// inlinable.

lib/AST/Decl.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6583,6 +6583,11 @@ bool EnumDecl::hasOnlyCasesWithoutAssociatedValues() const {
65836583
return !hasAssociatedValues;
65846584
}
65856585

6586+
bool EnumDecl::treatAsExhaustiveForDiags(const DeclContext *useDC) const {
6587+
return isFormallyExhaustive(useDC) ||
6588+
(useDC && getModuleContext()->inSamePackage(useDC->getParentModule()));
6589+
}
6590+
65866591
bool EnumDecl::isFormallyExhaustive(const DeclContext *useDC) const {
65876592
// Enums explicitly marked frozen are exhaustive.
65886593
if (getAttrs().hasAttribute<FrozenAttr>())
@@ -6600,14 +6605,10 @@ bool EnumDecl::isFormallyExhaustive(const DeclContext *useDC) const {
66006605
return true;
66016606

66026607
// Non-public, non-versioned enums are always exhaustive.
6603-
AccessScope accessScope = getFormalAccessScope(/*useDC*/nullptr,
6604-
/*respectVersioned*/true);
6605-
// Both public and package enums should behave the same unless
6606-
// package enum is optimized with bypassing resilience checks.
6608+
AccessScope accessScope = getFormalAccessScope(/*useDC*/ nullptr,
6609+
/*respectVersioned*/ true);
66076610
if (!accessScope.isPublicOrPackage())
66086611
return true;
6609-
if (useDC && bypassResilienceInPackage(useDC->getParentModule()))
6610-
return true;
66116612

66126613
// All other checks are use-site specific; with no further information, the
66136614
// enum must be treated non-exhaustively.
@@ -6639,11 +6640,13 @@ bool EnumDecl::isEffectivelyExhaustive(ModuleDecl *M,
66396640
if (isObjC())
66406641
return false;
66416642

6642-
// Otherwise, the only non-exhaustive cases are those that don't have a fixed
6643-
// layout.
6644-
assert(isFormallyExhaustive(M) == !isResilient(M,ResilienceExpansion::Maximal)
6645-
&& "ignoring the effects of @inlinable, @testable, and @objc, "
6646-
"these should match up");
6643+
// Otherwise, the only non-exhaustive enums are those that don't have
6644+
// a fixed layout; however, they are treated as exhaustive if package
6645+
// optimization is enabled.
6646+
assert((isFormallyExhaustive(M) || bypassResilienceInPackage(M)) ==
6647+
!isResilient(M, ResilienceExpansion::Maximal) &&
6648+
"ignoring the effects of @inlinable, @testable, and @objc, "
6649+
"these should match up");
66476650
return !isResilient(M, expansion);
66486651
}
66496652

lib/Sema/TypeCheckSwitchStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -861,7 +861,7 @@ namespace {
861861
constElemSpaces);
862862
});
863863

864-
if (!E->isFormallyExhaustive(DC)) {
864+
if (!E->treatAsExhaustiveForDiags(DC)) {
865865
arr.push_back(Space::forUnknown(/*allowedButNotRequired*/false));
866866
} else if (!E->getAttrs().hasAttribute<FrozenAttr>()) {
867867
arr.push_back(Space::forUnknown(/*allowedButNotRequired*/true));

0 commit comments

Comments
 (0)