@@ -26,14 +26,6 @@ namespace dart {
2626// Some checks are only performed at runtime to allow for generic code, these
2727// throw ArgumentExceptions.
2828
29- static void ThrowTypeArgumentError (const AbstractType& type_arg,
30- const char * expected) {
31- const String& error = String::Handle (String::NewFormatted (
32- " Type argument (%s) should be a %s" ,
33- String::Handle (type_arg.UserVisibleName ()).ToCString (), expected));
34- Exceptions::ThrowArgumentError (error);
35- }
36-
3729static bool IsPointerType (const AbstractType& type) {
3830 // Do a fast check for predefined types.
3931 classid_t type_cid = type.type_class_id ();
@@ -54,38 +46,15 @@ static bool IsPointerType(const AbstractType& type) {
5446 return type.IsSubtypeOf (pointer_type, Heap::kNew );
5547}
5648
57- static bool IsConcreteNativeType (const AbstractType& type) {
58- // Do a fast check for predefined types.
59- classid_t type_cid = type.type_class_id ();
60- if (RawObject::IsFfiNativeTypeTypeClassId (type_cid)) {
61- return false ;
62- }
63- if (RawObject::IsFfiTypeClassId (type_cid)) {
64- return true ;
65- }
66-
67- // Do a slow check for subtyping.
68- const Class& native_type_class = Class::Handle (
69- Isolate::Current ()->object_store ()->ffi_native_type_class ());
70- AbstractType& native_type_type =
71- AbstractType::Handle (native_type_class.DeclarationType ());
72- return type.IsSubtypeOf (native_type_type, Heap::kNew );
73- }
74-
75- static void CheckIsConcreteNativeType (const AbstractType& type) {
76- if (!IsConcreteNativeType (type)) {
77- ThrowTypeArgumentError (type, " concrete sub type of NativeType" );
78- }
79- }
80-
8149static bool IsNativeFunction (const AbstractType& type_arg) {
8250 classid_t type_cid = type_arg.type_class_id ();
8351 return RawObject::IsFfiTypeNativeFunctionClassId (type_cid);
8452}
8553
8654static void CheckSized (const AbstractType& type_arg) {
87- classid_t type_cid = type_arg.type_class_id ();
88- if (RawObject::IsFfiTypeVoidClassId (type_cid) ||
55+ const classid_t type_cid = type_arg.type_class_id ();
56+ if (RawObject::IsFfiNativeTypeTypeClassId (type_cid) ||
57+ RawObject::IsFfiTypeVoidClassId (type_cid) ||
8958 RawObject::IsFfiTypeNativeFunctionClassId (type_cid)) {
9059 const String& error = String::Handle (String::NewFormatted (
9160 " %s does not have a predefined size (@unsized). "
@@ -98,6 +67,8 @@ static void CheckSized(const AbstractType& type_arg) {
9867 }
9968}
10069
70+ enum class FfiVariance { kInvariant = 0 , kCovariant = 1 , kContravariant = 2 };
71+
10172// Checks that a dart type correspond to a [NativeType].
10273// Because this is checked already in a kernel transformation, it does not throw
10374// an ArgumentException but a boolean which should be asserted.
@@ -118,7 +89,8 @@ static void CheckSized(const AbstractType& type_arg) {
11889// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
11990// where DartRepresentationOf(Tn) -> Sn
12091static bool DartAndCTypeCorrespond (const AbstractType& native_type,
121- const AbstractType& dart_type) {
92+ const AbstractType& dart_type,
93+ FfiVariance variance) {
12294 classid_t native_type_cid = native_type.type_class_id ();
12395 if (RawObject::IsFfiTypeIntClassId (native_type_cid)) {
12496 return dart_type.IsSubtypeOf (AbstractType::Handle (Type::IntType ()),
@@ -129,7 +101,13 @@ static bool DartAndCTypeCorrespond(const AbstractType& native_type,
129101 Heap::kNew );
130102 }
131103 if (RawObject::IsFfiPointerClassId (native_type_cid)) {
132- return native_type.Equals (dart_type) || dart_type.IsNullType ();
104+ return (variance == FfiVariance::kInvariant &&
105+ dart_type.Equals (native_type)) ||
106+ (variance == FfiVariance::kCovariant &&
107+ dart_type.IsSubtypeOf (native_type, Heap::kNew )) ||
108+ (variance == FfiVariance::kContravariant &&
109+ native_type.IsSubtypeOf (dart_type, Heap::kNew )) ||
110+ dart_type.IsNullType ();
133111 }
134112 if (RawObject::IsFfiTypeNativeFunctionClassId (native_type_cid)) {
135113 if (!dart_type.IsFunctionType ()) {
@@ -161,20 +139,34 @@ static bool DartAndCTypeCorrespond(const AbstractType& native_type,
161139 }
162140 if (!DartAndCTypeCorrespond (
163141 AbstractType::Handle (nativefunction_function.result_type ()),
164- AbstractType::Handle (dart_function.result_type ()))) {
142+ AbstractType::Handle (dart_function.result_type ()), variance )) {
165143 return false ;
166144 }
167145 for (intptr_t i = 0 ; i < dart_function.NumParameters (); i++) {
168146 if (!DartAndCTypeCorrespond (
169147 AbstractType::Handle (nativefunction_function.ParameterTypeAt (i)),
170- AbstractType::Handle (dart_function.ParameterTypeAt (i)))) {
148+ AbstractType::Handle (dart_function.ParameterTypeAt (i)),
149+ variance)) {
171150 return false ;
172151 }
173152 }
174153 }
175154 return true ;
176155}
177156
157+ static void CheckDartAndCTypeCorrespond (const AbstractType& native_type,
158+ const AbstractType& dart_type,
159+ FfiVariance variance) {
160+ if (!DartAndCTypeCorrespond (native_type, dart_type, variance)) {
161+ const String& error = String::Handle (String::NewFormatted (
162+ " Expected type '%s' to be different, it should be "
163+ " DartRepresentationOf('%s')." ,
164+ String::Handle (dart_type.UserVisibleName ()).ToCString (),
165+ String::Handle (native_type.UserVisibleName ()).ToCString ()));
166+ Exceptions::ThrowArgumentError (error);
167+ }
168+ }
169+
178170// The following functions are runtime checks on arguments.
179171
180172// Note that expected_from and expected_to are inclusive.
@@ -224,7 +216,6 @@ DEFINE_NATIVE_ENTRY(Ffi_allocate, 1, 1) {
224216 // Pointer. https://github.com/dart-lang/sdk/issues/35782
225217 GET_NATIVE_TYPE_ARGUMENT (type_arg, arguments->NativeTypeArgAt (0 ));
226218
227- CheckIsConcreteNativeType (type_arg);
228219 CheckSized (type_arg);
229220
230221 GET_NON_NULL_NATIVE_ARGUMENT (Integer, argCount, arguments->NativeArgAt (0 ));
@@ -251,7 +242,6 @@ DEFINE_NATIVE_ENTRY(Ffi_fromAddress, 1, 1) {
251242 TypeArguments& type_args = TypeArguments::Handle (type_arg.arguments ());
252243 AbstractType& native_type = AbstractType::Handle (
253244 type_args.TypeAtNullSafe (Pointer::kNativeTypeArgPos ));
254- CheckIsConcreteNativeType (native_type);
255245 GET_NON_NULL_NATIVE_ARGUMENT (Integer, arg_ptr, arguments->NativeArgAt (0 ));
256246
257247 // TODO(dacoharkes): should this return NULL if address is 0?
@@ -298,7 +288,6 @@ DEFINE_NATIVE_ENTRY(Ffi_cast, 1, 1) {
298288 TypeArguments& type_args = TypeArguments::Handle (type_arg.arguments ());
299289 AbstractType& native_type = AbstractType::Handle (
300290 type_args.TypeAtNullSafe (Pointer::kNativeTypeArgPos ));
301- CheckIsConcreteNativeType (native_type);
302291
303292 const Integer& address = Integer::Handle (zone, pointer.GetCMemoryAddress ());
304293 RawPointer* result =
@@ -379,7 +368,8 @@ DEFINE_NATIVE_ENTRY(Ffi_load, 1, 1) {
379368 AbstractType& pointer_type_arg =
380369 AbstractType::Handle (pointer.type_argument ());
381370 CheckSized (pointer_type_arg);
382- ASSERT (DartAndCTypeCorrespond (pointer_type_arg, type_arg));
371+ CheckDartAndCTypeCorrespond (pointer_type_arg, type_arg,
372+ FfiVariance::kContravariant );
383373
384374 uint8_t * address = reinterpret_cast <uint8_t *>(
385375 Integer::Handle (pointer.GetCMemoryAddress ()).AsInt64Value ());
@@ -460,7 +450,8 @@ DEFINE_NATIVE_ENTRY(Ffi_store, 0, 2) {
460450 AbstractType& pointer_type_arg =
461451 AbstractType::Handle (pointer.type_argument ());
462452 CheckSized (pointer_type_arg);
463- ASSERT (DartAndCTypeCorrespond (pointer_type_arg, arg_type));
453+ CheckDartAndCTypeCorrespond (pointer_type_arg, arg_type,
454+ FfiVariance::kCovariant );
464455
465456 classid_t type_cid = pointer_type_arg.type_class_id ();
466457 StoreValue (zone, pointer, type_cid, new_value);
@@ -469,7 +460,6 @@ DEFINE_NATIVE_ENTRY(Ffi_store, 0, 2) {
469460
470461DEFINE_NATIVE_ENTRY (Ffi_sizeOf, 1 , 0 ) {
471462 GET_NATIVE_TYPE_ARGUMENT (type_arg, arguments->NativeTypeArgAt (0 ));
472- CheckIsConcreteNativeType (type_arg);
473463 CheckSized (type_arg);
474464
475465 classid_t type_cid = type_arg.type_class_id ();
@@ -523,7 +513,8 @@ DEFINE_NATIVE_ENTRY(Ffi_asFunction, 1, 1) {
523513 AbstractType::Handle (pointer.type_argument ());
524514 ASSERT (IsNativeFunction (pointer_type_arg));
525515 GET_NATIVE_TYPE_ARGUMENT (type_arg, arguments->NativeTypeArgAt (0 ));
526- ASSERT (DartAndCTypeCorrespond (pointer_type_arg, type_arg));
516+ CheckDartAndCTypeCorrespond (pointer_type_arg, type_arg,
517+ FfiVariance::kInvariant );
527518
528519 Function& dart_signature = Function::Handle (Type::Cast (type_arg).signature ());
529520 TypeArguments& nativefunction_type_args =
0 commit comments