dart-sdk/tests/ffi/static_checks_test.dart
Samir Jindel fc6cb0ac21 [vm/ffi] Revamp struct representation in FFI.
See dartbug.com/37229 for details.

Change-Id: I63490e41c512ffc9312803985a6f6d4be1586c0a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101291
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
2019-07-02 23:12:13 +00:00

435 lines
12 KiB
Dart

// Copyright (c) 2019, 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.
//
// Dart test program for testing dart:ffi extra checks
//
// SharedObjects=ffi_test_dynamic_library
library FfiTest;
import 'dart:ffi' as ffi;
import 'dart:ffi' show Pointer;
import 'dylib_utils.dart';
void main() {
testGetGeneric();
testGetGeneric2();
testGetVoid();
testGetNativeFunction();
testGetNativeType();
testGetTypeMismatch();
testSetGeneric();
testSetGeneric2();
testSetVoid();
testSetNativeFunction();
testSetNativeType();
testSetTypeMismatch();
testAsFunctionGeneric();
testAsFunctionGeneric2();
testAsFunctionWrongNativeFunctionSignature();
testAsFunctionTypeMismatch();
testFromFunctionGeneric();
testFromFunctionGeneric2();
testFromFunctionWrongNativeFunctionSignature();
testFromFunctionTypeMismatch();
testFromFunctionClosure();
testFromFunctionTearOff();
testLookupFunctionGeneric();
testLookupFunctionGeneric2();
testLookupFunctionWrongNativeFunctionSignature();
testLookupFunctionTypeMismatch();
testNativeFunctionSignatureInvalidReturn();
testNativeFunctionSignatureInvalidParam();
testNativeFunctionSignatureInvalidOptionalNamed();
testNativeFunctionSignatureInvalidOptionalPositional();
}
typedef Int8UnOp = ffi.Int8 Function(ffi.Int8);
typedef IntUnOp = int Function(int);
void testGetGeneric() {
int generic(ffi.Pointer p) {
int result;
result = p.load<int>(); //# 20: compile-time error
return result;
}
ffi.Pointer<ffi.Int8> p = Pointer.allocate();
p.store(123);
ffi.Pointer loseType = p;
generic(loseType);
p.free();
}
void testGetGeneric2() {
T generic<T extends Object>() {
Pointer<ffi.Int8> p = Pointer.allocate();
p.store(123);
T result;
result = p.load<T>(); //# 21: compile-time error
p.free();
return result;
}
generic<int>();
}
void testGetVoid() {
ffi.Pointer<ffi.IntPtr> p1 = Pointer.allocate();
ffi.Pointer<ffi.Void> p2 = p1.cast();
p2.load<int>(); //# 22: compile-time error
p1.free();
}
void testGetNativeFunction() {
Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
IntUnOp f = p.load(); //# 23: compile-time error
}
void testGetNativeType() {
// Is it possible to obtain a ffi.Pointer<ffi.NativeType> at all?
}
void testGetTypeMismatch() {
ffi.Pointer<ffi.Pointer<ffi.Int16>> p = Pointer.allocate();
ffi.Pointer<ffi.Int16> typedNull = ffi.nullptr.cast();
p.store(typedNull);
// this fails to compile due to type mismatch
ffi.Pointer<ffi.Int8> p2 = p.load(); //# 25: compile-time error
p.free();
}
void testSetGeneric() {
void generic(ffi.Pointer p) {
p.store(123); //# 26: compile-time error
}
ffi.Pointer<ffi.Int8> p = Pointer.allocate();
p.store(123);
ffi.Pointer loseType = p;
generic(loseType);
p.free();
}
void testSetGeneric2() {
void generic<T extends Object>(T arg) {
ffi.Pointer<ffi.Int8> p = Pointer.allocate();
p.store(arg); //# 27: compile-time error
p.free();
}
generic<int>(123);
}
void testSetVoid() {
ffi.Pointer<ffi.IntPtr> p1 = Pointer.allocate();
ffi.Pointer<ffi.Void> p2 = p1.cast();
p2.store(1234); //# 28: compile-time error
p1.free();
}
void testSetNativeFunction() {
Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
IntUnOp f = (a) => a + 1;
p.store(f); //# 29: compile-time error
}
void testSetNativeType() {
// Is it possible to obtain a ffi.Pointer<ffi.NativeType> at all?
}
void testSetTypeMismatch() {
// the pointer to pointer types must match up
ffi.Pointer<ffi.Int8> pHelper = Pointer.allocate();
pHelper.store(123);
ffi.Pointer<ffi.Pointer<ffi.Int16>> p = Pointer.allocate();
// this fails to compile due to type mismatch
p.store(pHelper); //# 40: compile-time error
pHelper.free();
p.free();
}
void testAsFunctionGeneric() {
T generic<T extends Function>() {
ffi.Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
Function f;
f = p.asFunction<T>(); //# 11: compile-time error
return f;
}
generic<IntUnOp>();
}
void testAsFunctionGeneric2() {
generic(ffi.Pointer<ffi.NativeFunction> p) {
Function f;
f = p.asFunction<IntUnOp>(); //# 12: compile-time error
return f;
}
ffi.Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
generic(p);
}
void testAsFunctionWrongNativeFunctionSignature() {
ffi.Pointer<ffi.NativeFunction<IntUnOp>> p;
Function f = p.asFunction<IntUnOp>(); //# 13: compile-time error
}
typedef IntBinOp = int Function(int, int);
void testAsFunctionTypeMismatch() {
ffi.Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
IntBinOp f = p.asFunction(); //# 14: compile-time error
}
typedef NativeDoubleUnOp = ffi.Double Function(ffi.Double);
typedef DoubleUnOp = double Function(double);
double myTimesThree(double d) => d * 3;
int myTimesFour(int i) => i * 4;
void testFromFunctionGeneric() {
ffi.Pointer<ffi.NativeFunction> generic<T extends Function>(T f) {
ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> result;
result = ffi.fromFunction(f); //# 70: compile-time error
return result;
}
generic(myTimesThree);
}
void testFromFunctionGeneric2() {
ffi.Pointer<ffi.NativeFunction<T>> generic<T extends Function>() {
ffi.Pointer<ffi.NativeFunction<T>> result;
result = ffi.fromFunction(myTimesThree); //# 71: compile-time error
return result;
}
generic<NativeDoubleUnOp>();
}
void testFromFunctionWrongNativeFunctionSignature() {
ffi.fromFunction<IntUnOp>(myTimesFour); //# 72: compile-time error
}
void testFromFunctionTypeMismatch() {
ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> p;
p = ffi.fromFunction(myTimesFour); //# 73: compile-time error
}
void testFromFunctionClosure() {
DoubleUnOp someClosure = (double z) => z / 27.0;
ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> p;
p = ffi.fromFunction(someClosure); //# 74: compile-time error
}
class X {
double tearoff(double d) => d / 27.0;
}
DoubleUnOp fld = null;
void testFromFunctionTearOff() {
fld = X().tearoff;
ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> p;
p = ffi.fromFunction(fld); //# 75: compile-time error
}
void testLookupFunctionGeneric() {
Function generic<T extends Function>() {
ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
Function result;
result = l.lookupFunction<T, DoubleUnOp>("cos"); //# 15: compile-time error
return result;
}
generic<NativeDoubleUnOp>();
}
void testLookupFunctionGeneric2() {
Function generic<T extends Function>() {
ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
Function result;
result = //# 16: compile-time error
l.lookupFunction<NativeDoubleUnOp, T>("cos"); //# 16: compile-time error
return result;
}
generic<DoubleUnOp>();
}
void testLookupFunctionWrongNativeFunctionSignature() {
ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
l.lookupFunction<IntUnOp, IntUnOp>("cos"); //# 17: compile-time error
}
void testLookupFunctionTypeMismatch() {
ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
l.lookupFunction<NativeDoubleUnOp, IntUnOp>("cos"); //# 18: compile-time error
}
// TODO(dacoharkes): make the next 4 test compile errors
typedef Invalid1 = int Function(ffi.Int8);
typedef Invalid2 = ffi.Int8 Function(int);
typedef Invalid3 = ffi.Int8 Function({ffi.Int8 named});
typedef Invalid4 = ffi.Int8 Function([ffi.Int8 positional]);
void testNativeFunctionSignatureInvalidReturn() {
// ffi.Pointer<ffi.NativeFunction<Invalid1>> p = ffi.fromAddress(999);
}
void testNativeFunctionSignatureInvalidParam() {
// ffi.Pointer<ffi.NativeFunction<Invalid2>> p = ffi.fromAddress(999);
}
void testNativeFunctionSignatureInvalidOptionalNamed() {
// ffi.Pointer<ffi.NativeFunction<Invalid3>> p = ffi.fromAddress(999);
}
void testNativeFunctionSignatureInvalidOptionalPositional() {
// ffi.Pointer<ffi.NativeFunction<Invalid4>> p = ffi.fromAddress(999);
}
// error on missing field annotation
class TestStruct extends ffi.Struct<TestStruct> {
@ffi.Double()
double x;
double y; //# 50: compile-time error
}
// Cannot extend structs.
class TestStruct3 extends TestStruct {} //# 52: compile-time error
// error on double annotation
class TestStruct4 extends ffi.Struct<TestStruct4> {
@ffi.Double()
@ffi.Double() //# 53: compile-time error
double z;
}
// error on annotation not matching up
class TestStruct5 extends ffi.Struct<TestStruct5> {
@ffi.Int64() //# 54: compile-time error
double z; //# 54: compile-time error
}
// error on annotation not matching up
class TestStruct6 extends ffi.Struct<TestStruct6> {
@ffi.Void() //# 55: compile-time error
double z; //# 55: compile-time error
}
// error on annotation not matching up
class TestStruct7 extends ffi.Struct<TestStruct7> {
@ffi.NativeType() //# 56: compile-time error
double z; //# 56: compile-time error
}
// error on field initializer on field
class TestStruct8 extends ffi.Struct<TestStruct8> {
@ffi.Double() //# 57: compile-time error
double z = 10.0; //# 57: compile-time error
}
// error on field initializer in constructor
class TestStruct9 extends ffi.Struct<TestStruct9> {
@ffi.Double()
double z;
TestStruct9() : z = 0.0 {} //# 58: compile-time error
}
// A struct "C" must extend "Struct<C>", not "Struct<AnythingElse>".
class TestStruct10 extends ffi.Struct<ffi.Int8> {} //# 59: compile-time error
// Struct classes may not be generic.
class TestStruct11<T> extends ffi.Struct<TestStruct11<dynamic>> {} //# 60: compile-time error
// Structs may not appear inside structs (currently, there is no suitable
// annotation).
class TestStruct12 extends ffi.Struct<TestStruct12> {
@ffi.Pointer //# 61: compile-time error
TestStruct9 struct; //# 61: compile-time error
}
// Cannot extend native types.
class ENativeType extends ffi.NativeType {} //# 90: compile-time error
class EInt8 extends ffi.Int8 {} //# 91: compile-time error
class EInt16 extends ffi.Int16 {} //# 92: compile-time error
class EInt32 extends ffi.Int32 {} //# 93: compile-time error
class EInt64 extends ffi.Int64 {} //# 94: compile-time error
class EUint8 extends ffi.Uint8 {} //# 95: compile-time error
class EUint16 extends ffi.Uint16 {} //# 96: compile-time error
class EUint32 extends ffi.Uint32 {} //# 97: compile-time error
class EUint64 extends ffi.Uint64 {} //# 98: compile-time error
class EIntPtr extends ffi.IntPtr {} //# 99: compile-time error
class EFloat extends ffi.Float {} //# 910: compile-time error
class EDouble extends ffi.Double {} //# 911: compile-time error
class EVoid extends ffi.Void {} //# 912: compile-time error
class ENativeFunction extends ffi.NativeFunction {} //# 913: compile-time error
class EPointer extends ffi.Pointer {} //# 914: compile-time error
// Cannot implement native natives or Struct.
// Cannot extend native types.
class INativeType implements ffi.NativeType {} //# 80: compile-time error
class IInt8 implements ffi.Int8 {} //# 81: compile-time error
class IInt16 implements ffi.Int16 {} //# 82: compile-time error
class IInt32 implements ffi.Int32 {} //# 83: compile-time error
class IInt64 implements ffi.Int64 {} //# 84: compile-time error
class IUint8 implements ffi.Uint8 {} //# 85: compile-time error
class IUint16 implements ffi.Uint16 {} //# 86: compile-time error
class IUint32 implements ffi.Uint32 {} //# 87: compile-time error
class IUint64 implements ffi.Uint64 {} //# 88: compile-time error
class IIntPtr implements ffi.IntPtr {} //# 88: compile-time error
class IFloat implements ffi.Float {} //# 810: compile-time error
class IDouble implements ffi.Double {} //# 811: compile-time error
class IVoid implements ffi.Void {} //# 812: compile-time error
class INativeFunction implements ffi.NativeFunction {} //# 813: compile-time error
class IPointer implements ffi.Pointer {} //# 814: compile-time error
class IStruct implements ffi.Struct {} //# 815: compile-time error