diff --git a/Sources/SwiftSyntax/ByteTreeDeserialization.swift b/Sources/SwiftSyntax/ByteTreeDeserialization.swift index 13101a633fa..87f2c128b79 100644 --- a/Sources/SwiftSyntax/ByteTreeDeserialization.swift +++ b/Sources/SwiftSyntax/ByteTreeDeserialization.swift @@ -22,6 +22,17 @@ struct ByteTreeUserInfoKey: Hashable { } } +public enum ByteTreeDecodingError: Error, CustomStringConvertible { + case invalidEnumRawValue(type: String, value: Int) + + public var description: String { + switch self { + case .invalidEnumRawValue(let type, let value): + return "Invalid raw value \"\(value)\" for \(type)" + } + } +} + /// A type that can be deserialized from ByteTree into a scalar value that /// doesn't have any child nodes protocol ByteTreeScalarDecodable { @@ -32,7 +43,8 @@ protocol ByteTreeScalarDecodable { /// - size: The length of the serialized data in bytes /// - Returns: The deserialized value static func read(from pointer: UnsafeRawPointer, size: Int, - userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]>) -> Self + userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]> + ) throws -> Self } /// A type that can be deserialized from ByteTree into an object with child @@ -50,7 +62,8 @@ protocol ByteTreeObjectDecodable { /// - Returns: The deserialized object static func read(from reader: UnsafeMutablePointer, numFields: Int, - userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]>) -> Self + userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]> + ) throws -> Self } // MARK: - Reader objects @@ -92,9 +105,9 @@ struct ByteTreeObjectReader { /// - Returns: The decoded field mutating func readField( _ objectType: FieldType.Type, index: Int - ) -> FieldType { + ) throws -> FieldType { advanceAndValidateIndex(index) - return reader.pointee.read(objectType) + return try reader.pointee.read(objectType) } /// Read the field at the given index as the specified type. All indicies must @@ -107,9 +120,9 @@ struct ByteTreeObjectReader { /// - Returns: The decoded field mutating func readField( _ objectType: FieldType.Type, index: Int - ) -> FieldType { + ) throws -> FieldType { advanceAndValidateIndex(index) - return reader.pointee.read(objectType) + return try reader.pointee.read(objectType) } /// Read and immediately discard the field at the specified index. This @@ -178,7 +191,7 @@ struct ByteTreeReader { ) throws -> T { var reader = ByteTreeReader(pointer: pointer, userInfo: userInfo) try reader.readAndValidateProtocolVersion(protocolVersionValidation) - return reader.read(rootObjectType) + return try reader.read(rootObjectType) } /// Deserialize an object tree from the ByteTree data at the given memory @@ -266,15 +279,15 @@ struct ByteTreeReader { /// - Returns: The deserialized object fileprivate mutating func read( _ objectType: T.Type - ) -> T { + ) throws -> T { let numFields = readObjectLength() var objectReader = ByteTreeObjectReader(reader: &self, numFields: numFields) defer { objectReader.finalize() } - return T.read(from: &objectReader, numFields: numFields, - userInfo: userInfo) + return try T.read(from: &objectReader, numFields: numFields, + userInfo: userInfo) } /// Read the next field in the tree as a scalar of the specified type. @@ -283,12 +296,12 @@ struct ByteTreeReader { /// - Returns: The deserialized scalar fileprivate mutating func read( _ scalarType: T.Type - ) -> T { + ) throws -> T { let fieldSize = readScalarLength() defer { pointer = pointer.advanced(by: fieldSize) } - return T.read(from: pointer, size: fieldSize, userInfo: userInfo) + return try T.read(from: pointer, size: fieldSize, userInfo: userInfo) } /// Discard the next scalar field, advancing the pointer to the next field @@ -338,12 +351,12 @@ extension Optional: ByteTreeObjectDecodable static func read(from reader: UnsafeMutablePointer, numFields: Int, userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]> - ) -> Optional { + ) throws -> Optional { if numFields == 0 { return nil } else { - return Wrapped.read(from: reader, numFields: numFields, - userInfo: userInfo) + return try Wrapped.read(from: reader, numFields: numFields, + userInfo: userInfo) } } } @@ -354,9 +367,9 @@ extension Array: ByteTreeObjectDecodable static func read(from reader: UnsafeMutablePointer, numFields: Int, userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]> - ) -> Array { - return (0.. Array { + return try (0.., numFields: Int, userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]> - ) -> RawSyntax { + ) throws -> RawSyntax { let syntaxNode: RawSyntax - let type = reader.pointee.readField(SyntaxType.self, index: 0) - let id = reader.pointee.readField(SyntaxNodeId.self, index: 1) + let type = try reader.pointee.readField(SyntaxType.self, index: 0) + let id = try reader.pointee.readField(SyntaxNodeId.self, index: 1) switch type { case .token: - let presence = reader.pointee.readField(SourcePresence.self, index: 2) - let kind = reader.pointee.readField(TokenKind.self, index: 3) - let leadingTrivia = reader.pointee.readField(Trivia.self, index: 4) - let trailingTrivia = reader.pointee.readField(Trivia.self, index: 5) + let presence = try reader.pointee.readField(SourcePresence.self, index: 2) + let kind = try reader.pointee.readField(TokenKind.self, index: 3) + let leadingTrivia = try reader.pointee.readField(Trivia.self, index: 4) + let trailingTrivia = try reader.pointee.readField(Trivia.self, index: 5) syntaxNode = RawSyntax(kind: kind, leadingTrivia: leadingTrivia, trailingTrivia: trailingTrivia, presence: presence, id: id) case .layout: - let presence = reader.pointee.readField(SourcePresence.self, index: 2) - let kind = reader.pointee.readField(SyntaxKind.self, index: 3) - let layout = reader.pointee.readField([RawSyntax?].self, index: 4) + let presence = try reader.pointee.readField(SourcePresence.self, index: 2) + let kind = try reader.pointee.readField(SyntaxKind.self, index: 3) + let layout = try reader.pointee.readField([RawSyntax?].self, index: 4) syntaxNode = RawSyntax(kind: kind, layout: layout, presence: presence, id: id) case .omitted: guard let lookupFunc = userInfo.pointee[.omittedNodeLookupFunction] as? (SyntaxNodeId) -> RawSyntax? else { - fatalError("omittedNodeLookupFunction is required when decoding an " + - "incrementally transferred syntax tree") + throw IncrementalDecodingError.noLookupFunctionPassed } guard let lookupNode = lookupFunc(id) else { - fatalError("Node lookup for id \(id) failed") + throw IncrementalDecodingError.nodeLookupFailed(id) } syntaxNode = lookupNode } diff --git a/Sources/SwiftSyntax/TokenKind.swift.gyb b/Sources/SwiftSyntax/TokenKind.swift.gyb index 9f47387cb61..463fdbb8719 100644 --- a/Sources/SwiftSyntax/TokenKind.swift.gyb +++ b/Sources/SwiftSyntax/TokenKind.swift.gyb @@ -114,10 +114,10 @@ extension TokenKind: ByteTreeObjectDecodable { static func read(from reader: UnsafeMutablePointer, numFields: Int, userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]> - ) -> TokenKind { + ) throws -> TokenKind { // Explicitly spell out all TokenKinds to keep the serialized value stable // even if its members get reordered or members get removed - let kind = reader.pointee.readField(UInt8.self, index: 0) + let kind = try reader.pointee.readField(UInt8.self, index: 0) switch kind { case 0: return .eof % for token in SYNTAX_TOKENS: @@ -125,7 +125,7 @@ extension TokenKind: ByteTreeObjectDecodable { % if token.text: # The token does not have text associated with it return .${token.swift_kind()} % else: - let text = reader.pointee.readField(String.self, index: 1) + let text = try reader.pointee.readField(String.self, index: 1) return .${token.swift_kind()}(text) % end % end @@ -133,12 +133,13 @@ extension TokenKind: ByteTreeObjectDecodable { if numFields > 1 { // Default to an unknown token with the passed text if we don't know // its kind. - let text = reader.pointee.readField(String.self, index: 1) + let text = try reader.pointee.readField(String.self, index: 1) return .unknown(text) } else { // If we were not passed the token's text, we cannot recover since we // would lose roundtripness. - fatalError("Unknown TokenKind \(kind)") + throw ByteTreeDecodingError.invalidEnumRawValue(type: "\(self)", + value: Int(kind)) } } } diff --git a/Sources/SwiftSyntax/Trivia.swift.gyb b/Sources/SwiftSyntax/Trivia.swift.gyb index 1f8336b9f06..cff30c24347 100644 --- a/Sources/SwiftSyntax/Trivia.swift.gyb +++ b/Sources/SwiftSyntax/Trivia.swift.gyb @@ -224,9 +224,9 @@ extension Trivia: ByteTreeObjectDecodable { static func read(from reader: UnsafeMutablePointer, numFields: Int, userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]> - ) -> Trivia { - let pieces = [TriviaPiece].read(from: reader, numFields: numFields, - userInfo: userInfo) + ) throws -> Trivia { + let pieces = try [TriviaPiece].read(from: reader, numFields: numFields, + userInfo: userInfo) return Trivia(pieces: pieces) } } @@ -235,21 +235,22 @@ extension TriviaPiece: ByteTreeObjectDecodable { static func read(from reader: UnsafeMutablePointer, numFields: Int, userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]> - ) -> TriviaPiece { - let kind = reader.pointee.readField(UInt8.self, index: 0) + ) throws -> TriviaPiece { + let kind = try reader.pointee.readField(UInt8.self, index: 0) switch kind { % for trivia in TRIVIAS: case ${trivia.serialization_code}: % if trivia.is_collection(): - let count = Int(reader.pointee.readField(UInt32.self, index: 1)) + let count = Int(try reader.pointee.readField(UInt32.self, index: 1)) return .${trivia.lower_name}s(count) % else: - let text = reader.pointee.readField(String.self, index: 1) + let text = try reader.pointee.readField(String.self, index: 1) return .${trivia.lower_name}(text) % end % end default: - fatalError("Unknown trivia piece kind \(kind)") + throw ByteTreeDecodingError.invalidEnumRawValue(type: "\(self)", + value: Int(kind)) } } }