@@ -172,6 +172,23 @@ enum FfiTypeCheckDirection {
172
172
dartToNative,
173
173
}
174
174
175
+ /// Converting mode of `Handle` in [convertNativeTypeToDartType] .
176
+ enum HandleToDartTypeConversionMode {
177
+ /// The variance-based conversion mode, where `Handle` is converted to
178
+ /// `Never` if it appears in covariant positions of the type being converted,
179
+ /// or to `Object?` when it appears in contravariant positions of the type.
180
+ /// This mode is used when the type being converted appears as the subtype of
181
+ /// a type check.
182
+ varianceBasedBehaviorForSubtype,
183
+
184
+ /// The variance-based conversion mode, where `Handle` is converted to
185
+ /// `Object?` if it appears in covariant positions of the type being
186
+ /// converted, or to `Never` when it appears in contravariant positions of
187
+ /// the type. This mode is used when the type being converted appears as the
188
+ /// supertype of a type check.
189
+ varianceBasedBehaviorForSupertype,
190
+ }
191
+
175
192
/// [FfiTransformer] contains logic which is shared between
176
193
/// _FfiUseSiteTransformer and _FfiDefinitionTransformer.
177
194
class FfiTransformer extends Transformer {
@@ -1080,16 +1097,38 @@ class FfiTransformer extends Transformer {
1080
1097
/// [Pointer]<T> -> [Pointer]<T>
1081
1098
/// T extends [Struct] -> T
1082
1099
/// T extends [Union] -> T
1083
- /// [Handle] -> [Object]
1100
+ /// [Handle] -> [Object?]|[Never ]
1084
1101
/// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
1085
1102
/// where DartRepresentationOf(Tn) -> Sn
1086
1103
/// ```
1104
+ ///
1105
+ /// If [mode] is [HandleToDartTypeConversionMode.oldNativeBehavior] , `Handle`
1106
+ /// is converted to `Object?` . Otherwise, `Handle` is converted to either
1107
+ /// `Object?` or `Never` . Since `Handle` represents any possible Dart object,
1108
+ /// it should match any type. To achieve that, in the subtype checks where
1109
+ /// `Handle` appears as the subtype (as indicated by [mode] being
1110
+ /// [HandleToDartTypeConversionMode.varianceBasedBehaviorForSubtype] ), it
1111
+ /// should be converted depending on the variance of its position: `Never` for
1112
+ /// covariant positions, and `Object?` for contravariant ones. If `Handle`
1113
+ /// appears as the supertype in the check (as indicated by [mode] being
1114
+ /// [HandleToDartTypeConversionMode.varianceBasedBehaviorForSupertype] ), the
1115
+ /// treatment of covariant and contravariant positions is reversed. For more
1116
+ /// details, see https://github.com/dart-lang/sdk/issues/49518.
1117
+ ///
1118
+ /// [isCovariant] is the flag that helps compute the variance of the position
1119
+ /// in [nativeType] . It's updated in the recursive invocations of
1120
+ /// [convertNativeTypeToDartType] and should be omitted in regular call sites.
1121
+ /// [isCovariant] is ignored if [mode] is
1122
+ /// [HandleToDartTypeConversionMode.oldNativeBehavior] .
1087
1123
DartType ? convertNativeTypeToDartType (
1088
1124
DartType nativeType, {
1089
1125
bool allowStructAndUnion = false ,
1090
1126
bool allowHandle = false ,
1091
1127
bool allowInlineArray = false ,
1092
1128
bool allowVoid = false ,
1129
+ HandleToDartTypeConversionMode mode =
1130
+ HandleToDartTypeConversionMode .varianceBasedBehaviorForSubtype,
1131
+ Variance variance = Variance .invariant,
1093
1132
}) {
1094
1133
if (nativeType is ! InterfaceType ) {
1095
1134
return null ;
@@ -1146,7 +1185,22 @@ class FfiTransformer extends Transformer {
1146
1185
return VoidType ();
1147
1186
}
1148
1187
if (nativeType_ == NativeType .kHandle && allowHandle) {
1149
- return coreTypes.objectNonNullableRawType;
1188
+ switch (mode) {
1189
+ case HandleToDartTypeConversionMode .varianceBasedBehaviorForSubtype:
1190
+ return switch (variance) {
1191
+ Variance .contravariant => coreTypes.objectNullableRawType,
1192
+ Variance .covariant ||
1193
+ Variance .invariant ||
1194
+ Variance .unrelated => const NeverType .nonNullable (),
1195
+ };
1196
+ case HandleToDartTypeConversionMode .varianceBasedBehaviorForSupertype:
1197
+ return switch (variance) {
1198
+ Variance .contravariant => const NeverType .nonNullable (),
1199
+ Variance .covariant ||
1200
+ Variance .invariant ||
1201
+ Variance .unrelated => coreTypes.objectNullableRawType,
1202
+ };
1203
+ }
1150
1204
}
1151
1205
if (nativeType_ != NativeType .kNativeFunction ||
1152
1206
native .typeArguments[0 ] is ! FunctionType ) {
@@ -1165,6 +1219,8 @@ class FfiTransformer extends Transformer {
1165
1219
allowStructAndUnion: true ,
1166
1220
allowHandle: true ,
1167
1221
allowVoid: true ,
1222
+ mode: mode,
1223
+ variance: variance,
1168
1224
);
1169
1225
if (returnType == null ) return null ;
1170
1226
final argumentTypes = < DartType > [];
@@ -1174,6 +1230,8 @@ class FfiTransformer extends Transformer {
1174
1230
paramDartType,
1175
1231
allowStructAndUnion: true ,
1176
1232
allowHandle: true ,
1233
+ mode: mode,
1234
+ variance: variance.combine (Variance .contravariant),
1177
1235
) ??
1178
1236
dummyDartType,
1179
1237
);
@@ -1856,17 +1914,21 @@ class FfiTransformer extends Transformer {
1856
1914
bool allowVoid = false ,
1857
1915
bool allowArray = false ,
1858
1916
}) {
1859
- final DartType correspondingDartType =
1860
- convertNativeTypeToDartType (
1861
- nativeType,
1862
- allowStructAndUnion: true ,
1863
- allowHandle: allowHandle,
1864
- allowInlineArray: allowArray,
1865
- allowVoid: allowVoid,
1866
- )! ;
1867
- if (dartType == correspondingDartType) return correspondingDartType;
1917
+ final DartType correspondingDartType;
1868
1918
switch (direction) {
1869
1919
case FfiTypeCheckDirection .nativeToDart:
1920
+ correspondingDartType =
1921
+ convertNativeTypeToDartType (
1922
+ nativeType,
1923
+ allowStructAndUnion: true ,
1924
+ allowHandle: allowHandle,
1925
+ allowInlineArray: allowArray,
1926
+ allowVoid: allowVoid,
1927
+ mode:
1928
+ HandleToDartTypeConversionMode
1929
+ .varianceBasedBehaviorForSubtype,
1930
+ variance: Variance .covariant ,
1931
+ )! ;
1870
1932
if (env.isSubtypeOf (
1871
1933
correspondingDartType,
1872
1934
dartType,
@@ -1888,6 +1950,18 @@ class FfiTransformer extends Transformer {
1888
1950
}
1889
1951
}
1890
1952
case FfiTypeCheckDirection .dartToNative:
1953
+ correspondingDartType =
1954
+ convertNativeTypeToDartType (
1955
+ nativeType,
1956
+ allowStructAndUnion: true ,
1957
+ allowHandle: allowHandle,
1958
+ allowInlineArray: allowArray,
1959
+ allowVoid: allowVoid,
1960
+ mode:
1961
+ HandleToDartTypeConversionMode
1962
+ .varianceBasedBehaviorForSupertype,
1963
+ variance: Variance .covariant ,
1964
+ )! ;
1891
1965
if (env.isSubtypeOf (
1892
1966
dartType,
1893
1967
correspondingDartType,
0 commit comments