| // 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 ffi_test_functions |
| |
| import 'dart:ffi'; |
| |
| import "package:ffi/ffi.dart"; |
| |
| 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(); |
| testFromFunctionAbstract(); |
| testLookupFunctionGeneric(); |
| testLookupFunctionGeneric2(); |
| testLookupFunctionWrongNativeFunctionSignature(); |
| testLookupFunctionTypeMismatch(); |
| testLookupFunctionPointervoid(); |
| testLookupFunctionPointerNFdyn(); |
| testNativeFunctionSignatureInvalidReturn(); |
| testNativeFunctionSignatureInvalidParam(); |
| testNativeFunctionSignatureInvalidOptionalNamed(); |
| testNativeFunctionSignatureInvalidOptionalPositional(); |
| testHandleVariance(); |
| testEmptyStructLookupFunctionArgument(); |
| testEmptyStructLookupFunctionReturn(); |
| testEmptyStructAsFunctionArgument(); |
| testEmptyStructAsFunctionReturn(); |
| testEmptyStructFromFunctionArgument(); |
| testEmptyStructFromFunctionReturn(); |
| testAllocateGeneric(); |
| testAllocateNativeType(); |
| testRefStruct(); |
| testSizeOfGeneric(); |
| testSizeOfNativeType(); |
| testElementAtGeneric(); |
| testElementAtNativeType(); |
| } |
| |
| typedef Int8UnOp = Int8 Function(Int8); |
| typedef IntUnOp = int Function(int); |
| |
| void testGetGeneric() { |
| int generic(Pointer p) { |
| int result = -1; |
| result = p.value; //# 20: compile-time error |
| return result; |
| } |
| |
| Pointer<Int8> p = calloc(); |
| p.value = 123; |
| Pointer loseType = p; |
| generic(loseType); |
| calloc.free(p); |
| } |
| |
| void testGetGeneric2() { |
| T? generic<T extends Object>() { |
| Pointer<Int8> p = calloc(); |
| p.value = 123; |
| T? result; |
| result = p.value; //# 21: compile-time error |
| calloc.free(p); |
| return result; |
| } |
| |
| generic<int>(); |
| } |
| |
| void testGetVoid() { |
| Pointer<IntPtr> p1 = calloc(); |
| Pointer<Void> p2 = p1.cast(); |
| |
| p2.value; //# 22: compile-time error |
| |
| calloc.free(p1); |
| } |
| |
| void testGetNativeFunction() { |
| Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337); |
| IntUnOp f = p.value; //# 23: compile-time error |
| } |
| |
| void testGetNativeType() { |
| // Is it possible to obtain a Pointer<NativeType> at all? |
| } |
| |
| void testGetTypeMismatch() { |
| Pointer<Pointer<Int16>> p = calloc(); |
| Pointer<Int16> typedNull = nullptr; |
| p.value = typedNull; |
| |
| // this fails to compile due to type mismatch |
| Pointer<Int8> p2 = p.value; //# 25: compile-time error |
| |
| calloc.free(p); |
| } |
| |
| void testSetGeneric() { |
| void generic(Pointer p) { |
| p.value = 123; //# 26: compile-time error |
| } |
| |
| Pointer<Int8> p = calloc(); |
| p.value = 123; |
| Pointer loseType = p; |
| generic(loseType); |
| calloc.free(p); |
| } |
| |
| void testSetGeneric2() { |
| void generic<T extends Object>(T arg) { |
| Pointer<Int8> p = calloc(); |
| p.value = arg; //# 27: compile-time error |
| calloc.free(p); |
| } |
| |
| generic<int>(123); |
| } |
| |
| void testSetVoid() { |
| Pointer<IntPtr> p1 = calloc(); |
| Pointer<Void> p2 = p1.cast(); |
| |
| p2.value = 1234; //# 28: compile-time error |
| |
| calloc.free(p1); |
| } |
| |
| void testSetNativeFunction() { |
| Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337); |
| IntUnOp f = (a) => a + 1; |
| p.value = f; //# 29: compile-time error |
| } |
| |
| void testSetNativeType() { |
| // Is it possible to obtain a Pointer<NativeType> at all? |
| } |
| |
| void testSetTypeMismatch() { |
| // the pointer to pointer types must match up |
| Pointer<Int8> pHelper = calloc(); |
| pHelper.value = 123; |
| |
| Pointer<Pointer<Int16>> p = calloc(); |
| |
| // this fails to compile due to type mismatch |
| p.value = pHelper; //# 40: compile-time error |
| |
| calloc.free(pHelper); |
| calloc.free(p); |
| } |
| |
| void testAsFunctionGeneric() { |
| T generic<T extends Function>(T defaultFunction) { |
| Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337); |
| T f = defaultFunction; |
| f = p.asFunction<T>(); //# 11: compile-time error |
| return f; |
| } |
| |
| generic<IntUnOp>((int a) => a + 1); |
| } |
| |
| void testAsFunctionGeneric2() { |
| generic(Pointer<NativeFunction> p) { |
| Function f = () => "dummy"; |
| f = p.asFunction<IntUnOp>(); //# 12: compile-time error |
| return f; |
| } |
| |
| Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337); |
| generic(p); |
| } |
| |
| void testAsFunctionWrongNativeFunctionSignature() { |
| Pointer<NativeFunction<IntUnOp>> p; |
| Function f = p.asFunction<IntUnOp>(); //# 13: compile-time error |
| } |
| |
| typedef IntBinOp = int Function(int, int); |
| |
| void testAsFunctionTypeMismatch() { |
| Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337); |
| IntBinOp f = p.asFunction(); //# 14: compile-time error |
| } |
| |
| typedef NativeDoubleUnOp = Double Function(Double); |
| typedef DoubleUnOp = double Function(double); |
| |
| double myTimesThree(double d) => d * 3; |
| |
| int myTimesFour(int i) => i * 4; |
| |
| void testFromFunctionGeneric() { |
| Pointer<NativeFunction> generic<T extends Function>(T f) { |
| Pointer<NativeFunction<NativeDoubleUnOp>> result = nullptr; |
| result = Pointer.fromFunction(f); //# 70: compile-time error |
| return result; |
| } |
| |
| generic(myTimesThree); |
| } |
| |
| void testFromFunctionGeneric2() { |
| Pointer<NativeFunction<T>> generic<T extends Function>() { |
| Pointer<NativeFunction<T>> result = nullptr; |
| result = Pointer.fromFunction(myTimesThree); //# 71: compile-time error |
| return result; |
| } |
| |
| generic<NativeDoubleUnOp>(); |
| } |
| |
| void testFromFunctionWrongNativeFunctionSignature() { |
| Pointer.fromFunction<IntUnOp>(myTimesFour); //# 72: compile-time error |
| } |
| |
| void testFromFunctionTypeMismatch() { |
| Pointer<NativeFunction<NativeDoubleUnOp>> p; |
| p = Pointer.fromFunction(myTimesFour); //# 73: compile-time error |
| } |
| |
| void testFromFunctionClosure() { |
| DoubleUnOp someClosure = (double z) => z / 27.0; |
| Pointer<NativeFunction<NativeDoubleUnOp>> p; |
| p = Pointer.fromFunction(someClosure); //# 74: compile-time error |
| } |
| |
| class X { |
| double tearoff(double d) => d / 27.0; |
| } |
| |
| void testFromFunctionTearOff() { |
| DoubleUnOp fld = X().tearoff; |
| Pointer<NativeFunction<NativeDoubleUnOp>> p; |
| p = Pointer.fromFunction(fld); //# 75: compile-time error |
| } |
| |
| void testFromFunctionAbstract() { |
| Pointer.fromFunction<Function>(//# 76: compile-time error |
| testFromFunctionAbstract); //# 76: compile-time error |
| } |
| |
| void testLookupFunctionGeneric() { |
| Function generic<T extends Function>() { |
| DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); |
| Function result = () => "dummy"; |
| result = l.lookupFunction<T, DoubleUnOp>("cos"); //# 15: compile-time error |
| return result; |
| } |
| |
| generic<NativeDoubleUnOp>(); |
| } |
| |
| void testLookupFunctionGeneric2() { |
| Function generic<T extends Function>() { |
| DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); |
| Function result = () => "dummy"; |
| result = //# 16: compile-time error |
| l.lookupFunction<NativeDoubleUnOp, T>("cos"); //# 16: compile-time error |
| return result; |
| } |
| |
| generic<DoubleUnOp>(); |
| } |
| |
| void testLookupFunctionWrongNativeFunctionSignature() { |
| DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); |
| l.lookupFunction<IntUnOp, IntUnOp>("cos"); //# 17: compile-time error |
| } |
| |
| void testLookupFunctionTypeMismatch() { |
| DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); |
| l.lookupFunction<NativeDoubleUnOp, IntUnOp>("cos"); //# 18: compile-time error |
| } |
| |
| typedef PointervoidN = Void Function(Pointer<void>); |
| typedef PointervoidD = void Function(Pointer<void>); |
| |
| void testLookupFunctionPointervoid() { |
| DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); |
| // TODO(https://dartbug.com/44593): This should be a compile-time error in CFE. |
| // l.lookupFunction<PointervoidN, PointervoidD>("cos"); |
| } |
| |
| typedef PointerNFdynN = Void Function(Pointer<NativeFunction>); |
| typedef PointerNFdynD = void Function(Pointer<NativeFunction>); |
| |
| void testLookupFunctionPointerNFdyn() { |
| DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); |
| // TODO(https://dartbug.com/44594): Should this be an error or not? |
| // l.lookupFunction<PointerNFdynN, PointerNFdynD>("cos"); |
| } |
| |
| // TODO(dacoharkes): make the next 4 test compile errors |
| typedef Invalid1 = int Function(Int8); |
| typedef Invalid2 = Int8 Function(int); |
| typedef Invalid3 = Int8 Function({Int8 named}); |
| typedef Invalid4 = Int8 Function([Int8 positional]); |
| |
| void testNativeFunctionSignatureInvalidReturn() { |
| // Pointer<NativeFunction<Invalid1>> p = fromAddress(999); |
| } |
| |
| void testNativeFunctionSignatureInvalidParam() { |
| // Pointer<NativeFunction<Invalid2>> p = fromAddress(999); |
| } |
| |
| void testNativeFunctionSignatureInvalidOptionalNamed() { |
| // Pointer<NativeFunction<Invalid3>> p = fromAddress(999); |
| } |
| |
| void testNativeFunctionSignatureInvalidOptionalPositional() { |
| // Pointer<NativeFunction<Invalid4>> p = fromAddress(999); |
| } |
| |
| // error on missing field annotation |
| class TestStruct extends Struct { |
| @Double() |
| external double x; |
| |
| external double y; //# 50: compile-time error |
| } |
| |
| // Cannot extend structs. |
| class TestStruct3 extends TestStruct {} //# 52: compile-time error |
| |
| // error on double annotation |
| class TestStruct4 extends Struct { |
| @Double() |
| @Double() //# 53: compile-time error |
| external double z; |
| } |
| |
| // error on annotation not matching up |
| class TestStruct5 extends Struct { |
| @Int64() //# 54: compile-time error |
| external double z; //# 54: compile-time error |
| |
| external Pointer notEmpty; |
| } |
| |
| // error on annotation not matching up |
| class TestStruct6 extends Struct { |
| @Void() //# 55: compile-time error |
| external double z; //# 55: compile-time error |
| |
| external Pointer notEmpty; |
| } |
| |
| // error on annotation not matching up |
| class TestStruct7 extends Struct { |
| @NativeType() //# 56: compile-time error |
| external double z; //# 56: compile-time error |
| |
| external Pointer notEmpty; |
| } |
| |
| // error on field initializer on field |
| class TestStruct8 extends Struct { |
| @Double() //# 57: compile-time error |
| double z = 10.0; //# 57: compile-time error |
| |
| external Pointer notEmpty; |
| } |
| |
| // error on field initializer in constructor |
| class TestStruct9 extends Struct { |
| @Double() //# 58: compile-time error |
| double z; //# 58: compile-time error |
| |
| external Pointer notEmpty; |
| |
| TestStruct9() : z = 0.0 {} //# 58: compile-time error |
| } |
| |
| // Struct classes may not be generic. |
| class TestStruct11<T> extends //# 60: compile-time error |
| Struct<TestStruct11<dynamic>> {} //# 60: compile-time error |
| |
| // Structs may not appear inside structs (currently, there is no suitable |
| // annotation). |
| class TestStruct12 extends Struct { |
| @Pointer //# 61: compile-time error |
| external TestStruct9 struct; //# 61: compile-time error |
| |
| external Pointer notEmpty; |
| } |
| |
| class DummyAnnotation { |
| const DummyAnnotation(); |
| } |
| |
| // Structs fields may have other annotations. |
| class TestStruct13 extends Struct { |
| @DummyAnnotation() |
| @Double() |
| external double z; |
| } |
| |
| // Cannot extend native types. |
| |
| class ENativeType extends NativeType {} //# 90: compile-time error |
| |
| class EInt8 extends Int8 {} //# 91: compile-time error |
| |
| class EInt16 extends Int16 {} //# 92: compile-time error |
| |
| class EInt32 extends Int32 {} //# 93: compile-time error |
| |
| class EInt64 extends Int64 {} //# 94: compile-time error |
| |
| class EUint8 extends Uint8 {} //# 95: compile-time error |
| |
| class EUint16 extends Uint16 {} //# 96: compile-time error |
| |
| class EUint32 extends Uint32 {} //# 97: compile-time error |
| |
| class EUint64 extends Uint64 {} //# 98: compile-time error |
| |
| class EIntPtr extends IntPtr {} //# 99: compile-time error |
| |
| class EFloat extends Float {} //# 910: compile-time error |
| |
| class EDouble extends Double {} //# 911: compile-time error |
| |
| class EVoid extends Void {} //# 912: compile-time error |
| |
| class ENativeFunction extends NativeFunction {} //# 913: compile-time error |
| |
| class EPointer extends Pointer {} //# 914: compile-time error |
| |
| // Cannot implement native natives or Struct. |
| |
| // Cannot extend native types. |
| |
| class INativeType implements NativeType {} //# 80: compile-time error |
| |
| class IInt8 implements Int8 {} //# 81: compile-time error |
| |
| class IInt16 implements Int16 {} //# 82: compile-time error |
| |
| class IInt32 implements Int32 {} //# 83: compile-time error |
| |
| class IInt64 implements Int64 {} //# 84: compile-time error |
| |
| class IUint8 implements Uint8 {} //# 85: compile-time error |
| |
| class IUint16 implements Uint16 {} //# 86: compile-time error |
| |
| class IUint32 implements Uint32 {} //# 87: compile-time error |
| |
| class IUint64 implements Uint64 {} //# 88: compile-time error |
| |
| class IIntPtr implements IntPtr {} //# 88: compile-time error |
| |
| class IFloat implements Float {} //# 810: compile-time error |
| |
| class IDouble implements Double {} //# 811: compile-time error |
| |
| class IVoid implements Void {} //# 812: compile-time error |
| |
| class INativeFunction //# 813: compile-time error |
| implements //# 813: compile-time error |
| NativeFunction {} //# 813: compile-time error |
| |
| class IPointer implements Pointer {} //# 814: compile-time error |
| |
| class IStruct implements Struct {} //# 815: compile-time error |
| |
| class IOpaque implements Opaque {} //# 816: compile-time error |
| |
| class MyClass { |
| int x; |
| MyClass(this.x); |
| } |
| |
| final testLibrary = dlopenPlatformSpecific("ffi_test_functions"); |
| |
| void testHandleVariance() { |
| // Taking a more specific argument is okay. |
| testLibrary.lookupFunction<Handle Function(Handle), Object Function(MyClass)>( |
| "PassObjectToC"); |
| |
| // Requiring a more specific return type is not, this requires a cast from |
| // the user. |
| testLibrary.lookupFunction< //# 1000: compile-time error |
| Handle Function(Handle), //# 1000: compile-time error |
| MyClass Function(Object)>("PassObjectToC"); //# 1000: compile-time error |
| } |
| |
| class TestStruct1001 extends Struct { |
| external Handle handle; //# 1001: compile-time error |
| |
| external Pointer notEmpty; |
| } |
| |
| class TestStruct1002 extends Struct { |
| @Handle() //# 1002: compile-time error |
| external Object handle; //# 1002: compile-time error |
| |
| external Pointer notEmpty; |
| } |
| |
| class EmptyStruct extends Struct {} //# 1099: compile-time error |
| |
| class EmptyStruct extends Struct {} //# 1100: compile-time error |
| |
| void testEmptyStructLookupFunctionArgument() { |
| testLibrary.lookupFunction< //# 1100: compile-time error |
| Void Function(EmptyStruct), //# 1100: compile-time error |
| void Function(EmptyStruct)>("DoesNotExist"); //# 1100: compile-time error |
| } |
| |
| class EmptyStruct extends Struct {} //# 1101: compile-time error |
| |
| void testEmptyStructLookupFunctionReturn() { |
| testLibrary.lookupFunction< //# 1101: compile-time error |
| EmptyStruct Function(), //# 1101: compile-time error |
| EmptyStruct Function()>("DoesNotExist"); //# 1101: compile-time error |
| } |
| |
| class EmptyStruct extends Struct {} //# 1102: compile-time error |
| |
| void testEmptyStructAsFunctionArgument() { |
| final Pointer< //# 1102: compile-time error |
| NativeFunction< //# 1102: compile-time error |
| Void Function(EmptyStruct)>> //# 1102: compile-time error |
| pointer = Pointer.fromAddress(1234); //# 1102: compile-time error |
| pointer.asFunction<void Function(EmptyStruct)>(); //# 1102: compile-time error |
| } |
| |
| class EmptyStruct extends Struct {} //# 1103: compile-time error |
| |
| void testEmptyStructAsFunctionReturn() { |
| final Pointer< //# 1103: compile-time error |
| NativeFunction<EmptyStruct Function()>> //# 1103: compile-time error |
| pointer = Pointer.fromAddress(1234); //# 1103: compile-time error |
| pointer.asFunction<EmptyStruct Function()>(); //# 1103: compile-time error |
| } |
| |
| class EmptyStruct extends Struct {} //# 1104: compile-time error |
| |
| void _consumeEmptyStruct(EmptyStruct e) => //# 1104: compile-time error |
| print(e); //# 1104: compile-time error |
| |
| void testEmptyStructFromFunctionArgument() { |
| Pointer.fromFunction<Void Function(EmptyStruct)>(//# 1104: compile-time error |
| _consumeEmptyStruct); //# 1104: compile-time error |
| } |
| |
| class EmptyStruct extends Struct {} //# 1105: compile-time error |
| |
| EmptyStruct _returnEmptyStruct() => EmptyStruct(); //# 1105: compile-time error |
| |
| void testEmptyStructFromFunctionReturn() { |
| Pointer.fromFunction<EmptyStruct Function()>(//# 1105: compile-time error |
| _returnEmptyStruct); //# 1105: compile-time error |
| } |
| |
| class EmptyStruct extends Struct {} //# 1106: compile-time error |
| |
| class HasNestedEmptyStruct extends Struct { |
| external EmptyStruct nestedEmptyStruct; //# 1106: compile-time error |
| |
| external Pointer notEmpty; |
| } |
| |
| void testAllocateGeneric() { |
| Pointer<T> generic<T extends NativeType>() { |
| Pointer<T> pointer = nullptr; |
| pointer = calloc(); //# 1320: compile-time error |
| return pointer; |
| } |
| |
| Pointer p = generic<Int64>(); |
| } |
| |
| void testAllocateNativeType() { |
| calloc(); //# 1321: compile-time error |
| } |
| |
| void testRefStruct() { |
| final myStructPointer = calloc<TestStruct13>(); |
| Pointer<Struct> structPointer = myStructPointer; |
| structPointer.ref; //# 1330: compile-time error |
| calloc.free(myStructPointer); |
| } |
| |
| T genericRef<T extends Struct>(Pointer<T> p) => //# 1200: compile-time error |
| p.ref; //# 1200: compile-time error |
| |
| T genericRef2<T extends Struct>(Pointer<T> p) => //# 1201: compile-time error |
| p.cast<T>().ref; //# 1201: compile-time error |
| |
| T genericRef3<T extends Struct>(Pointer<T> p) => //# 1202: compile-time error |
| p[0]; //# 1202: compile-time error |
| |
| T genericRef4<T extends Struct>(Array<T> p) => //# 1210: compile-time error |
| p[0]; //# 1210: compile-time error |
| |
| void testSizeOfGeneric() { |
| int generic<T extends Pointer>() { |
| int size = sizeOf<IntPtr>(); |
| size = sizeOf<T>(); //# 1300: compile-time error |
| return size; |
| } |
| |
| int size = generic<Pointer<Int64>>(); |
| } |
| |
| void testSizeOfNativeType() { |
| try { |
| sizeOf(); //# 1301: compile-time error |
| } catch (e) { |
| print(e); |
| } |
| } |
| |
| void testElementAtGeneric() { |
| Pointer<T> generic<T extends NativeType>(Pointer<T> pointer) { |
| Pointer<T> returnValue = pointer; |
| returnValue = returnValue.elementAt(1); //# 1310: compile-time error |
| return returnValue; |
| } |
| |
| Pointer<Int8> p = calloc(); |
| p.elementAt(1); |
| generic(p); |
| calloc.free(p); |
| } |
| |
| void testElementAtNativeType() { |
| Pointer<Int8> p = calloc(); |
| p.elementAt(1); |
| Pointer<NativeType> p2 = p; |
| p2.elementAt(1); //# 1311: compile-time error |
| calloc.free(p); |
| } |
| |
| class TestStruct1400 extends Struct { |
| @Array(8) //# 1400: compile-time error |
| @Array(8) |
| external Array<Uint8> a0; |
| } |
| |
| class TestStruct1401 extends Struct { |
| external Array<Uint8> a0; //# 1401: compile-time error |
| |
| external Pointer<Uint8> notEmpty; |
| } |
| |
| class TestStruct1402 extends Struct { |
| @Array(8, 8, 8) //# 1402: compile-time error |
| external Array<Array<Uint8>> a0; //# 1402: compile-time error |
| |
| external Pointer<Uint8> notEmpty; |
| } |
| |
| class TestStruct1403 extends Struct { |
| @Array(8, 8) //# 1403: compile-time error |
| external Array<Array<Array<Uint8>>> a0; //# 1403: compile-time error |
| |
| external Pointer<Uint8> notEmpty; |
| } |
| |
| class TestStruct1404 extends Struct { |
| @Array.multi([8, 8, 8]) //# 1404: compile-time error |
| external Array<Array<Uint8>> a0; //# 1404: compile-time error |
| |
| external Pointer<Uint8> notEmpty; |
| } |
| |
| class TestStruct1405 extends Struct { |
| @Array.multi([8, 8]) //# 1405: compile-time error |
| external Array<Array<Array<Uint8>>> a0; //# 1405: compile-time error |
| |
| external Pointer<Uint8> notEmpty; |
| } |