Skip to content

Commit ab364ca

Browse files
Yusufihsangorgeldart-scoped@luci-project-accounts.iam.gserviceaccount.com
authored andcommitted
[analyzer/ffi] Handle NativeCallable arguments independently of source order
Closes #63871 GitOrigin-RevId: 5aa023a Change-Id: Ic1c13632654588ad3f8c459a51623958ee4dba80 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/526980 Reviewed-by: Daco Harkes <dacoharkes@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
1 parent c561da2 commit ab364ca

2 files changed

Lines changed: 116 additions & 6 deletions

File tree

pkg/analyzer/lib/src/generated/ffi_verifier.dart

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,7 +1937,24 @@ class FfiVerifier extends RecursiveAstVisitor2<void> {
19371937
return;
19381938
}
19391939

1940-
var f = node.argumentList.arguments2[0];
1940+
ArgumentImpl? f;
1941+
NamedArgumentImpl? exceptionalReturn;
1942+
for (var argument in node.argumentList.arguments2) {
1943+
if (argument is NamedArgumentImpl) {
1944+
exceptionalReturn = argument;
1945+
} else if (f == null) {
1946+
f = argument;
1947+
} else {
1948+
// There are other diagnostics reported against the invocation and the
1949+
// diagnostics generated below might be inaccurate, so don't report
1950+
// them.
1951+
return;
1952+
}
1953+
}
1954+
if (f == null) {
1955+
return;
1956+
}
1957+
19411958
var funcType = f.argumentExpression2.typeOrThrow;
19421959
if (!_validateCompatibleFunctionTypes(
19431960
_FfiTypeCheckDirection.dartToNative,
@@ -1962,20 +1979,19 @@ class FfiVerifier extends RecursiveAstVisitor2<void> {
19621979
natRetType.isPointer ||
19631980
natRetType.isHandle ||
19641981
natRetType.isCompoundSubtype) {
1965-
if (argCount != 1) {
1982+
if (exceptionalReturn != null) {
19661983
_diagnosticReporter.report(
19671984
diag.invalidExceptionValue
19681985
.withArguments(methodName: name)
1969-
.at(node.argumentList.arguments2[1]),
1986+
.at(exceptionalReturn),
19701987
);
19711988
}
1972-
} else if (argCount != 2) {
1989+
} else if (exceptionalReturn == null) {
19731990
_diagnosticReporter.report(
19741991
diag.missingExceptionValue.withArguments(methodName: name).at(node),
19751992
);
19761993
} else {
1977-
var e = (node.argumentList.arguments2[1] as NamedArgument)
1978-
.argumentExpression2;
1994+
var e = exceptionalReturn.argumentExpression2;
19791995
var eType = e.typeOrThrow;
19801996
if (!_validateCompatibleNativeType(
19811997
_FfiTypeCheckDirection.dartToNative,

pkg/analyzer/test/src/diagnostics/ffi_async_callback_test.dart

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ void g() {
2828
''');
2929
}
3030

31+
test_NativeCallable_isolateLocal_argumentMustBeAConstant_namedFirst() async {
32+
await resolveTestCodeWithDiagnostics(r'''
33+
import 'dart:ffi';
34+
int f(int i) => i * 2;
35+
void g() {
36+
int e = 123;
37+
NativeCallable<Int32 Function(Int32)>.isolateLocal(exceptionalReturn: e, f);
38+
// ^
39+
// [diag.argumentMustBeAConstant] Argument 'exceptionalReturn' must be a constant.
40+
}
41+
''');
42+
}
43+
3144
test_NativeCallable_isolateLocal_exceptionMustBeASubtype() async {
3245
await resolveTestCodeWithDiagnostics(r'''
3346
import 'dart:ffi';
@@ -40,6 +53,18 @@ void g() {
4053
''');
4154
}
4255

56+
test_NativeCallable_isolateLocal_exceptionMustBeASubtype_namedFirst() async {
57+
await resolveTestCodeWithDiagnostics(r'''
58+
import 'dart:ffi';
59+
int f(int i) => i * 2;
60+
void g() {
61+
NativeCallable<Int32 Function(Int32)>.isolateLocal(exceptionalReturn: '?', f);
62+
// ^^^
63+
// [diag.mustBeASubtype] The type 'String' must be a subtype of 'Int32' for 'isolateLocal'.
64+
}
65+
''');
66+
}
67+
4368
test_NativeCallable_isolateLocal_inferred() async {
4469
await resolveTestCodeWithDiagnostics(r'''
4570
import 'dart:ffi';
@@ -64,6 +89,29 @@ void g() {
6489
''');
6590
}
6691

92+
test_NativeCallable_isolateLocal_invalidExceptionValue_namedFirst() async {
93+
await resolveTestCodeWithDiagnostics(r'''
94+
import 'dart:ffi';
95+
void f(int i) => i * 2;
96+
void g() {
97+
NativeCallable<Void Function(Int32)>.isolateLocal(exceptionalReturn: 4, f);
98+
// ^^^^^^^^^^^^^^^^^^^^
99+
// [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'.
100+
}
101+
''');
102+
}
103+
104+
test_NativeCallable_isolateLocal_missingCallback() async {
105+
await resolveTestCodeWithDiagnostics(r'''
106+
import 'dart:ffi';
107+
void g() {
108+
NativeCallable<Int32 Function(Int32)>.isolateLocal(exceptionalReturn: 0);
109+
// ^^^^^^^^^^^^^^^^^
110+
// [diag.notEnoughPositionalArgumentsNameSingular] 1 positional argument expected by 'isolateLocal', but 0 found.
111+
}
112+
''');
113+
}
114+
67115
test_NativeCallable_isolateLocal_missingExceptionValue() async {
68116
await resolveTestCodeWithDiagnostics(r'''
69117
import 'dart:ffi';
@@ -100,6 +148,18 @@ void g() {
100148
''');
101149
}
102150

151+
test_NativeCallable_isolateLocal_mustBeASubtype_namedFirst() async {
152+
await resolveTestCodeWithDiagnostics(r'''
153+
import 'dart:ffi';
154+
int f(int i) => i * 2;
155+
void g() {
156+
NativeCallable<Int32 Function(Double)>.isolateLocal(exceptionalReturn: 4, f);
157+
// ^
158+
// [diag.mustBeASubtype] The type 'int Function(int)' must be a subtype of 'Int32 Function(Double)' for 'NativeCallable'.
159+
}
160+
''');
161+
}
162+
103163
test_NativeCallable_isolateLocal_mustHaveTypeArgs() async {
104164
await resolveTestCodeWithDiagnostics(r'''
105165
import 'dart:ffi';
@@ -122,6 +182,16 @@ void g() {
122182
''');
123183
}
124184

185+
test_NativeCallable_isolateLocal_ok_namedFirst() async {
186+
await resolveTestCodeWithDiagnostics(r'''
187+
import 'dart:ffi';
188+
int f(int i) => i * 2;
189+
void g() {
190+
NativeCallable<Int32 Function(Int32)>.isolateLocal(exceptionalReturn: 4, f);
191+
}
192+
''');
193+
}
194+
125195
test_NativeCallable_isolateLocal_okVoid() async {
126196
await resolveTestCodeWithDiagnostics(r'''
127197
import 'dart:ffi';
@@ -132,6 +202,30 @@ void g() {
132202
''');
133203
}
134204

205+
test_NativeCallable_isolateLocal_positionalExceptionalReturn() async {
206+
await resolveTestCodeWithDiagnostics(r'''
207+
import 'dart:ffi';
208+
int f(int i) => i * 2;
209+
void g() {
210+
NativeCallable<Int32 Function(Int32)>.isolateLocal(f, 0);
211+
// ^
212+
// [diag.extraPositionalArgumentsCouldBeNamed] Too many positional arguments: 1 expected, but 2 found.
213+
}
214+
''');
215+
}
216+
217+
test_NativeCallable_isolateLocal_positionalExceptionalReturn_void() async {
218+
await resolveTestCodeWithDiagnostics(r'''
219+
import 'dart:ffi';
220+
void f(int i) => i * 2;
221+
void g() {
222+
NativeCallable<Void Function(Int32)>.isolateLocal(f, 0);
223+
// ^
224+
// [diag.extraPositionalArgumentsCouldBeNamed] Too many positional arguments: 1 expected, but 2 found.
225+
}
226+
''');
227+
}
228+
135229
test_NativeCallable_isolateLocal_voidReturnPermissive() async {
136230
await resolveTestCodeWithDiagnostics(r'''
137231
import 'dart:ffi';

0 commit comments

Comments
 (0)