2015-12-08 2 views
9

Я получаю странный Bus Error при работе, что кажется совершенно безопасным быстрым кодом. Я пытался уменьшить его до минимального тестового случая следующим образом:Почему повторное закрытие замыкания вызывает ошибку шины в swift?

Apple Swift version 2.2-dev (LLVM 3ebdbb2c7e, Clang f66c5bb67b, Swift 0ddf238ad7) 
Target: x86_64-apple-macosx10.9 

Этот код:

public enum MyError: ErrorType { 
    case SomeError(code: Int) 
} 

public typealias MyType =() throws -> Bool 

public class Foo { 
    var a:MyType = {() throws -> Bool in 
    print("A") 
    return true 
    } 
    var b:MyType = {() throws -> Bool in 
    print("B") 
    return true 
    } 
    var c:MyType = {() throws -> Bool in 
    print("C") 
    throw MyError.SomeError(0) 
    } 
} 

public func handle<T>(test:T) { 
    let mirror = Mirror(reflecting: test) 
    print(mirror.subjectType) 
    for child in mirror.children { 
    if let callable = child.value as? MyType { 
     do { 
     try callable() 
     } 
     catch MyError.SomeError(let id) { 
     print(id) 
     } 
     catch { 
     print("unknown error") 
     } 
    } 
    } 
} 

let foo = Foo() 
handle(foo) 

Формирует этот вывод:

Foo 
A 
B 
C 
Bus error: 10 

Запуск в отладчике отлично работает, поэтому я предполагаю, что это связано с проблемой синхронизации во время выполнения.

Я делаю что-то незаконное или небезопасное в этом коде?

Являются ли исключения незаконными в закрытии?

В чем причина этой ошибки?

Edit:

Я создал ошибку на быстром выпуске трекера для этого сейчас здесь: https://bugs.swift.org/browse/SR-324

ответ

4

Что вызывает эту ошибку?

Ошибка не произойдет, пока вы не дойдете до последнего закрытия:

var c:MyType = {() throws -> Bool in 
    print("C") 
    throw MyError.SomeError(0) 
} 

Очевидно, что вы бросаете исключение здесь, и я подозреваю, что проблема не столько с Перебор children и многое другое, чтобы сделать исключение, пока вы делаете это, итерации. Я пыталась дозвониться c без итерация:

public func trythis() { 
    let foo = Foo() 
    do { 
     try (foo.c)() 
    } 
    catch MyError.SomeError(let id) { 
     print(id) 
    } 
    catch { print("unknown") } 
} 

trythis() 

и обнаружили, что он работал отлично. Я также попытался удалить throw из c:

var c:MyType = {() throws -> Bool in 
    print("C") 
// throw MyError.SomeError(code: 0) 
    return true 
} 

и обнаружили, что код работает отлично в этом случае. Таким образом, это комбинация метания, итерация по списку, что является проблемой, и это заставляет меня подозревать, что это просто ошибка компилятора или, может быть, проблема с классом Mirror.

Я думаю, вы должны подать отчет об ошибке с Apple для этого.

2

Я согласен с Калебом в том, что это должно быть ошибкой.

Но для того, чтобы быть ясным, это не комбинация метания во время итерации. Состоит из , отражающих и метание.

Это модифицированная версия вашей handle функции:

public func handle<T>(test:T) { 
    let mirror = Mirror(reflecting: test) 
    print(mirror.subjectType) 

    // Extract only the last function, no iteration... 
    if let callable = mirror.children[AnyForwardIndex(2)].value as? MyType { 
    do { 
     try callable() 
    } 
    catch MyError.SomeError(let id) { 
     print(id) 
    } 
    catch { 
     print("unknown error") 
    } 

    } 
} 

Эта функция вызовет ту же ошибку, как ваша функцию. Вы просто не можете вызвать функцию, которая выбрасывает, если найдена с использованием отражения.

Ошибка, я бы сказал.

Смежные вопросы