Skip to content

Commit 3f3b823

Browse files
committed
Support proto3 optional in generation.
- Filter out synthetic oneofs from oneof generation - Map proto3 optional fields to normal fields (ignoring the oneof). - Use the new api on descriptor to tell if a field gets presence support. - Regenerate the files with the support. Note: Yes, the diffs in the generated show yet another issue with our naming, the wrapper oneof (before we filtered it out) was a naming collision with the field. Updating our naming support to consider all other fields/oneofs for collisions is something we've never done, but might actually have to happen since we do transform names. Until then, issue like this will remain things that the compiler catchs and the generator never works around.
1 parent 126c8c9 commit 3f3b823

File tree

7 files changed

+236
-731
lines changed

7 files changed

+236
-731
lines changed

Reference/google/protobuf/unittest_proto3_optional.pb.swift

Lines changed: 182 additions & 587 deletions
Large diffs are not rendered by default.

Reference/pluginlib_descriptor_test2.pb.swift

Lines changed: 40 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -56,45 +56,41 @@ struct SwiftDescriptorTest_Proto3MessageForPresence {
5656
/// Clears the value of `messageField`. Subsequent reads from it will return its default value.
5757
mutating func clearMessageField() {self._messageField = nil}
5858

59-
var optStrField: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptStrField? = nil
60-
6159
var optStrField: String {
62-
get {
63-
if case .optStrField(let v)? = optStrField {return v}
64-
return String()
65-
}
66-
set {optStrField = .optStrField(newValue)}
60+
get {return _optStrField ?? String()}
61+
set {_optStrField = newValue}
6762
}
68-
69-
var optInt32Field: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptInt32Field? = nil
63+
/// Returns true if `optStrField` has been explicitly set.
64+
var hasOptStrField: Bool {return self._optStrField != nil}
65+
/// Clears the value of `optStrField`. Subsequent reads from it will return its default value.
66+
mutating func clearOptStrField() {self._optStrField = nil}
7067

7168
var optInt32Field: Int32 {
72-
get {
73-
if case .optInt32Field(let v)? = optInt32Field {return v}
74-
return 0
75-
}
76-
set {optInt32Field = .optInt32Field(newValue)}
69+
get {return _optInt32Field ?? 0}
70+
set {_optInt32Field = newValue}
7771
}
78-
79-
var optEnumField: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptEnumField? = nil
72+
/// Returns true if `optInt32Field` has been explicitly set.
73+
var hasOptInt32Field: Bool {return self._optInt32Field != nil}
74+
/// Clears the value of `optInt32Field`. Subsequent reads from it will return its default value.
75+
mutating func clearOptInt32Field() {self._optInt32Field = nil}
8076

8177
var optEnumField: SwiftDescriptorTest_Proto3MessageForPresence.SubEnum {
82-
get {
83-
if case .optEnumField(let v)? = optEnumField {return v}
84-
return .subValue0
85-
}
86-
set {optEnumField = .optEnumField(newValue)}
78+
get {return _optEnumField ?? .subValue0}
79+
set {_optEnumField = newValue}
8780
}
88-
89-
var optMessageField: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptMessageField? = nil
81+
/// Returns true if `optEnumField` has been explicitly set.
82+
var hasOptEnumField: Bool {return self._optEnumField != nil}
83+
/// Clears the value of `optEnumField`. Subsequent reads from it will return its default value.
84+
mutating func clearOptEnumField() {self._optEnumField = nil}
9085

9186
var optMessageField: SwiftDescriptorTest_OtherMessage {
92-
get {
93-
if case .optMessageField(let v)? = optMessageField {return v}
94-
return SwiftDescriptorTest_OtherMessage()
95-
}
96-
set {optMessageField = .optMessageField(newValue)}
87+
get {return _optMessageField ?? SwiftDescriptorTest_OtherMessage()}
88+
set {_optMessageField = newValue}
9789
}
90+
/// Returns true if `optMessageField` has been explicitly set.
91+
var hasOptMessageField: Bool {return self._optMessageField != nil}
92+
/// Clears the value of `optMessageField`. Subsequent reads from it will return its default value.
93+
mutating func clearOptMessageField() {self._optMessageField = nil}
9894

9995
var repeatStrField: [String] = []
10096

@@ -159,54 +155,6 @@ struct SwiftDescriptorTest_Proto3MessageForPresence {
159155
#endif
160156
}
161157

162-
enum OneOf_OptStrField: Equatable {
163-
case optStrField(String)
164-
165-
#if !swift(>=4.1)
166-
static func ==(lhs: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptStrField, rhs: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptStrField) -> Bool {
167-
switch (lhs, rhs) {
168-
case (.optStrField(let l), .optStrField(let r)): return l == r
169-
}
170-
}
171-
#endif
172-
}
173-
174-
enum OneOf_OptInt32Field: Equatable {
175-
case optInt32Field(Int32)
176-
177-
#if !swift(>=4.1)
178-
static func ==(lhs: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptInt32Field, rhs: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptInt32Field) -> Bool {
179-
switch (lhs, rhs) {
180-
case (.optInt32Field(let l), .optInt32Field(let r)): return l == r
181-
}
182-
}
183-
#endif
184-
}
185-
186-
enum OneOf_OptEnumField: Equatable {
187-
case optEnumField(SwiftDescriptorTest_Proto3MessageForPresence.SubEnum)
188-
189-
#if !swift(>=4.1)
190-
static func ==(lhs: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptEnumField, rhs: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptEnumField) -> Bool {
191-
switch (lhs, rhs) {
192-
case (.optEnumField(let l), .optEnumField(let r)): return l == r
193-
}
194-
}
195-
#endif
196-
}
197-
198-
enum OneOf_OptMessageField: Equatable {
199-
case optMessageField(SwiftDescriptorTest_OtherMessage)
200-
201-
#if !swift(>=4.1)
202-
static func ==(lhs: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptMessageField, rhs: SwiftDescriptorTest_Proto3MessageForPresence.OneOf_OptMessageField) -> Bool {
203-
switch (lhs, rhs) {
204-
case (.optMessageField(let l), .optMessageField(let r)): return l == r
205-
}
206-
}
207-
#endif
208-
}
209-
210158
enum SubEnum: SwiftProtobuf.Enum {
211159
typealias RawValue = Int
212160
case subValue0 // = 0
@@ -241,6 +189,10 @@ struct SwiftDescriptorTest_Proto3MessageForPresence {
241189
init() {}
242190

243191
fileprivate var _messageField: SwiftDescriptorTest_OtherMessage? = nil
192+
fileprivate var _optStrField: String? = nil
193+
fileprivate var _optInt32Field: Int32? = nil
194+
fileprivate var _optEnumField: SwiftDescriptorTest_Proto3MessageForPresence.SubEnum? = nil
195+
fileprivate var _optMessageField: SwiftDescriptorTest_OtherMessage? = nil
244196
}
245197

246198
#if swift(>=4.2)
@@ -300,29 +252,10 @@ extension SwiftDescriptorTest_Proto3MessageForPresence: SwiftProtobuf.Message, S
300252
case 2: try decoder.decodeSingularInt32Field(value: &self.int32Field)
301253
case 3: try decoder.decodeSingularEnumField(value: &self.enumField)
302254
case 4: try decoder.decodeSingularMessageField(value: &self._messageField)
303-
case 11:
304-
if self.optStrField != nil {try decoder.handleConflictingOneOf()}
305-
var v: String?
306-
try decoder.decodeSingularStringField(value: &v)
307-
if let v = v {self.optStrField = .optStrField(v)}
308-
case 12:
309-
if self.optInt32Field != nil {try decoder.handleConflictingOneOf()}
310-
var v: Int32?
311-
try decoder.decodeSingularInt32Field(value: &v)
312-
if let v = v {self.optInt32Field = .optInt32Field(v)}
313-
case 13:
314-
if self.optEnumField != nil {try decoder.handleConflictingOneOf()}
315-
var v: SwiftDescriptorTest_Proto3MessageForPresence.SubEnum?
316-
try decoder.decodeSingularEnumField(value: &v)
317-
if let v = v {self.optEnumField = .optEnumField(v)}
318-
case 14:
319-
var v: SwiftDescriptorTest_OtherMessage?
320-
if let current = self.optMessageField {
321-
try decoder.handleConflictingOneOf()
322-
if case .optMessageField(let m) = current {v = m}
323-
}
324-
try decoder.decodeSingularMessageField(value: &v)
325-
if let v = v {self.optMessageField = .optMessageField(v)}
255+
case 11: try decoder.decodeSingularStringField(value: &self._optStrField)
256+
case 12: try decoder.decodeSingularInt32Field(value: &self._optInt32Field)
257+
case 13: try decoder.decodeSingularEnumField(value: &self._optEnumField)
258+
case 14: try decoder.decodeSingularMessageField(value: &self._optMessageField)
326259
case 21: try decoder.decodeRepeatedStringField(value: &self.repeatStrField)
327260
case 22: try decoder.decodeRepeatedInt32Field(value: &self.repeatInt32Field)
328261
case 23: try decoder.decodeRepeatedEnumField(value: &self.repeatEnumField)
@@ -368,16 +301,16 @@ extension SwiftDescriptorTest_Proto3MessageForPresence: SwiftProtobuf.Message, S
368301
if let v = self._messageField {
369302
try visitor.visitSingularMessageField(value: v, fieldNumber: 4)
370303
}
371-
if case .optStrField(let v)? = self.optStrField {
304+
if let v = self._optStrField {
372305
try visitor.visitSingularStringField(value: v, fieldNumber: 11)
373306
}
374-
if case .optInt32Field(let v)? = self.optInt32Field {
307+
if let v = self._optInt32Field {
375308
try visitor.visitSingularInt32Field(value: v, fieldNumber: 12)
376309
}
377-
if case .optEnumField(let v)? = self.optEnumField {
310+
if let v = self._optEnumField {
378311
try visitor.visitSingularEnumField(value: v, fieldNumber: 13)
379312
}
380-
if case .optMessageField(let v)? = self.optMessageField {
313+
if let v = self._optMessageField {
381314
try visitor.visitSingularMessageField(value: v, fieldNumber: 14)
382315
}
383316
if !self.repeatStrField.isEmpty {
@@ -411,10 +344,10 @@ extension SwiftDescriptorTest_Proto3MessageForPresence: SwiftProtobuf.Message, S
411344
if lhs.int32Field != rhs.int32Field {return false}
412345
if lhs.enumField != rhs.enumField {return false}
413346
if lhs._messageField != rhs._messageField {return false}
414-
if lhs.optStrField != rhs.optStrField {return false}
415-
if lhs.optInt32Field != rhs.optInt32Field {return false}
416-
if lhs.optEnumField != rhs.optEnumField {return false}
417-
if lhs.optMessageField != rhs.optMessageField {return false}
347+
if lhs._optStrField != rhs._optStrField {return false}
348+
if lhs._optInt32Field != rhs._optInt32Field {return false}
349+
if lhs._optEnumField != rhs._optEnumField {return false}
350+
if lhs._optMessageField != rhs._optMessageField {return false}
418351
if lhs.repeatStrField != rhs.repeatStrField {return false}
419352
if lhs.repeatInt32Field != rhs.repeatInt32Field {return false}
420353
if lhs.repeatEnumField != rhs.repeatEnumField {return false}

Sources/protoc-gen-swift/Descriptor+Extensions.swift

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ extension FileDescriptor {
1616
return syntax == .proto3
1717
}
1818

19-
/// True of primative field types should have field presence.
20-
var hasPrimativeFieldPresence: Bool {
21-
return syntax == .proto2
22-
}
23-
2419
var isBundledProto: Bool {
2520
return SwiftProtobufInfo.isBundledProto(file: proto)
2621
}
@@ -100,25 +95,6 @@ extension Descriptor {
10095
}
10196

10297
extension FieldDescriptor {
103-
/// True if this field should have presence support
104-
var hasFieldPresence: Bool {
105-
if label == .repeated { // Covers both Arrays and Maps
106-
return false
107-
}
108-
if oneofIndex != nil {
109-
// When in a oneof, no presence is provided.
110-
return false
111-
}
112-
switch type {
113-
case .group, .message:
114-
// Groups/messages always get field presence.
115-
return true
116-
default:
117-
// Depends on the context the message was declared in.
118-
return file.hasPrimativeFieldPresence
119-
}
120-
}
121-
12298
func swiftType(namer: SwiftProtobufNamer) -> String {
12399
if isMap {
124100
let mapDescriptor: Descriptor = messageType
@@ -163,7 +139,10 @@ extension FieldDescriptor {
163139
case .repeated:
164140
return swiftType
165141
case .optional, .required:
166-
if hasFieldPresence {
142+
guard realOneof == nil else {
143+
return swiftType
144+
}
145+
if hasPresence {
167146
return "\(swiftType)?"
168147
} else {
169148
return swiftType

Sources/protoc-gen-swift/MessageFieldGenerator.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ class MessageFieldGenerator: FieldGeneratorBase, FieldGenerator {
5252
namer: SwiftProtobufNamer,
5353
usesHeapStorage: Bool)
5454
{
55-
precondition(descriptor.oneofIndex == nil)
55+
precondition(descriptor.realOneof == nil)
5656

5757
self.generatorOptions = generatorOptions
5858
self.usesHeapStorage = usesHeapStorage
5959

60-
hasFieldPresence = descriptor.hasFieldPresence
60+
hasFieldPresence = descriptor.hasPresence && descriptor.realOneof == nil
6161
let names = namer.messagePropertyNames(field: descriptor,
6262
prefixed: "_",
6363
includeHasAndClear: hasFieldPresence)

Sources/protoc-gen-swift/MessageGenerator.swift

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class MessageGenerator {
5555
// storage yet.
5656
let useHeapStorage = isAnyMessage || descriptor.fields.count > 16 || hasRecursiveSingularField(descriptor: descriptor)
5757

58-
oneofs = descriptor.oneofs.map {
58+
oneofs = descriptor.realOneofs.map {
5959
return OneofGenerator(descriptor: $0, generatorOptions: generatorOptions, namer: namer, usesHeapStorage: useHeapStorage)
6060
}
6161

@@ -553,13 +553,12 @@ fileprivate struct MessageFieldFactory {
553553
}
554554

555555
func make(forFieldDescriptor field: FieldDescriptor) -> FieldGenerator {
556-
if let oneofIndex = field.oneofIndex {
557-
return oneofs[Int(oneofIndex)].fieldGenerator(forFieldNumber: Int(field.number))
558-
} else {
559-
return MessageFieldGenerator(descriptor: field,
560-
generatorOptions: generatorOptions,
561-
namer: namer,
562-
usesHeapStorage: useHeapStorage)
556+
guard field.realOneof == nil else {
557+
return oneofs[Int(field.oneofIndex!)].fieldGenerator(forFieldNumber: Int(field.number))
563558
}
559+
return MessageFieldGenerator(descriptor: field,
560+
generatorOptions: generatorOptions,
561+
namer: namer,
562+
usesHeapStorage: useHeapStorage)
564563
}
565564
}

Sources/protoc-gen-swift/OneofGenerator.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ class OneofGenerator {
120120
private let storedProperty: String
121121

122122
init(descriptor: OneofDescriptor, generatorOptions: GeneratorOptions, namer: SwiftProtobufNamer, usesHeapStorage: Bool) {
123+
precondition(!descriptor.isSynthetic)
123124
self.oneofDescriptor = descriptor
124125
self.generatorOptions = generatorOptions
125126
self.namer = namer

Sources/protoc-gen-swift/main.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,6 @@ struct GeneratorPlugin {
239239
Google_Protobuf_Compiler_CodeGeneratorResponse.File(name: fileGenerator.outputFilename,
240240
content: printer.content))
241241
}
242-
// TODO(thomasvl): Don't support proto3Optional just yet, but working on
243-
// it and this let things generate in the mean time.
244242
return Google_Protobuf_Compiler_CodeGeneratorResponse(files: responseFiles,
245243
supportedFeatures: [.proto3Optional])
246244
}

0 commit comments

Comments
 (0)