Version 2.19.0-51.0.dev

Merge commit '48693c6b3df256eb082bc51e7b5856d23bd7ce4a' into 'dev'
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index 43b4217..920c786 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/error/ffi_code.dart';
 
@@ -341,6 +342,7 @@
       }
 
       var ffiParameterTypes = ffiSignature.normalParameterTypes;
+      var ffiParameters = ffiSignature.parameters;
 
       if (declarationElement is MethodElement && !declarationElement.isStatic) {
         // Instance methods must have the receiver as an extra parameter in the
@@ -366,6 +368,7 @@
         }
 
         ffiParameterTypes = ffiParameterTypes.sublist(1);
+        ffiParameters = ffiParameters.sublist(1);
       } else {
         // Number of parameters in the FfiNative annotation must match the
         // annotated declaration.
@@ -391,6 +394,27 @@
           }
         }
       }
+
+      final dartType = declarationElement.type;
+      final nativeType = FunctionTypeImpl(
+        typeFormals: ffiSignature.typeFormals,
+        parameters: ffiParameters,
+        returnType: ffiSignature.returnType,
+        nullabilitySuffix: ffiSignature.nullabilitySuffix,
+      );
+      if (!_isValidFfiNativeFunctionType(nativeType)) {
+        _errorReporter.reportErrorForNode(
+            FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE,
+            errorNode,
+            [nativeType, 'FfiNative']);
+        return;
+      }
+      if (!_validateCompatibleFunctionTypes(dartType, nativeType,
+          nativeFieldWrappersAsPointer: true, allowStricterReturn: true)) {
+        _errorReporter.reportErrorForNode(FfiCode.MUST_BE_A_SUBTYPE, errorNode,
+            [nativeType, dartType, 'FfiNative']);
+        return;
+      }
     }
   }
 
@@ -777,7 +801,11 @@
   /// Validates that the given [nativeType] is, when native types are converted
   /// to their Dart equivalent, a subtype of [dartType].
   bool _validateCompatibleFunctionTypes(
-      DartType dartType, DartType nativeType) {
+    DartType dartType,
+    DartType nativeType, {
+    bool nativeFieldWrappersAsPointer = false,
+    bool allowStricterReturn = false,
+  }) {
     // We require both to be valid function types.
     if (dartType is! FunctionType ||
         dartType.isDartCoreFunction ||
@@ -804,14 +832,26 @@
 
     // Validate that the return types are compatible.
     if (!_validateCompatibleNativeType(
-        dartType.returnType, nativeType.returnType, false)) {
-      return false;
+        dartType.returnType, nativeType.returnType)) {
+      // TODO(http://dartbug.com/49518): Fix inconsistency between `FfiNative`
+      // and `asFunction`.
+      if (!allowStricterReturn) {
+        return false;
+      } else if (!_validateCompatibleNativeType(
+          dartType.returnType, nativeType.returnType,
+          checkCovariance: true)) {
+        return false;
+      }
     }
 
     // Validate that the parameter types are compatible.
     for (int i = 0; i < parameterCount; ++i) {
-      if (!_validateCompatibleNativeType(dartType.normalParameterTypes[i],
-          nativeType.normalParameterTypes[i], true)) {
+      if (!_validateCompatibleNativeType(
+        dartType.normalParameterTypes[i],
+        nativeType.normalParameterTypes[i],
+        checkCovariance: true,
+        nativeFieldWrappersAsPointer: nativeFieldWrappersAsPointer,
+      )) {
         return false;
       }
     }
@@ -824,7 +864,11 @@
   /// [dartType] the latter is a subtype of the former if
   /// [checkCovariance].
   bool _validateCompatibleNativeType(
-      DartType dartType, DartType nativeType, bool checkCovariance) {
+    DartType dartType,
+    DartType nativeType, {
+    bool checkCovariance = false,
+    bool nativeFieldWrappersAsPointer = false,
+  }) {
     final nativeReturnType = _primitiveNativeType(nativeType);
     if (nativeReturnType == _PrimitiveDartType.int ||
         (nativeType is InterfaceType &&
@@ -837,12 +881,22 @@
       return dartType.isDartCoreBool;
     } else if (nativeReturnType == _PrimitiveDartType.void_) {
       return dartType.isVoid;
+    } else if (dartType.isVoid) {
+      // Don't allow other native subtypes if the Dart return type is void.
+      return nativeReturnType == _PrimitiveDartType.void_;
     } else if (nativeReturnType == _PrimitiveDartType.handle) {
       InterfaceType objectType = typeSystem.objectStar;
       return checkCovariance
           ? /* everything is subtype of objectStar */ true
           : typeSystem.isSubtypeOf(objectType, dartType);
     } else if (dartType is InterfaceType && nativeType is InterfaceType) {
+      if (nativeFieldWrappersAsPointer &&
+          _extendsNativeFieldWrapperClass1(dartType)) {
+        // Must be `Pointer<Void>`, `Handle` already checked above.
+        return nativeType.isPointer &&
+            _primitiveNativeType(nativeType.typeArguments.single) ==
+                _PrimitiveDartType.void_;
+      }
       return checkCovariance
           ? typeSystem.isSubtypeOf(dartType, nativeType)
           : typeSystem.isSubtypeOf(nativeType, dartType);
@@ -1015,7 +1069,7 @@
     } else {
       Expression e = node.argumentList.arguments[1];
       var eType = e.typeOrThrow;
-      if (!_validateCompatibleNativeType(eType, R, true)) {
+      if (!_validateCompatibleNativeType(eType, R, checkCovariance: true)) {
         _errorReporter.reportErrorForNode(
             FfiCode.MUST_BE_A_SUBTYPE, e, [eType, R, 'fromFunction']);
       }
diff --git a/pkg/analyzer/test/src/diagnostics/ffi_native_test.dart b/pkg/analyzer/test/src/diagnostics/ffi_native_test.dart
index 9b23e47..638d75f 100644
--- a/pkg/analyzer/test/src/diagnostics/ffi_native_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/ffi_native_test.dart
@@ -50,7 +50,7 @@
     await assertErrorsInCode(r'''
 import 'dart:ffi';
 @FfiNative<Int8 Function(Int64)>('DoesntMatter', isLeaf:true)
-external int doesntMatter(int);
+external int doesntMatter(int x);
 ''', []);
   }
 
@@ -87,6 +87,26 @@
     ]);
   }
 
+  test_FfiNativeNonFfiParameter() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+@FfiNative<IntPtr Function(int)>('doesntmatter')
+external int nonFfiParameter(int v);
+''', [
+      error(FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE, 19, 85),
+    ]);
+  }
+
+  test_FfiNativeNonFfiReturnType() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+@FfiNative<double Function(IntPtr)>('doesntmatter')
+external double nonFfiReturnType(int v);
+''', [
+      error(FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE, 19, 92),
+    ]);
+  }
+
   test_FfiNativeTooFewParameters() async {
     await assertErrorsInCode(r'''
 import 'dart:ffi';
@@ -106,4 +126,34 @@
       error(FfiCode.FFI_NATIVE_UNEXPECTED_NUMBER_OF_PARAMETERS, 19, 95),
     ]);
   }
+
+  test_FfiNativeVoidReturn() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+@FfiNative<Handle Function(Uint32, Uint32, Handle)>('doesntmatter')
+external void voidReturn(int width, int height, Object outImage);
+''', [
+      error(FfiCode.MUST_BE_A_SUBTYPE, 19, 133),
+    ]);
+  }
+
+  test_FfiNativeWrongFfiParameter() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+@FfiNative<IntPtr Function(Double)>('doesntmatter')
+external int wrongFfiParameter(int v);
+''', [
+      error(FfiCode.MUST_BE_A_SUBTYPE, 19, 90),
+    ]);
+  }
+
+  test_FfiNativeWrongFfiReturnType() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+@FfiNative<IntPtr Function(IntPtr)>('doesntmatter')
+external double wrongFfiReturnType(int v);
+''', [
+      error(FfiCode.MUST_BE_A_SUBTYPE, 19, 94),
+    ]);
+  }
 }
diff --git a/tests/ffi/vmspecific_static_checks_ffinative_test.dart b/tests/ffi/vmspecific_static_checks_ffinative_test.dart
index 24bd3d4..72549f7 100644
--- a/tests/ffi/vmspecific_static_checks_ffinative_test.dart
+++ b/tests/ffi/vmspecific_static_checks_ffinative_test.dart
@@ -80,18 +80,14 @@
 @FfiNative<Void Function({Double})>('doesntmatter') //# 13: compile-time error
 external static int badNamedParam(); //# 13: compile-time error
 
-// TODO(https://dartbug.com/49412): Implement in analyzer.
 @FfiNative<IntPtr Function(Double)>('doesntmatter') //# 14: compile-time error
 external int wrongFfiParameter(int v); //# 14: compile-time error
 
-// TODO(https://dartbug.com/49412): Implement in analyzer.
 @FfiNative<IntPtr Function(IntPtr)>('doesntmatter') //# 15: compile-time error
 external double wrongFfiReturnType(int v); //# 15: compile-time error
 
-// TODO(https://dartbug.com/49412): Implement in analyzer.
-@FfiNative<int Function(Double)>('doesntmatter') //# 16: compile-time error
+@FfiNative<IntPtr Function(int)>('doesntmatter') //# 16: compile-time error
 external int nonFfiParameter(int v); //# 16: compile-time error
 
-// TODO(https://dartbug.com/49412): Implement in analyzer.
 @FfiNative<double Function(IntPtr)>('doesntmatter') //# 17: compile-time error
 external double nonFfiReturnType(int v); //# 17: compile-time error
diff --git a/tools/VERSION b/tools/VERSION
index dc85efc..6265d32 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 19
 PATCH 0
-PRERELEASE 50
+PRERELEASE 51
 PRERELEASE_PATCH 0
\ No newline at end of file