Быстрая оценка @autoclosure под влиянием аннотаций типов? (ошибка компилятора?)

Сегодня я снова играл со Свифтом и нуждался в undefined() функция. В основном функция, которая может быть любого типа, которую вы хотите, но сбои, когда она фактически запускается / оценивается. Это полезно, если вы еще не успели реализовать определенное выражение, но хотите посмотреть, проверяет ли тип программы.

Я также реализовал Result<T> и (сомнительная) функция chain который возвращает влево Result<> если не удачно, иначе право Result<>, Таким образом, подпись chain<L,R>(l : Result<L>, r : @autoclosure () -> Result<R>) -> Result<R>, Я определил право Result<> как @autoclosure потому что нет необходимости оценивать это, если левый отказ.

Меня не интересует полезность (или улучшения) для всего этого, мне просто интересно, почему моя программа падает в строке, помеченной [L3],

Обратите внимание, что

  • как и ожидалось [L1] работает отлично (|| лениво оценивается)
  • [L2] работает отлично (chain тоже ленив в своем правильном аргументе)

Но странно

  • [L3] вылетает программа оценки undefined()

Насколько я понимаю, L2 и L3 должны быть эквивалентны во время выполнения: L3 просто сообщает контролеру типов то, что он уже знает... Кстати, тот же эффект происходит, если вы меняете тип undefined в () -> Result<T> (вместо () -> T), то все работает даже без as Result<String>,

Это весь мой код:

import Foundation

enum Result<T> {
    case Success(@autoclosure () -> T);
    case Failure(@autoclosure () -> NSError)
}

func undefined<T>(file:StaticString=__FILE__, line:UWord=__LINE__) -> T {
    fatalError("undefined", file:file, line:line)
}

func chain<L,R>(l : Result<L>, r : @autoclosure () -> Result<R>) -> Result<R> {
    switch(l) {
    case .Failure(let f):
        return .Failure(f())
    case .Success(let _):
        return r()
    }
}

func testEvaluation() {
    let error = NSError(domain: NSPOSIXErrorDomain, code: Int(ENOENT), userInfo: nil)
    let failure : Result<String> = .Failure(error)
    assert(true || undefined() as Bool) // [L1]: works
    let x : Result<String> = chain(failure, undefined() as Result<String>) // [L2]: works
    print("x = \(x)\n")
    let y : Result<String> = chain(failure, undefined()) // [L3]: CRASHES THE PROGRAM EVALUATING undefined()
    print("y = \(y)\n")
}

testEvaluation()

Верьте или нет, результат программы:

x = (Enum Value)
fatal error: undefined: file main.swift, line 27
Illegal instruction: 4

Это не может быть правдой! Почему бы as Result<String> (в чем единственная разница между L2 и L3) изменить вывод программы? Это должно быть полностью обработано в контроллере типов, и это означает, что во время компиляции, нет? Ошибка компилятора?

Самый быстрый способ воспроизвести это должен быть:

  1. скопировать весь мой код в буфер обмена
  2. cd /tmp
  3. pbpaste > main.swift
  4. xcrun -sdk macosx swiftc main.swift
  5. ./main

фактический выход:

x = (Enum Value)
fatal error: undefined: file main.swift, line 27
Illegal instruction: 4

ожидаемый результат:

x = (Enum Value)
y = (Enum Value)

1 ответ

Подтверждено как ошибка разработчиком Swift Джо Гроффом через Twitter.

Другие вопросы по тегам