Skip to content

[Typechecker] Diagnose use of magic literals as raw value for enum case #32364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2665,6 +2665,9 @@ ERROR(enum_non_integer_convertible_raw_type_no_value,none,
"expressible by integer or string literal", ())
ERROR(enum_raw_value_not_unique,none,
"raw value for enum case is not unique", ())
ERROR(enum_raw_value_magic_literal,none,
"use of '%0' literal as raw value for enum case is not supported",
(StringRef))
NOTE(enum_raw_value_used_here,none,
"raw value previously used here", ())
NOTE(enum_raw_value_incrementing_from_here,none,
Expand Down
18 changes: 15 additions & 3 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,21 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED,
if (ED->LazySemanticInfo.hasFixedRawValues())
continue;

// Using magic literals like #file as raw value is not supported right now.
// TODO: We could potentially support #file, #function, #line and #column.
auto &Diags = ED->getASTContext().Diags;
SourceLoc diagLoc = uncheckedRawValueOf(elt)->isImplicit()
? elt->getLoc()
: uncheckedRawValueOf(elt)->getLoc();
if (auto magicLiteralExpr =
dyn_cast<MagicIdentifierLiteralExpr>(prevValue)) {
auto kindString =
magicLiteralExpr->getKindString(magicLiteralExpr->getKind());
Diags.diagnose(diagLoc, diag::enum_raw_value_magic_literal, kindString);
elt->setInvalid();
continue;
}

// Check that the raw value is unique.
RawValueKey key{prevValue};
RawValueSource source{elt, lastExplicitValueElt};
Expand All @@ -1091,9 +1106,6 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED,
continue;

// Diagnose the duplicate value.
auto &Diags = ED->getASTContext().Diags;
SourceLoc diagLoc = uncheckedRawValueOf(elt)->isImplicit()
? elt->getLoc() : uncheckedRawValueOf(elt)->getLoc();
Diags.diagnose(diagLoc, diag::enum_raw_value_not_unique);
assert(lastExplicitValueElt &&
"should not be able to have non-unique raw values when "
Expand Down
19 changes: 19 additions & 0 deletions test/Sema/enum_raw_representable_object_literals.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %target-typecheck-verify-swift
// REQUIRES: OS=ios

import UIKit

struct FooLiteral: _ExpressibleByColorLiteral, _ExpressibleByImageLiteral, _ExpressibleByFileReferenceLiteral {
init(_colorLiteralRed: Float, green: Float, blue: Float, alpha: Float) {}
init(imageLiteralResourceName: String) {}
init(fileReferenceLiteralResourceName: String) {}
}

enum Foo: FooLiteral { // expected-error {{raw type 'FooLiteral' is not expressible by a string, integer, or floating-point literal}}
typealias RawValue = Never
var rawValue: Never { fatalError() }
init(rawValue: Never) { fatalError() }
case bar1 = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1)
case bar2 = #imageLiteral(resourceName: "hello.png")
case bar3 = #fileLiteral(resourceName: "what.txt")
}
19 changes: 19 additions & 0 deletions validation-test/compiler_crashers_2_fixed/sr12998.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %target-swift-frontend -typecheck %s -verify

enum FooString: String { // expected-error {{'FooString' declares raw type 'String', but does not conform to RawRepresentable and conformance could not be synthesized}}
case bar1 = #file // expected-error {{use of '#file' literal as raw value for enum case is not supported}}
case bar2 = #function // expected-error {{use of '#function' literal as raw value for enum case is not supported}}
case bar3 = #filePath // expected-error {{use of '#filePath' literal as raw value for enum case is not supported}}
case bar4 = #line // expected-error {{cannot convert value of type 'Int' to raw type 'String'}}
case bar5 = #column // expected-error {{cannot convert value of type 'Int' to raw type 'String'}}
case bar6 = #dsohandle // expected-error {{cannot convert value of type 'UnsafeRawPointer' to raw type 'String'}}
}

enum FooInt: Int { // expected-error {{'FooInt' declares raw type 'Int', but does not conform to RawRepresentable and conformance could not be synthesized}}
case bar1 = #file // expected-error {{cannot convert value of type 'String' to raw type 'Int'}}
case bar2 = #function // expected-error {{cannot convert value of type 'String' to raw type 'Int'}}
case bar3 = #filePath // expected-error {{cannot convert value of type 'String' to raw type 'Int'}}
case bar4 = #line // expected-error {{use of '#line' literal as raw value for enum case is not supported}}
case bar5 = #column // expected-error {{use of '#column' literal as raw value for enum case is not supported}}
case bar6 = #dsohandle // expected-error {{cannot convert value of type 'UnsafeRawPointer' to raw type 'Int'}}
}