Skip to content

Commit 4bc01d4

Browse files
liamappelbeCommit Queue
authored andcommitted
[ffi] Support non-trivial const expressions in exceptional returns
Bug: #54417 Change-Id: Iddafe896f7c070b7ef4205347b4b454febbd164a Fixes: #54417 TEST=tests/ffi/exceptional_return_const_test.dart for the new behavior TEST=tests/ffi/vmspecific_static_checks_test.dart tests that the existing error messages still work. Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/397220 Commit-Queue: Liam Appelbe <[email protected]> Reviewed-by: Daco Harkes <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent 7b76a0d commit 4bc01d4

File tree

9 files changed

+195
-44
lines changed

9 files changed

+195
-44
lines changed

pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,8 @@ class LibraryAnalyzer {
486486
FfiVerifier(
487487
_typeSystem,
488488
diagnosticReporter,
489+
_libraryElement,
490+
_declaredVariables,
489491
strictCasts: _analysisOptions.strictCasts,
490492
),
491493
);

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

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analyzer/dart/analysis/declared_variables.dart';
56
import 'package:analyzer/dart/ast/syntactic_entity.dart';
67
import 'package:analyzer/dart/ast/token.dart';
78
import 'package:analyzer/dart/ast/visitor.dart';
@@ -12,6 +13,8 @@ import 'package:analyzer/dart/element/type.dart';
1213
import 'package:analyzer/error/listener.dart';
1314
import 'package:analyzer/src/dart/ast/ast.dart';
1415
import 'package:analyzer/src/dart/ast/extensions.dart';
16+
import 'package:analyzer/src/dart/constant/evaluation.dart';
17+
import 'package:analyzer/src/dart/constant/value.dart';
1518
import 'package:analyzer/src/dart/element/element.dart';
1619
import 'package:analyzer/src/dart/element/type.dart';
1720
import 'package:analyzer/src/dart/element/type_system.dart';
@@ -106,15 +109,24 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
106109
/// Subclass of `Struct` or `Union` we are currently visiting, or `null`.
107110
ClassDeclaration? compound;
108111

112+
final LibraryElementImpl _currentLibrary;
113+
114+
final ConstantEvaluationEngine _evaluationEngine;
115+
109116
/// The `Void` type from `dart:ffi`, or `null` if unresolved.
110117
InterfaceTypeImpl? ffiVoidType;
111118

112119
/// Initialize a newly created verifier.
113120
FfiVerifier(
114121
this.typeSystem,
115-
this._diagnosticReporter, {
122+
this._diagnosticReporter,
123+
this._currentLibrary,
124+
DeclaredVariables declaredVariables, {
116125
required this.strictCasts,
117-
});
126+
}) : _evaluationEngine = ConstantEvaluationEngine(
127+
declaredVariables: declaredVariables,
128+
configuration: ConstantEvaluationConfiguration(),
129+
);
118130

119131
@override
120132
void visitClassDeclaration(covariant ClassDeclarationImpl node) {
@@ -744,21 +756,17 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
744756
}
745757

746758
bool _isConst(Expression expr) {
747-
if (expr is Literal) {
748-
return true;
749-
}
750-
if (expr is Identifier) {
751-
var element = expr.element;
752-
if (element is VariableElement && element.isConst) {
753-
return true;
754-
}
755-
if (element is PropertyAccessorElement) {
756-
if (element.variable.isConst) {
757-
return true;
758-
}
759-
}
760-
}
761-
return false;
759+
var subDiagnosticReporter = DiagnosticReporter(
760+
RecordingDiagnosticListener(),
761+
_diagnosticReporter.source,
762+
);
763+
var constantVisitor = ConstantVisitor(
764+
_evaluationEngine,
765+
_currentLibrary,
766+
subDiagnosticReporter,
767+
);
768+
var result = constantVisitor.evaluateConstant(expr);
769+
return result is! InvalidConstant;
762770
}
763771

764772
bool _isLeaf(NodeList<Expression>? args) {

pkg/dart2wasm/lib/target.dart

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -340,24 +340,34 @@ class WasmTarget extends Target {
340340
logger?.call("Skipped ffi transformation");
341341
} else {
342342
wasmFfiNativeAddressTrans.transformLibraries(
343-
component,
344-
coreTypes,
345-
hierarchy,
346-
transitiveImportingDartFfi,
347-
diagnosticReporter,
348-
referenceFromIndex);
343+
component,
344+
coreTypes,
345+
hierarchy,
346+
transitiveImportingDartFfi,
347+
diagnosticReporter,
348+
referenceFromIndex,
349+
);
349350
wasmFfiNativeTrans.transformLibraries(component, coreTypes, hierarchy,
350351
transitiveImportingDartFfi, diagnosticReporter, referenceFromIndex);
351352
transformFfiDefinitions.transformLibraries(
352-
component,
353-
coreTypes,
354-
hierarchy,
355-
transitiveImportingDartFfi,
356-
diagnosticReporter,
357-
referenceFromIndex,
358-
changedStructureNotifier);
359-
transformFfiUseSites.transformLibraries(component, coreTypes, hierarchy,
360-
transitiveImportingDartFfi, diagnosticReporter, referenceFromIndex);
353+
component,
354+
coreTypes,
355+
hierarchy,
356+
transitiveImportingDartFfi,
357+
diagnosticReporter,
358+
referenceFromIndex,
359+
changedStructureNotifier,
360+
);
361+
transformFfiUseSites.transformLibraries(
362+
this,
363+
component,
364+
coreTypes,
365+
hierarchy,
366+
transitiveImportingDartFfi,
367+
diagnosticReporter,
368+
referenceFromIndex,
369+
environmentDefines,
370+
);
361371
logger?.call("Transformed ffi annotations");
362372
}
363373

pkg/vm/lib/modular/target/vm.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,14 @@ class VmTarget extends Target {
217217
// VM pragma attached to valid targets in the native transformer. Hence,
218218
// it can only run after `@Native` targets have been transformed.
219219
transformFfiUseSites.transformLibraries(
220+
this,
220221
component,
221222
coreTypes,
222223
hierarchy,
223224
transitiveImportingDartFfi,
224225
diagnosticReporter,
225226
referenceFromIndex,
227+
environmentDefines,
226228
);
227229
logger?.call("Transformed ffi use sites");
228230
}

pkg/vm/lib/modular/transformations/ffi/use_sites.dart

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
// This imports 'codes/cfe_codes.dart' instead of 'api_prototype/codes.dart' to
66
// avoid cyclic dependency between `package:vm/modular` and `package:front_end`.
7+
import 'package:front_end/src/api_prototype/constant_evaluator.dart'
8+
show ConstantEvaluator, SimpleErrorReporter;
79
import 'package:front_end/src/codes/cfe_codes.dart'
810
show
11+
LocatedMessage,
912
codeFfiAddressOfMustBeNative,
1013
codeFfiAddressPosition,
1114
codeFfiAddressReceiver,
@@ -28,7 +31,7 @@ import 'package:kernel/kernel.dart';
2831
import 'package:kernel/library_index.dart' show LibraryIndex;
2932
import 'package:kernel/names.dart';
3033
import 'package:kernel/reference_from_index.dart';
31-
import 'package:kernel/target/targets.dart' show DiagnosticReporter;
34+
import 'package:kernel/target/targets.dart' show DiagnosticReporter, Target;
3235
import 'package:kernel/type_algebra.dart'
3336
show FunctionTypeInstantiator, Substitution;
3437
import 'package:kernel/type_environment.dart';
@@ -40,18 +43,27 @@ import 'finalizable.dart';
4043
import 'native.dart' as native;
4144
import 'native_type_cfe.dart';
4245

46+
class _SilentErrorReporter extends SimpleErrorReporter {
47+
const _SilentErrorReporter();
48+
49+
@override
50+
void report(LocatedMessage message, [List<LocatedMessage>? context]) {}
51+
}
52+
4353
/// Checks and replaces calls to dart:ffi compound fields and methods.
4454
///
4555
/// To reliably lower calls to methods like `sizeOf` and `Native.addressOf`,
4656
/// this requires that the [definitions] and the [native] transformer already
4757
/// ran on the libraries to transform.
4858
void transformLibraries(
59+
Target target,
4960
Component component,
5061
CoreTypes coreTypes,
5162
ClassHierarchy hierarchy,
5263
List<Library> libraries,
5364
DiagnosticReporter diagnosticReporter,
5465
ReferenceFromIndex? referenceFromIndex,
66+
Map<String, String>? environmentDefines,
5567
) {
5668
final index = LibraryIndex(component, [
5769
"dart:ffi",
@@ -76,6 +88,15 @@ void transformLibraries(
7688
hierarchy,
7789
diagnosticReporter,
7890
referenceFromIndex,
91+
ConstantEvaluator(
92+
target.dartLibrarySupport,
93+
target.constantsBackend,
94+
component,
95+
environmentDefines,
96+
TypeEnvironment(coreTypes, hierarchy),
97+
const _SilentErrorReporter(),
98+
errorOnUnevaluatedConstant: true,
99+
),
79100
);
80101
libraries.forEach(transformer.visitLibrary);
81102
}
@@ -88,12 +109,14 @@ void transformLibraries(
88109
/// respectively. This means one cannot do `visitX() { super.visitX() as X }`.
89110
class _FfiUseSiteTransformer2 extends FfiTransformer
90111
with _FfiUseSiteTransformer, FinalizableTransformer {
112+
final ConstantEvaluator _constantEvaluator;
91113
_FfiUseSiteTransformer2(
92114
LibraryIndex index,
93115
CoreTypes coreTypes,
94116
ClassHierarchy hierarchy,
95117
DiagnosticReporter diagnosticReporter,
96118
ReferenceFromIndex? referenceFromIndex,
119+
this._constantEvaluator,
97120
) : super(
98121
index,
99122
coreTypes,
@@ -115,6 +138,7 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
115138
StaticTypeContext? get staticTypeContext;
116139

117140
bool _inFfiTearoff = false;
141+
ConstantEvaluator get _constantEvaluator;
118142

119143
bool get isFfiLibrary => currentLibrary == ffiLibrary;
120144

@@ -1210,9 +1234,11 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
12101234

12111235
// The exceptional return value must be a constant so that it can be
12121236
// referenced by precompiled trampoline's object pool.
1213-
if (exceptionalReturn is! BasicLiteral &&
1214-
!(exceptionalReturn is ConstantExpression &&
1215-
exceptionalReturn.constant is PrimitiveConstant)) {
1237+
final exceptionalReturnValue = _constantEvaluator.evaluate(
1238+
staticTypeContext!,
1239+
exceptionalReturn,
1240+
);
1241+
if (exceptionalReturnValue is UnevaluatedConstant) {
12161242
diagnosticReporter.report(
12171243
codeFfiExpectedConstant,
12181244
node.fileOffset,
@@ -1223,9 +1249,7 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
12231249
}
12241250

12251251
// Moreover it may not be null.
1226-
if (exceptionalReturn is NullLiteral ||
1227-
(exceptionalReturn is ConstantExpression &&
1228-
exceptionalReturn.constant is NullConstant)) {
1252+
if (exceptionalReturnValue is NullConstant) {
12291253
diagnosticReporter.report(
12301254
codeFfiExceptionalReturnNull,
12311255
node.fileOffset,
@@ -1251,6 +1275,11 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
12511275
);
12521276
return node;
12531277
}
1278+
1279+
exceptionalReturn = ConstantExpression(
1280+
exceptionalReturnValue,
1281+
returnType,
1282+
);
12541283
}
12551284

12561285
final compoundClasses =

pkg/vm/testcases/transformations/ffi/native_callable.dart.aot.expect

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ static method negateInt(core::int i) → core::int
9898

9999
[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)]
100100
static method testNativeCallableIsolateLocalInt() → void {
101-
final ffi::NativeCallable<(ffi::Int32) → ffi::Int> callback = new ffi::_NativeCallableIsolateLocal::•<(ffi::Int32) → ffi::Int>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_createNativeCallableIsolateLocal<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>(ffi::_nativeCallbackFunction<(ffi::Int32) → ffi::Int>(#C3, 123), null, true));
101+
final ffi::NativeCallable<(ffi::Int32) → ffi::Int> callback = new ffi::_NativeCallableIsolateLocal::•<(ffi::Int32) → ffi::Int>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_createNativeCallableIsolateLocal<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>(ffi::_nativeCallbackFunction<(ffi::Int32) → ffi::Int>(#C3, #C4), null, true));
102102
core::print([@vm.direct-call.metadata=dart.ffi::_NativeCallableBase.nativeFunction] [@vm.inferred-type.metadata=dart.ffi::Pointer] callback.{ffi::NativeCallable::nativeFunction}{ffi::Pointer<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>});
103103
[@vm.direct-call.metadata=dart.ffi::_NativeCallableBase.close] [@vm.inferred-type.metadata=? (skip check)] callback.{ffi::NativeCallable::close}(){() → void};
104104
}
@@ -108,12 +108,13 @@ static method testNativeCallableIsolateLocalIntClosure() → void {
108108
[@vm.inferred-type.metadata=dart.core::_Smi (value: 123)] core::int j = 123;
109109
function closure(core::int i) → core::int
110110
return [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(j){(core::num) → core::int};
111-
final ffi::NativeCallable<(ffi::Int32) → ffi::Int> callback = new ffi::_NativeCallableIsolateLocal::•<(ffi::Int32) → ffi::Int>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_createNativeCallableIsolateLocal<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>(ffi::_nativeIsolateLocalCallbackFunction<(ffi::Int32) → ffi::Int>(123), closure, true));
111+
final ffi::NativeCallable<(ffi::Int32) → ffi::Int> callback = new ffi::_NativeCallableIsolateLocal::•<(ffi::Int32) → ffi::Int>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_createNativeCallableIsolateLocal<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>(ffi::_nativeIsolateLocalCallbackFunction<(ffi::Int32) → ffi::Int>(#C4), closure, true));
112112
core::print([@vm.direct-call.metadata=dart.ffi::_NativeCallableBase.nativeFunction] [@vm.inferred-type.metadata=dart.ffi::Pointer] callback.{ffi::NativeCallable::nativeFunction}{ffi::Pointer<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>});
113113
[@vm.direct-call.metadata=dart.ffi::_NativeCallableBase.close] [@vm.inferred-type.metadata=? (skip check)] callback.{ffi::NativeCallable::close}(){() → void};
114114
}
115115
constants {
116116
#C1 = static-tearoff self::printInt
117117
#C2 = static-tearoff self::intToPointer
118118
#C3 = static-tearoff self::negateInt
119+
#C4 = 123
119120
}

pkg/vm/testcases/transformations/ffi/native_callable.dart.expect

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,20 +72,21 @@ static method testNativeCallableIsolateLocalPointerClosure() → void {
7272
static method negateInt(core::int i) → core::int
7373
return i.{core::int::unary-}(){() → core::int};
7474
static method testNativeCallableIsolateLocalInt() → void {
75-
final ffi::NativeCallable<(ffi::Int32) → ffi::Int> callback = new ffi::_NativeCallableIsolateLocal::•<(ffi::Int32) → ffi::Int>(ffi::_createNativeCallableIsolateLocal<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>(ffi::_nativeCallbackFunction<(ffi::Int32) → ffi::Int>(#C3, 123), null, true));
75+
final ffi::NativeCallable<(ffi::Int32) → ffi::Int> callback = new ffi::_NativeCallableIsolateLocal::•<(ffi::Int32) → ffi::Int>(ffi::_createNativeCallableIsolateLocal<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>(ffi::_nativeCallbackFunction<(ffi::Int32) → ffi::Int>(#C3, #C4), null, true));
7676
core::print(callback.{ffi::NativeCallable::nativeFunction}{ffi::Pointer<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>});
7777
callback.{ffi::NativeCallable::close}(){() → void};
7878
}
7979
static method testNativeCallableIsolateLocalIntClosure() → void {
8080
core::int j = 123;
8181
function closure(core::int i) → core::int
8282
return i.{core::num::+}(j){(core::num) → core::int};
83-
final ffi::NativeCallable<(ffi::Int32) → ffi::Int> callback = new ffi::_NativeCallableIsolateLocal::•<(ffi::Int32) → ffi::Int>(ffi::_createNativeCallableIsolateLocal<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>(ffi::_nativeIsolateLocalCallbackFunction<(ffi::Int32) → ffi::Int>(123), closure, true));
83+
final ffi::NativeCallable<(ffi::Int32) → ffi::Int> callback = new ffi::_NativeCallableIsolateLocal::•<(ffi::Int32) → ffi::Int>(ffi::_createNativeCallableIsolateLocal<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>(ffi::_nativeIsolateLocalCallbackFunction<(ffi::Int32) → ffi::Int>(#C4), closure, true));
8484
core::print(callback.{ffi::NativeCallable::nativeFunction}{ffi::Pointer<ffi::NativeFunction<(ffi::Int32) → ffi::Int>>});
8585
callback.{ffi::NativeCallable::close}(){() → void};
8686
}
8787
constants {
8888
#C1 = static-tearoff self::printInt
8989
#C2 = static-tearoff self::intToPointer
9090
#C3 = static-tearoff self::negateInt
91+
#C4 = 123
9192
}

pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ final class Struct12 extends ffi::Struct {
7070
}
7171

7272
[@vm.inferred-type.metadata=dart.ffi::Pointer]
73-
static final field ffi::Pointer<ffi::NativeFunction<(self::Struct3) → ffi::Int32>> _#ffiCallback0 = [@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_createNativeCallableIsolateLocal<ffi::NativeFunction<(self::Struct3) → ffi::Int32>>(ffi::_nativeCallbackFunction<(self::Struct3) → ffi::Int32>(#C17, 0), null, false);
73+
static final field ffi::Pointer<ffi::NativeFunction<(self::Struct3) → ffi::Int32>> _#ffiCallback0 = [@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_createNativeCallableIsolateLocal<ffi::NativeFunction<(self::Struct3) → ffi::Int32>>(ffi::_nativeCallbackFunction<(self::Struct3) → ffi::Int32>(#C17, #C9), null, false);
7474

7575
[@vm.inferred-type.metadata=dart.ffi::Pointer]
7676
static final field ffi::Pointer<ffi::NativeFunction<() → self::Struct7>> _#ffiCallback1 = [@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_createNativeCallableIsolateLocal<ffi::NativeFunction<() → self::Struct7>>(ffi::_nativeCallbackFunction<() → self::Struct7>(#C18, null), null, false);

0 commit comments

Comments
 (0)