I was trying to implement a property wrapper and I was hit with the following error:
1. While emitting IR SIL function "@$s17Firebase_Practice11ContentViewVACycfC".
for 'init()' (at /Users/noahwilder/Desktop/Dating App/Practice/Firebase Practice/Firebase Practice/ContentView.swift:14:8)
0 swift 0x000000010f144a63 PrintStackTraceSignalHandler(void*) + 51
1 swift 0x000000010f144236 SignalHandler(int) + 358
2 libsystem_platform.dylib 0x00007fff7140a42d _sigtramp + 29
3 libsystem_platform.dylib 0x00007fd087198880 _sigtramp + 366535792
4 libsystem_c.dylib 0x00007fff712dfa1c abort + 120
5 libsystem_malloc.dylib 0x00007fff713d5647 has_default_zone0 + 0
6 libsystem_malloc.dylib 0x00007fff713d840e malloc_report + 151
7 libsystem_malloc.dylib 0x00007fff713c9275 realloc + 312
8 swift 0x000000010ae5dacd swift::irgen::SingleScalarTypeInfo<(anonymous namespace)::ClassTypeInfo, swift::irgen::ReferenceTypeInfo>::getSchema(swift::irgen::ExplosionSchema&) const + 157
9 swift 0x000000010afd31fe swift::SILInstructionVisitor<(anonymous namespace)::IRGenSILFunction, void>::visit(swift::SILInstruction*) + 35646
10 swift 0x000000010afc7b4a swift::irgen::IRGenModule::emitSILFunction(swift::SILFunction*) + 9834
11 swift 0x000000010ae72c50 swift::irgen::IRGenerator::emitGlobalTopLevel() + 1712
12 swift 0x000000010afa48c5 performIRGeneration(swift::IRGenOptions&, swift::ModuleDecl*, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule> >, llvm::StringRef, swift::PrimarySpecificPaths const&, llvm::LLVMContext&, swift::SourceFile*, llvm::GlobalVariable**) + 1189
13 swift 0x000000010ad8fa01 performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) + 36673
14 swift 0x000000010ad832b4 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 6820
15 swift 0x000000010ad107b3 main + 1219
16 libdyld.dylib 0x00007fff712117fd start + 1
17 libdyld.dylib 0x00000000000000a6 start + 2396973226
error: Abort trap: 6 (in target 'Firebase Practice' from project 'Firebase Practice')
After playing around with it for a bit, I am pretty sure that this is being caused by the convenience initializer in DatabaseBackedArray
. More specifically I think the compiler is having trouble with the variadic parameter.
Here is the code that produced the error:
import SwiftUI
import Firebase
import CodableFirebase
import Combine
struct SecondaryView: View {
@DatabaseBackedArray(\.school, events: .all, actions: .on(.constructive) { $0.sort { $0.name < $1.name } })
var schools: [School] = []
var body: some View {
Text("School: ").bold() +
Text(schools.isEmpty ? "Loading..." : schools.first!.name)
}
}
@propertyWrapper
final class DatabaseBackedArray<Element>: ObservableObject where Element: Codable & Identifiable {
typealias ObserverHandle = UInt
typealias Action = RealtimeDatabase.Action
typealias Event = RealtimeDatabase.Event
private(set) var reference: DatabaseReference
private var currentValue: [Element]
private var childAddedObserverHandle: ObserverHandle?
private var childChangedObserverHandle: ObserverHandle?
private var childRemovedObserverHandle: ObserverHandle?
private var childAddedActions: [Action<[Element]>] = []
private var childChangedActions: [Action<[Element]>] = []
private var childRemovedActions: [Action<[Element]>] = []
init(wrappedValue: [Element], _ path: KeyPath<RealtimeDatabase, RealtimeDatabase>, events: Event = .all,
actions: [Action<[Element]>]) {
currentValue = wrappedValue
reference = RealtimeDatabase()[keyPath: path].reference
for action in actions {
if action.event.contains(.childAdded) {
childAddedActions.append(action)
}
if action.event.contains(.childChanged) {
childChangedActions.append(action)
}
if action.event.contains(.childRemoved) {
childRemovedActions.append(action)
}
}
if events.contains(.childAdded) {
childAddedObserverHandle = reference.observe(.childAdded) { [self] snapshot in
guard let value = snapshot.value, let decodedValue = try? FirebaseDecoder().decode(Element.self, from: value) else {
fatalError("Could not decode value from Firebase.")
}
self.objectWillChange.send()
self.currentValue.append(decodedValue)
self.childAddedActions.forEach { $0.action(&self.currentValue) }
}
}
if events.contains(.childChanged) {
childChangedObserverHandle = reference.observe(.childChanged) { [self] snapshot in
guard let value = snapshot.value, let decodedValue = try? FirebaseDecoder().decode(Element.self, from: value) else {
fatalError("Could not decode value from Firebase.")
}
guard let changeIndex = self.currentValue.firstIndex(where: { $0.id == decodedValue.id }) else {
return
}
self.objectWillChange.send()
self.currentValue[changeIndex] = decodedValue
self.childChangedActions.forEach { $0.action(&self.currentValue) }
}
}
if events.contains(.childRemoved) {
childRemovedObserverHandle = reference.observe(.childRemoved) { [self] snapshot in
guard let value = snapshot.value, let decodedValue = try? FirebaseDecoder().decode(Element.self, from: value) else {
fatalError("Could not decode value from Firebase.")
}
self.objectWillChange.send()
self.currentValue.removeAll { $0.id == decodedValue.id }
self.childRemovedActions.forEach { $0.action(&self.currentValue) }
}
}
}
convenience init(wrappedValue: [Element], _ path: KeyPath<RealtimeDatabase, RealtimeDatabase>, events: Event = .all, actions: Action<[Element]>...) {
self.init(wrappedValue: wrappedValue, path, events: events, actions: actions)
}
private func setValue(to value: [Element]) {
guard let encodedValue = try? FirebaseEncoder().encode(currentValue) else {
fatalError("Could not encode value to Firebase.")
}
reference.setValue(encodedValue)
}
var wrappedValue: [Element] {
get {
return currentValue
}
set {
self.objectWillChange.send()
setValue(to: newValue)
}
}
var projectedValue: Binding<[Element]> {
return Binding(get: {
return self.wrappedValue
}) { newValue in
self.wrappedValue = newValue
}
}
var hasActiveObserver: Bool {
return childAddedObserverHandle != nil || childChangedObserverHandle != nil || childRemovedObserverHandle != nil
}
var hasChildAddedObserver: Bool {
return childAddedObserverHandle != nil
}
var hasChildChangedObserver: Bool {
return childChangedObserverHandle != nil
}
var hasChildRemovedObserver: Bool {
return childRemovedObserverHandle != nil
}
func connectObservers(for event: Event) {
if event.contains(.childAdded) && childAddedObserverHandle == nil {
childAddedObserverHandle = reference.observe(.childAdded) { [self] snapshot in
guard let value = snapshot.value, let decodedValue = try? FirebaseDecoder().decode(Element.self, from: value) else {
fatalError("Could not decode value from Firebase.")
}
self.objectWillChange.send()
self.currentValue.append(decodedValue)
self.childAddedActions.forEach { $0.action(&self.currentValue) }
}
}
if event.contains(.childChanged) && childChangedObserverHandle == nil {
childChangedObserverHandle = reference.observe(.childChanged) { [self] snapshot in
guard let value = snapshot.value, let decodedValue = try? FirebaseDecoder().decode(Element.self, from: value) else {
fatalError("Could not decode value from Firebase.")
}
guard let changeIndex = self.currentValue.firstIndex(where: { $0.id == decodedValue.id }) else {
return
}
self.objectWillChange.send()
self.currentValue[changeIndex] = decodedValue
self.childChangedActions.forEach { $0.action(&self.currentValue) }
print("Child Changed")
}
}
if event.contains(.childRemoved) && childRemovedObserverHandle == nil {
childRemovedObserverHandle = reference.observe(.childRemoved) { [self] snapshot in
guard let value = snapshot.value, let decodedValue = try? FirebaseDecoder().decode(Element.self, from: value) else {
fatalError("Could not decode value from Firebase.")
}
self.objectWillChange.send()
self.currentValue.removeAll { $0.id == decodedValue.id }
self.childRemovedActions.forEach { $0.action(&self.currentValue) }
print("Child Removed")
}
}
}
func removeObserver(for event: Event) {
if event.contains(.childAdded), let handle = childAddedObserverHandle {
reference.removeObserver(withHandle: handle)
self.childAddedObserverHandle = nil
}
if event.contains(.childChanged), let handle = childChangedObserverHandle {
reference.removeObserver(withHandle: handle)
self.childChangedObserverHandle = nil
}
if event.contains(.childRemoved), let handle = childRemovedObserverHandle {
reference.removeObserver(withHandle: handle)
self.childRemovedObserverHandle = nil
}
}
func removeAction(_ action: Action<[Element]>) {
if action.event.contains(.childAdded) {
childAddedActions.removeAll { $0.id == action.id }
}
if action.event.contains(.childChanged) {
childChangedActions.removeAll { $0.id == action.id }
}
if action.event.contains(.childRemoved) {
childRemovedActions.removeAll { $0.id == action.id }
}
}
func removeAllActions(for event: Event) {
if event.contains(.childAdded) {
childAddedActions = []
}
if event.contains(.childChanged) {
childChangedActions = []
}
if event.contains(.childRemoved) {
childRemovedActions = []
}
}
}
struct School: Codable, Identifiable {
/// The unique id of the school.
var id: String
/// The name of the school.
var name: String
/// The city of the school.
var city: String
/// The province of the school.
var province: String
/// Email domains for student emails from the school.
var domains: [String]
}
@dynamicMemberLookup
struct RealtimeDatabase {
private var path: [String]
var reference: DatabaseReference {
var ref = Database.database().reference()
for component in path {
ref = ref.child(component)
}
return ref
}
init(previous: Self? = nil, child: String? = nil) {
if let previous = previous {
path = previous.path
} else {
path = []
}
if let child = child {
path.append(child)
}
}
static subscript(dynamicMember member: String) -> Self {
return Self(child: member)
}
subscript(dynamicMember member: String) -> Self {
return Self(child: member)
}
static subscript(dynamicMember keyPath: KeyPath<Self, Self>) -> Self {
return Self()[keyPath: keyPath]
}
static let reference = Database.database().reference()
struct Event: OptionSet, Hashable {
let rawValue: UInt
static let childAdded = Event(rawValue: 1 << 0)
static let childChanged = Event(rawValue: 1 << 1)
static let childRemoved = Event(rawValue: 1 << 2)
static let all: Event = [.childAdded, .childChanged, .childRemoved]
static let constructive: Event = [.childAdded, .childChanged]
static let destructive: Event = .childRemoved
}
struct Action<Value>: Identifiable {
let id = UUID()
let event: Event
let action: (inout Value) -> Void
private init(on event: Event, perform action: @escaping (inout Value) -> Void) {
self.event = event
self.action = action
}
static func on<Value>(_ event: RealtimeDatabase.Event, perform action: @escaping (inout Value) -> Void) -> Action<Value> {
return Action<Value>(on: event, perform: action)
}
}
}
Does anyone know why this is happening? Is this indeed a bug?
Update
Here is a more generalized version of the problem that does not have the same external dependencies that the previous example has:
import SwiftUI
struct FooView: View {
@Bar(things: 4)
var foo: Int = []
var body: some View {
Text("Hello, World!")
}
}
@propertyWrapper
struct Bar<Value> {
var baz: [Value]
var someStuff: [Value]
init(wrappedValue: [Value], things: [Value]) {
self.baz = wrappedValue
self.someStuff = things
}
init(wrappedValue: [Value], things: Value...) {
self.init(wrappedValue: wrappedValue, things: things)
}
var wrappedValue: Value {
return baz.randomElement()!
}
}
This fails with a Segmentation fault 11
:
1. While emitting IR SIL function "@$s17Firebase_Practice7FooViewV3fooACSi_tcfC".
for 'init(foo:)' (at /Users/noahwilder/Desktop/Dating App/Practice/Firebase Practice/Firebase Practice/FooView.swift:11:8)
0 swift 0x000000010b1e7a63 PrintStackTraceSignalHandler(void*) + 51
1 swift 0x000000010b1e7236 SignalHandler(int) + 358
2 libsystem_platform.dylib 0x00007fff7140a42d _sigtramp + 29
3 swift 0x00000001070180ed swift::irgen::RecordTypeInfoImpl<(anonymous namespace)::LoadableStructTypeInfo, swift::irgen::LoadableTypeInfo, (anonymous namespace)::StructFieldInfo, true>::getSchema(swift::irgen::ExplosionSchema&) const + 61
4 swift 0x000000010706ab4a swift::irgen::IRGenModule::emitSILFunction(swift::SILFunction*) + 9834
5 swift 0x0000000106f15c50 swift::irgen::IRGenerator::emitGlobalTopLevel() + 1712
6 swift 0x00000001070478c5 performIRGeneration(swift::IRGenOptions&, swift::ModuleDecl*, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule> >, llvm::StringRef, swift::PrimarySpecificPaths const&, llvm::LLVMContext&, swift::SourceFile*, llvm::GlobalVariable**) + 1189
7 swift 0x0000000106e32a01 performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) + 36673
8 swift 0x0000000106e262b4 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 6820
9 swift 0x0000000106db37b3 main + 1219
10 libdyld.dylib 0x00007fff712117fd start + 1
error: Segmentation fault: 11 (in target 'Firebase Practice' from project 'Firebase Practice')