Считается ли #file буквальной строкой в ​​Swift? - PullRequest
8 голосов
/ 08 мая 2020

Ошибка > Swift > Enum > String Протокол

Я пытался создать перечисление, в котором все его элементы были бы именами файлов, и наткнулся на кое-что интересное. Примерно так:

enum FileNames: String {
     case main = #file
}

Это привело к внутренней ошибке. (Ошибка сегментации: 11)

Мне удалось выяснить, как получить фактическое сообщение об ошибке:

enum Foo: String {
    case one = "\(1)"
}

Error: Raw value for enum case must be a literal

Вопросы по теме:
• Считается ли #file строковым литералом?
• Почему #file нарушает перечисление? Следует ли сообщать об этом на bugs.swift.org?
• Я заметил, что замена String на Int и #file на #line вызывает ту же проблему. Это намек?

Цветные литералы не работают

Я думал, что работают, но ошибся. Это также вызывает ту же внутреннюю ошибку.

import UIKit

enum ColorEnum: UIColor {
    case foo = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0)
}

Язык программирования Swift (Swift 5.2)

Согласно Apple, #file считается буквальным:

#file is described as a literal according to Apple


What about nil Literals?

These also crash the compiler.

enum Foo: String? {
    case breaks = nil
}

23 Characters of Mass Destruction enum I:Int?{case a=nil}


Bug Fixed

The crash has now been fixed, it has been merged officially into Swift here: Объединено на GitHub Вот ошибка report: SR-12998

Поддержка добавления!
Здесь поддерживается использование литералов magi c в качестве необработанных значений для случаев перечисления: СР-13022

Ответы [ 2 ]

3 голосов
/ 13 июня 2020

Да, #file и #line являются буквальными выражениями , но ваша программа все еще плохо сформирована.

В справочнике по языку Swift говорится :

Литеральное выражение состоит из обычного литерала (например, строки или числа), литерала массива или словаря, литерала детской площадки или одного из следующих специальных литералов:

#file - String - Имя файла, в котором он появляется.

#line - Int - Номер строки, в которой он появляется.

[. ..]

Отметим также грамматику:

literal-expression → literal
literal-expression → array-literal | dictionary-literal | playground-literal
literal-expression → #file | #line | #column | #function | #dsohandle

Теперь давайте рассмотрим грамматику определяемого вами перечисления . Я включаю сюда только самые важные части, вы можете проверить полный вывод самостоятельно:

enum-declaration → attributes opt access-level-modifier opt raw-value-style-enum
[...]
raw-value-style-enum → enum enum-name generic-parameter-clause opt type-inheritance-clause generic-where-clause opt { raw-value-style-enum-members }
[...]
raw-value-assignment → = raw-value-literal
raw-value-literal → numeric-literal | static-string-literal | boolean-literal

Примечательно, что только numeri c -literal , * Допускаются 1037 * stati c -string-literal , boolean-literal . Если мы посмотрим на их определения, станет ясно, что эти # литералы, таким образом, не соответствуют правилу raw-value-literal:

numeric-literal → -opt integer-literal | -opt floating-point-literal
boolean-literal → true | false
static-string-literal → string-literal-opening-delimiter quoted-text opt string-literal-closing-delimiter
static-string-literal → multiline-string-literal-opening-delimiter multiline-quoted-text opt multiline-string-literal-closing-delimiter

Все соответствующие правила для полного определения stati c -string-literal - длинные, но все же тривиально увидеть, что stati c -string-literal не может быть выведен из #file и не может включать интерполяцию. (Вот что делает его c.)

Итак, компилятор Swift действительно прав, отказываясь от вашей программы. Тем не менее, современный компилятор не должен просто взламывать sh незаконную программу, поэтому, возможно, стоит сообщить об этой проблеме.

2 голосов
/ 13 июня 2020

Это определенно ошибка, поэтому стоит отправить отзыв в Apple (хотя они задокументировали, что эти #file, #function, et c. Являются специальными литералами )

В любом случае, возможно, в некоторых случаях может оказаться полезным следующий обходной путь:

enum FileNames {
    static let main = FileNames.file(#file)
    case file(String)
}
...