Skip to content

Commit b835465

Browse files
authored
[pigeon] adds support for collections of enums and classes (#7476)
adds support for collections of enums and classes fixes flutter/flutter#133728
1 parent 1f9b89b commit b835465

File tree

35 files changed

+20688
-2647
lines changed

35 files changed

+20688
-2647
lines changed

packages/pigeon/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 22.3.0
2+
3+
* Adds support for enums and classes in collections.
4+
15
## 22.2.0
26

37
* [kotlin] Adds implementation for `@ProxyApi`.

packages/pigeon/example/app/ios/Runner/Messages.g.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ private class MessagesPigeonCodecReader: FlutterStandardReader {
113113
override func readValue(ofType type: UInt8) -> Any? {
114114
switch type {
115115
case 129:
116-
let enumResultAsInt: Int? = nilOrValue(self.readValue() as? Int)
116+
let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?)
117117
if let enumResultAsInt = enumResultAsInt {
118118
return Code(rawValue: enumResultAsInt)
119119
}
@@ -191,8 +191,8 @@ class ExampleHostApiSetup {
191191
if let api = api {
192192
addChannel.setMessageHandler { message, reply in
193193
let args = message as! [Any?]
194-
let aArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32)
195-
let bArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
194+
let aArg = args[0] as! Int64
195+
let bArg = args[1] as! Int64
196196
do {
197197
let result = try api.add(aArg, to: bArg)
198198
reply(wrapResult(result))

packages/pigeon/lib/generator_tools.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import 'ast.dart';
1414
/// The current version of pigeon.
1515
///
1616
/// This must match the version in pubspec.yaml.
17-
const String pigeonVersion = '22.2.0';
17+
const String pigeonVersion = '22.3.0';
1818

1919
/// Read all the content from [stdin] to a String.
2020
String readStdin() {

packages/pigeon/lib/pigeon_lib.dart

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -979,13 +979,6 @@ List<Error> _validateAst(Root root, String source) {
979979
lineNumber: _calculateLineNumberNullable(source, field.offset),
980980
));
981981
}
982-
if (customEnums.contains(typeArgument.baseName)) {
983-
result.add(Error(
984-
message:
985-
'Enum types aren\'t supported in type arguments in "${field.name}" in class "${classDefinition.name}".',
986-
lineNumber: _calculateLineNumberNullable(source, field.offset),
987-
));
988-
}
989982
}
990983
if (!(validTypes.contains(field.type.baseName) ||
991984
customClasses.contains(field.type.baseName) ||

packages/pigeon/lib/swift_generator.dart

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ class SwiftGenerator extends StructuredGenerator<SwiftOptions> {
145145
indent.nest(1, () {
146146
if (customType.type == CustomTypes.customEnum) {
147147
indent.writeln(
148-
'let enumResultAsInt: Int? = nilOrValue(self.readValue() as? Int)');
148+
'let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?)');
149149
indent.writeScoped('if let enumResultAsInt = enumResultAsInt {', '}',
150150
() {
151151
indent.writeln(
@@ -419,7 +419,7 @@ if (wrapped == nil) {
419419
}
420420

421421
void _writeClassField(Indent indent, NamedType field, {bool addNil = true}) {
422-
indent.add('${field.name}: ${_nullsafeSwiftTypeForDartType(field.type)}');
422+
indent.add('${field.name}: ${_nullSafeSwiftTypeForDartType(field.type)}');
423423
final String defaultNil = field.type.isNullable && addNil ? ' = nil' : '';
424424
indent.add(defaultNil);
425425
}
@@ -487,7 +487,17 @@ if (wrapped == nil) {
487487
getFieldsInSerializationOrder(classDefinition).last == field
488488
? ''
489489
: ',';
490-
indent.writeln('${field.name}: ${field.name}$comma');
490+
// Force-casting nullable enums in maps doesn't work the same as other types.
491+
// It needs soft-casting followed by force unwrapping.
492+
final String forceUnwrapMapWithNullableEnums =
493+
(field.type.baseName == 'Map' &&
494+
!field.type.isNullable &&
495+
field.type.typeArguments
496+
.any((TypeDeclaration type) => type.isEnum))
497+
? '!'
498+
: '';
499+
indent.writeln(
500+
'${field.name}: ${field.name}$forceUnwrapMapWithNullableEnums$comma');
491501
}
492502
});
493503
});
@@ -650,14 +660,11 @@ if (wrapped == nil) {
650660
assert(!type.isVoid);
651661
if (type.baseName == 'Object') {
652662
return value + (type.isNullable ? '' : '!');
653-
} else if (type.baseName == 'int') {
654-
if (type.isNullable) {
655-
// Nullable ints need to check for NSNull, and Int32 before casting can be done safely.
656-
// This nested ternary is a necessary evil to avoid less efficient conversions.
657-
return 'isNullish($value) ? nil : ($value is Int64? ? $value as! Int64? : Int64($value as! Int32))';
658-
} else {
659-
return '$value is Int64 ? $value as! Int64 : Int64($value as! Int32)';
660-
}
663+
// Force-casting nullable enums in maps doesn't work the same as other types.
664+
// It needs soft-casting followed by force unwrapping.
665+
} else if (type.baseName == 'Map' &&
666+
type.typeArguments.any((TypeDeclaration type) => type.isEnum)) {
667+
return '$value as? ${_swiftTypeForDartType(type)}';
661668
} else if (type.isNullable) {
662669
return 'nilOrValue($value)';
663670
} else {
@@ -846,7 +853,13 @@ private func nilOrValue<T>(_ value: Any?) -> T? {
846853
fieldType: fieldType,
847854
type: returnType,
848855
);
849-
indent.writeln('completion(.success(result))');
856+
// There is a swift bug with unwrapping maps of nullable Enums;
857+
final String enumMapForceUnwrap = returnType.baseName == 'Map' &&
858+
returnType.typeArguments
859+
.any((TypeDeclaration type) => type.isEnum)
860+
? '!'
861+
: '';
862+
indent.writeln('completion(.success(result$enumMapForceUnwrap))');
850863
}
851864
});
852865
});
@@ -887,6 +900,12 @@ private func nilOrValue<T>(_ value: Any?) -> T? {
887900
final String argName = _getSafeArgumentName(index, arg.namedType);
888901
final String argIndex = 'args[$index]';
889902
final String fieldType = _swiftTypeForDartType(arg.type);
903+
// There is a swift bug with unwrapping maps of nullable Enums;
904+
final String enumMapForceUnwrap = arg.type.baseName == 'Map' &&
905+
arg.type.typeArguments
906+
.any((TypeDeclaration type) => type.isEnum)
907+
? '!'
908+
: '';
890909

891910
_writeGenericCasting(
892911
indent: indent,
@@ -896,9 +915,10 @@ private func nilOrValue<T>(_ value: Any?) -> T? {
896915
type: arg.type);
897916

898917
if (arg.label == '_') {
899-
methodArgument.add(argName);
918+
methodArgument.add('$argName$enumMapForceUnwrap');
900919
} else {
901-
methodArgument.add('${arg.label ?? arg.name}: $argName');
920+
methodArgument
921+
.add('${arg.label ?? arg.name}: $argName$enumMapForceUnwrap');
902922
}
903923
});
904924
}
@@ -1022,9 +1042,9 @@ String _swiftTypeForBuiltinGenericDartType(TypeDeclaration type) {
10221042
}
10231043
} else {
10241044
if (type.baseName == 'List') {
1025-
return '[${_nullsafeSwiftTypeForDartType(type.typeArguments.first)}]';
1045+
return '[${_nullSafeSwiftTypeForDartType(type.typeArguments.first)}]';
10261046
} else if (type.baseName == 'Map') {
1027-
return '[${_nullsafeSwiftTypeForDartType(type.typeArguments.first)}: ${_nullsafeSwiftTypeForDartType(type.typeArguments.last)}]';
1047+
return '[${_nullSafeSwiftTypeForDartType(type.typeArguments.first)}: ${_nullSafeSwiftTypeForDartType(type.typeArguments.last)}]';
10281048
} else {
10291049
return '${type.baseName}<${_flattenTypeArguments(type.typeArguments)}>';
10301050
}
@@ -1058,7 +1078,7 @@ String _swiftTypeForDartType(TypeDeclaration type) {
10581078
return _swiftTypeForBuiltinDartType(type) ?? type.baseName;
10591079
}
10601080

1061-
String _nullsafeSwiftTypeForDartType(TypeDeclaration type) {
1081+
String _nullSafeSwiftTypeForDartType(TypeDeclaration type) {
10621082
final String nullSafe = type.isNullable ? '?' : '';
10631083
return '${_swiftTypeForDartType(type)}$nullSafe';
10641084
}
@@ -1080,10 +1100,10 @@ String _getMethodSignature({
10801100
swiftFunction: swiftFunction,
10811101
);
10821102
final String returnTypeString =
1083-
returnType.isVoid ? 'Void' : _nullsafeSwiftTypeForDartType(returnType);
1103+
returnType.isVoid ? 'Void' : _nullSafeSwiftTypeForDartType(returnType);
10841104

10851105
final Iterable<String> types =
1086-
parameters.map((NamedType e) => _nullsafeSwiftTypeForDartType(e.type));
1106+
parameters.map((NamedType e) => _nullSafeSwiftTypeForDartType(e.type));
10871107
final Iterable<String> labels = indexMap(components.arguments,
10881108
(int index, _SwiftFunctionArgument argument) {
10891109
return argument.label ?? _getArgumentName(index, argument.namedType);

0 commit comments

Comments
 (0)