Skip to content

Commit 8573d70

Browse files
authored
[Typechecker] Diagnose use of magic literals as raw value for enum case (#32364)
1 parent f155ce8 commit 8573d70

File tree

4 files changed

+56
-3
lines changed

4 files changed

+56
-3
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2668,6 +2668,9 @@ ERROR(enum_non_integer_convertible_raw_type_no_value,none,
26682668
"expressible by integer or string literal", ())
26692669
ERROR(enum_raw_value_not_unique,none,
26702670
"raw value for enum case is not unique", ())
2671+
ERROR(enum_raw_value_magic_literal,none,
2672+
"use of '%0' literal as raw value for enum case is not supported",
2673+
(StringRef))
26712674
NOTE(enum_raw_value_used_here,none,
26722675
"raw value previously used here", ())
26732676
NOTE(enum_raw_value_incrementing_from_here,none,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,21 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED,
10821082
if (ED->LazySemanticInfo.hasFixedRawValues())
10831083
continue;
10841084

1085+
// Using magic literals like #file as raw value is not supported right now.
1086+
// TODO: We could potentially support #file, #function, #line and #column.
1087+
auto &Diags = ED->getASTContext().Diags;
1088+
SourceLoc diagLoc = uncheckedRawValueOf(elt)->isImplicit()
1089+
? elt->getLoc()
1090+
: uncheckedRawValueOf(elt)->getLoc();
1091+
if (auto magicLiteralExpr =
1092+
dyn_cast<MagicIdentifierLiteralExpr>(prevValue)) {
1093+
auto kindString =
1094+
magicLiteralExpr->getKindString(magicLiteralExpr->getKind());
1095+
Diags.diagnose(diagLoc, diag::enum_raw_value_magic_literal, kindString);
1096+
elt->setInvalid();
1097+
continue;
1098+
}
1099+
10851100
// Check that the raw value is unique.
10861101
RawValueKey key{prevValue};
10871102
RawValueSource source{elt, lastExplicitValueElt};
@@ -1091,9 +1106,6 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED,
10911106
continue;
10921107

10931108
// Diagnose the duplicate value.
1094-
auto &Diags = ED->getASTContext().Diags;
1095-
SourceLoc diagLoc = uncheckedRawValueOf(elt)->isImplicit()
1096-
? elt->getLoc() : uncheckedRawValueOf(elt)->getLoc();
10971109
Diags.diagnose(diagLoc, diag::enum_raw_value_not_unique);
10981110
assert(lastExplicitValueElt &&
10991111
"should not be able to have non-unique raw values when "
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// REQUIRES: OS=ios
3+
4+
import UIKit
5+
6+
struct FooLiteral: _ExpressibleByColorLiteral, _ExpressibleByImageLiteral, _ExpressibleByFileReferenceLiteral {
7+
init(_colorLiteralRed: Float, green: Float, blue: Float, alpha: Float) {}
8+
init(imageLiteralResourceName: String) {}
9+
init(fileReferenceLiteralResourceName: String) {}
10+
}
11+
12+
enum Foo: FooLiteral { // expected-error {{raw type 'FooLiteral' is not expressible by a string, integer, or floating-point literal}}
13+
typealias RawValue = Never
14+
var rawValue: Never { fatalError() }
15+
init(rawValue: Never) { fatalError() }
16+
case bar1 = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1)
17+
case bar2 = #imageLiteral(resourceName: "hello.png")
18+
case bar3 = #fileLiteral(resourceName: "what.txt")
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %target-swift-frontend -typecheck %s -verify
2+
3+
enum FooString: String { // expected-error {{'FooString' declares raw type 'String', but does not conform to RawRepresentable and conformance could not be synthesized}}
4+
case bar1 = #file // expected-error {{use of '#file' literal as raw value for enum case is not supported}}
5+
case bar2 = #function // expected-error {{use of '#function' literal as raw value for enum case is not supported}}
6+
case bar3 = #filePath // expected-error {{use of '#filePath' literal as raw value for enum case is not supported}}
7+
case bar4 = #line // expected-error {{cannot convert value of type 'Int' to raw type 'String'}}
8+
case bar5 = #column // expected-error {{cannot convert value of type 'Int' to raw type 'String'}}
9+
case bar6 = #dsohandle // expected-error {{cannot convert value of type 'UnsafeRawPointer' to raw type 'String'}}
10+
}
11+
12+
enum FooInt: Int { // expected-error {{'FooInt' declares raw type 'Int', but does not conform to RawRepresentable and conformance could not be synthesized}}
13+
case bar1 = #file // expected-error {{cannot convert value of type 'String' to raw type 'Int'}}
14+
case bar2 = #function // expected-error {{cannot convert value of type 'String' to raw type 'Int'}}
15+
case bar3 = #filePath // expected-error {{cannot convert value of type 'String' to raw type 'Int'}}
16+
case bar4 = #line // expected-error {{use of '#line' literal as raw value for enum case is not supported}}
17+
case bar5 = #column // expected-error {{use of '#column' literal as raw value for enum case is not supported}}
18+
case bar6 = #dsohandle // expected-error {{cannot convert value of type 'UnsafeRawPointer' to raw type 'Int'}}
19+
}

0 commit comments

Comments
 (0)