Skip to content

Commit 43eec8f

Browse files
committed
[AST/Sema] SE-0487: Expand @nonexhaustive attribute to support warn argument
The spelling `@nonexhaustive(warn)` replaces `@preEnumExtensibility` attriubte.
1 parent fe1ae75 commit 43eec8f

16 files changed

+133
-18
lines changed

include/swift/AST/Attr.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ enum : unsigned {
136136
InheritActorContextModifier::Last_InheritActorContextKind))
137137
};
138138

139+
enum : unsigned {
140+
NumNonexhaustiveModeBits = countBitsUsed(
141+
static_cast<unsigned>(NonexhaustiveMode::Last_NonexhaustiveMode))
142+
};
143+
139144
enum : unsigned { NumDeclAttrKindBits = countBitsUsed(NumDeclAttrKinds - 1) };
140145

141146
enum : unsigned { NumTypeAttrKindBits = countBitsUsed(NumTypeAttrKinds - 1) };
@@ -277,6 +282,10 @@ class DeclAttribute : public AttributeBase {
277282
SWIFT_INLINE_BITFIELD(LifetimeAttr, DeclAttribute, 1,
278283
isUnderscored : 1
279284
);
285+
286+
SWIFT_INLINE_BITFIELD(NonexhaustiveAttr, DeclAttribute, NumNonexhaustiveModeBits,
287+
mode : NumNonexhaustiveModeBits
288+
);
280289
} Bits;
281290
// clang-format on
282291

@@ -3500,6 +3509,36 @@ class ABIAttr : public DeclAttribute {
35003509
}
35013510
};
35023511

3512+
/// Defines a @nonexhaustive attribute.
3513+
class NonexhaustiveAttr : public DeclAttribute {
3514+
public:
3515+
NonexhaustiveAttr(SourceLoc atLoc, SourceRange range, NonexhaustiveMode mode,
3516+
bool implicit = false)
3517+
: DeclAttribute(DeclAttrKind::Nonexhaustive, atLoc, range, implicit) {
3518+
Bits.NonexhaustiveAttr.mode = unsigned(mode);
3519+
}
3520+
3521+
NonexhaustiveAttr(NonexhaustiveMode mode)
3522+
: NonexhaustiveAttr(SourceLoc(), SourceRange(), mode) {}
3523+
3524+
NonexhaustiveMode getMode() const {
3525+
return NonexhaustiveMode(Bits.NonexhaustiveAttr.mode);
3526+
}
3527+
3528+
static bool classof(const DeclAttribute *DA) {
3529+
return DA->getKind() == DeclAttrKind::Nonexhaustive;
3530+
}
3531+
3532+
NonexhaustiveAttr *clone(ASTContext &ctx) const {
3533+
return new (ctx) NonexhaustiveAttr(AtLoc, Range, getMode(), isImplicit());
3534+
}
3535+
3536+
bool isEquivalent(const NonexhaustiveAttr *other, Decl *attachedTo) const {
3537+
return getMode() == other->getMode();
3538+
}
3539+
};
3540+
3541+
35033542
/// The kind of unary operator, if any.
35043543
enum class UnaryOperatorKind : uint8_t { None, Prefix, Postfix };
35053544

include/swift/AST/AttrKind.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ enum class ENUM_EXTENSIBILITY_ATTR(closed)
135135
Last_InheritActorContextKind = Always
136136
};
137137

138+
enum class ENUM_EXTENSIBILITY_ATTR(closed) NonexhaustiveMode : uint8_t {
139+
Error SWIFT_NAME("error") = 0,
140+
Warning SWIFT_NAME("warning") = 1,
141+
Last_NonexhaustiveMode = Warning
142+
};
143+
138144
enum class ENUM_EXTENSIBILITY_ATTR(closed) DeclAttrKind : unsigned {
139145
#define DECL_ATTR(_, CLASS, ...) CLASS,
140146
#define LAST_DECL_ATTR(CLASS) Last_DeclAttr = CLASS,

include/swift/AST/DeclAttr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@ SIMPLE_DECL_ATTR(constInitialized, ConstInitialized,
877877
168)
878878
DECL_ATTR_FEATURE_REQUIREMENT(ConstInitialized, CompileTimeValues)
879879

880-
SIMPLE_DECL_ATTR(nonexhaustive, Nonexhaustive,
880+
DECL_ATTR(nonexhaustive, Nonexhaustive,
881881
OnEnum,
882882
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove | ForbiddenInABIAttr,
883883
169)

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ IDENTIFIER(value)
169169
IDENTIFIER_WITH_NAME(value_, "_value")
170170
IDENTIFIER(Void)
171171
IDENTIFIER(WinSDK)
172+
IDENTIFIER(warn)
172173
IDENTIFIER(with)
173174
IDENTIFIER(withArguments)
174175
IDENTIFIER(withKeywordArguments)

include/swift/Parse/IDEInspectionCallbacks.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ enum class ParameterizedDeclAttributeKind {
4040
FreestandingMacro,
4141
AttachedMacro,
4242
StorageRestrictions,
43-
InheritActorContext
43+
InheritActorContext,
44+
Nonexhaustive,
4445
};
4546

4647
/// A bit of a hack. When completing inside the '@storageRestrictions'

lib/AST/Attr.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,19 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
17321732
break;
17331733
}
17341734

1735+
case DeclAttrKind::Nonexhaustive: {
1736+
auto *attr = cast<NonexhaustiveAttr>(this);
1737+
Printer << "@nonexhaustive";
1738+
switch (attr->getMode()) {
1739+
case NonexhaustiveMode::Error:
1740+
break;
1741+
case NonexhaustiveMode::Warning:
1742+
Printer << "(warn)";
1743+
break;
1744+
}
1745+
break;
1746+
}
1747+
17351748
#define SIMPLE_DECL_ATTR(X, CLASS, ...) case DeclAttrKind::CLASS:
17361749
#include "swift/AST/DeclAttr.def"
17371750
llvm_unreachable("handled above");
@@ -1967,6 +1980,8 @@ StringRef DeclAttribute::getAttrName() const {
19671980
}
19681981
case DeclAttrKind::Lifetime:
19691982
return cast<LifetimeAttr>(this)->isUnderscored() ? "_lifetime" : "lifetime";
1983+
case DeclAttrKind::Nonexhaustive:
1984+
return "nonexhaustive";
19701985
}
19711986
llvm_unreachable("bad DeclAttrKind");
19721987
}

lib/IDE/CompletionLookup.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3278,6 +3278,11 @@ void CompletionLookup::getAttributeDeclParamCompletions(
32783278
getStoredPropertyCompletions(NT);
32793279
}
32803280
}
3281+
break;
3282+
}
3283+
case ParameterizedDeclAttributeKind::Nonexhaustive: {
3284+
addDeclAttrParamKeyword("warn", /*Parameters=*/{}, "", false);
3285+
break;
32813286
}
32823287
}
32833288
}

lib/Parse/ParseDecl.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4033,6 +4033,21 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
40334033
Attributes.add(Attr.get());
40344034
break;
40354035
}
4036+
4037+
case DeclAttrKind::Nonexhaustive: {
4038+
auto mode = parseSingleAttrOption<NonexhaustiveMode>(
4039+
*this, Loc, AttrRange, AttrName, DK,
4040+
{{Context.Id_warn, NonexhaustiveMode::Warning}},
4041+
NonexhaustiveMode::Error,
4042+
ParameterizedDeclAttributeKind::Nonexhaustive);
4043+
if (!mode)
4044+
return makeParserSuccess();
4045+
4046+
if (!DiscardAttribute)
4047+
Attributes.add(new (Context) NonexhaustiveAttr(AtLoc, AttrRange, *mode));
4048+
4049+
break;
4050+
}
40364051
}
40374052

40384053
if (DuplicateAttribute) {

lib/Sema/TypeCheckSwitchStmt.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,14 +1167,20 @@ namespace {
11671167
DE.diagnose(startLoc, diag::non_exhaustive_switch_unknown_only,
11681168
subjectType, shouldIncludeFutureVersionComment);
11691169

1170-
// Presence of `@preEnumExtensibility` pushed the warning farther
1171-
// into the future.
1172-
if (theEnum &&
1173-
theEnum->getAttrs().hasAttribute<PreEnumExtensibilityAttr>()) {
1174-
diag.warnUntilFutureSwiftVersion();
1175-
} else {
1176-
diag.warnUntilSwiftVersion(6);
1177-
}
1170+
auto shouldWarnUntilVersion = [&theEnum]() -> unsigned {
1171+
if (theEnum) {
1172+
// Presence of `@nonexhaustive(warn)` pushes the warning farther,
1173+
// into the future.
1174+
if (auto *nonexhaustive =
1175+
theEnum->getAttrs().getAttribute<NonexhaustiveAttr>()) {
1176+
if (nonexhaustive->getMode() == NonexhaustiveMode::Warning)
1177+
return swift::version::Version::getFutureMajorLanguageVersion();
1178+
}
1179+
}
1180+
return 6;
1181+
};
1182+
1183+
diag.warnUntilSwiftVersion(shouldWarnUntilVersion());
11781184

11791185
mainDiagType = std::nullopt;
11801186
}

lib/Serialization/Deserialization.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6676,6 +6676,14 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() {
66766676
break;
66776677
}
66786678

6679+
case decls_block::Nonexhaustive_DECL_ATTR: {
6680+
unsigned mode;
6681+
serialization::decls_block::NonexhaustiveDeclAttrLayout::readRecord(
6682+
scratch, mode);
6683+
Attr = new (ctx) NonexhaustiveAttr((NonexhaustiveMode)mode);
6684+
break;
6685+
}
6686+
66796687
#define SIMPLE_DECL_ATTR(NAME, CLASS, ...) \
66806688
case decls_block::CLASS##_DECL_ATTR: { \
66816689
bool isImplicit; \

0 commit comments

Comments
 (0)