| // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; | |
| import '../dart/resolution/context_collection_resolution.dart'; | |
| main() { | |
| defineReflectiveSuite(() { | |
| defineReflectiveTests(FfiNativeCallableListenersMustReturnVoid); | |
| }); | |
| } | |
| @reflectiveTest | |
| class FfiNativeCallableListenersMustReturnVoid | |
| extends PubPackageResolutionTest { | |
| test_NativeCallable_isolateLocal_argumentMustBeAConstant() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| int e = 123; | |
| NativeCallable<Int32 Function(Int32)>.isolateLocal(f, exceptionalReturn: e); | |
| // ^ | |
| // [diag.argumentMustBeAConstant] Argument 'exceptionalReturn' must be a constant. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_argumentMustBeAConstant_namedFirst() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| int e = 123; | |
| NativeCallable<Int32 Function(Int32)>.isolateLocal(exceptionalReturn: e, f); | |
| // ^ | |
| // [diag.argumentMustBeAConstant] Argument 'exceptionalReturn' must be a constant. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_exceptionMustBeASubtype() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Int32 Function(Int32)>.isolateLocal(f, exceptionalReturn: '?'); | |
| // ^^^ | |
| // [diag.mustBeASubtype] The type 'String' must be a subtype of 'Int32' for 'isolateLocal'. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_exceptionMustBeASubtype_namedFirst() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Int32 Function(Int32)>.isolateLocal(exceptionalReturn: '?', f); | |
| // ^^^ | |
| // [diag.mustBeASubtype] The type 'String' must be a subtype of 'Int32' for 'isolateLocal'. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_inferred() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Int32 Function(Int32)>? callback; | |
| callback = NativeCallable.isolateLocal(f, exceptionalReturn: 4); | |
| callback.close(); | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_invalidExceptionValue() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| void f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Void Function(Int32)>.isolateLocal(f, exceptionalReturn: 4); | |
| // ^^^^^^^^^^^^^^^^^^^^ | |
| // [diag.invalidExceptionValue] The method isolateLocal can't have an exceptional return value (the second argument) when the return type of the function is either 'void', 'Handle' or 'Pointer'. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_invalidExceptionValue_namedFirst() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| void f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Void Function(Int32)>.isolateLocal(exceptionalReturn: 4, f); | |
| // ^^^^^^^^^^^^^^^^^^^^ | |
| // [diag.invalidExceptionValue] The method isolateLocal can't have an exceptional return value (the second argument) when the return type of the function is either 'void', 'Handle' or 'Pointer'. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_missingCallback() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| void g() { | |
| NativeCallable<Int32 Function(Int32)>.isolateLocal(exceptionalReturn: 0); | |
| // ^^^^^^^^^^^^^^^^^ | |
| // [diag.notEnoughPositionalArgumentsNameSingular] 1 positional argument expected by 'isolateLocal', but 0 found. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_missingExceptionValue() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Int32 Function(Int32)>.isolateLocal(f); | |
| //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| // [diag.missingExceptionValue] The method isolateLocal must have an exceptional return value (the second argument) when the return type of the function is neither 'void', 'Handle', nor 'Pointer'. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_mustBeANativeFunctionType() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<int Function(int)>.isolateLocal(f, exceptionalReturn: 4); | |
| //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| // [diag.mustBeANativeFunctionType] The type 'int Function(int)' given to 'NativeCallable' must be a valid 'dart:ffi' native function type. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_mustBeASubtype() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Int32 Function(Double)>.isolateLocal(f, exceptionalReturn: 4); | |
| // ^ | |
| // [diag.mustBeASubtype] The type 'int Function(int)' must be a subtype of 'Int32 Function(Double)' for 'NativeCallable'. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_mustBeASubtype_namedFirst() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Int32 Function(Double)>.isolateLocal(exceptionalReturn: 4, f); | |
| // ^ | |
| // [diag.mustBeASubtype] The type 'int Function(int)' must be a subtype of 'Int32 Function(Double)' for 'NativeCallable'. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_mustHaveTypeArgs() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable.isolateLocal(f, exceptionalReturn: 4); | |
| //^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| // [diag.mustBeANativeFunctionType] The type 'Function' given to 'NativeCallable' must be a valid 'dart:ffi' native function type. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_ok() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Int32 Function(Int32)>.isolateLocal(f, exceptionalReturn: 4); | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_ok_namedFirst() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Int32 Function(Int32)>.isolateLocal(exceptionalReturn: 4, f); | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_okVoid() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| void f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Void Function(Int32)>.isolateLocal(f); | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_positionalExceptionalReturn() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Int32 Function(Int32)>.isolateLocal(f, 0); | |
| // ^ | |
| // [diag.extraPositionalArgumentsCouldBeNamed] Too many positional arguments: 1 expected, but 2 found. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_positionalExceptionalReturn_void() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| void f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Void Function(Int32)>.isolateLocal(f, 0); | |
| // ^ | |
| // [diag.extraPositionalArgumentsCouldBeNamed] Too many positional arguments: 1 expected, but 2 found. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_isolateLocal_voidReturnPermissive() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Void Function(Int32)>.isolateLocal(f); | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_listener_inferred() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| void f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Void Function(Int32)>? callback; | |
| callback = NativeCallable.listener(f); | |
| callback.close(); | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_listener_mustBeANativeFunctionType() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| void f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<void Function(int)>.listener(f); | |
| //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| // [diag.mustBeANativeFunctionType] The type 'void Function(int)' given to 'NativeCallable' must be a valid 'dart:ffi' native function type. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_listener_mustBeASubtype() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| void f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Void Function(Double)>.listener(f); | |
| // ^ | |
| // [diag.mustBeASubtype] The type 'void Function(int)' must be a subtype of 'Void Function(Double)' for 'NativeCallable'. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_listener_mustHaveTypeArgs() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable.listener(f); | |
| //^^^^^^^^^^^^^^^^^^^^^^^ | |
| // [diag.mustBeANativeFunctionType] The type 'Function' given to 'NativeCallable' must be a valid 'dart:ffi' native function type. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_listener_mustReturnVoid() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Int32 Function(Int32)>.listener(f); | |
| // ^ | |
| // [diag.mustReturnVoid] The return type of the function passed to 'NativeCallable.listener' must be 'void' rather than 'Int32'. | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_listener_ok() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| void f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Void Function(Int32)>.listener(f); | |
| } | |
| '''); | |
| } | |
| test_NativeCallable_listener_voidReturnPermissive() async { | |
| await resolveTestCodeWithDiagnostics(r''' | |
| import 'dart:ffi'; | |
| int f(int i) => i * 2; | |
| void g() { | |
| NativeCallable<Void Function(Int32)>.listener(f); | |
| } | |
| '''); | |
| } | |
| } |