Быстрая оценка @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) изменить вывод программы? Это должно быть полностью обработано в контроллере типов, и это означает, что во время компиляции, нет? Ошибка компилятора?
Самый быстрый способ воспроизвести это должен быть:
- скопировать весь мой код в буфер обмена
cd /tmp
pbpaste > main.swift
xcrun -sdk macosx swiftc main.swift
./main
фактический выход:
x = (Enum Value)
fatal error: undefined: file main.swift, line 27
Illegal instruction: 4
ожидаемый результат:
x = (Enum Value)
y = (Enum Value)