| # FFI static checks |
| |
| ## Translating FFI types |
| |
| The FFI library defines a number of "native" types, which have corresponding |
| Dart types. This is a many-to-one mapping, defined by `DartRepresentationOf` in |
| `native_type.dart`. |
| |
| ## Subtyping restrictions |
| |
| No class may extend, implement or mixin any classes inside the FFI library, with |
| the following exception. Any class may extend (but not implement or mixin) |
| `ffi.Struct`. In this case, the subclass is considered a *struct class*. No |
| class may extend, implement or mixin a struct class. |
| |
| ## Struct rules |
| |
| The following restrictions apply to struct classes: |
| |
| - A struct class must not be generic. |
| - A struct class `X` must extend `Struct<X>`. That is, the type argument to the |
| superclass must be exactly the subclass itself. |
| |
| Some restrictions apply to fields of struct classes: |
| |
| - A field of a struct class must not have an initializer. |
| - A field of a struct class must either have a type which is a subtype of |
| `ffi.Pointer` or else be annotated by one of the following types: |
| - `ffi.UintN` or `ffi.IntN` for any N |
| - `ffi.Float` or `ffi.Double` |
| If the field is annotated, the Dart version of the annotated type must be |
| identical to the field's declared type. Note that struct classes currently |
| must not be used as fields. |
| - A field of a struct class must not have more than one annotation corresponding |
| to an FFI native type. |
| |
| Finally, struct classes must not have constructors with field initializers. |
| |
| ## `fromFunction` rules |
| |
| The following restrictions apply to static invocations of the factory |
| constructor `Pointer<T>.fromFunction(f, e)`. Dynamic invocations of this method, |
| e.g. through mirrors, are runtime errors. `T` must be a subtype of |
| `NativeFunction<T'>` for some `T'`. Let `F` be the Dart type which corresponds |
| to static type of `T'` and `R` be the return type of `F`. |
| |
| - `T` must be instantiated; i.e., it must not reference any class or function |
| type parameters. |
| - The static type of `f` must be a subtype of `F`. |
| - Struct classes are not allowed as the top-level class in a parameter or return |
| type of `F`. |
| - The static type of `e` must be a subtype of `R`. |
| - `e` must be an expression which is legal in a constant context. |
| - `f` must be a direct reference to a top-level method. |
| - `e` must not be provided if `R` is `void` or `ffi.Pointer`. |
| - `e` must be provided otherwise. |
| |
| ## `asFunction` and `lookupFunction ` rules |
| |
| The following restrictions apply to statically resolved invocations of the |
| instance method `Pointer<T>.asFunction<F>()` and |
| `DynamicLibrary.lookupFunction<S, F>()`. Dynamic invocations of these methods, |
| e.g. through mirrors or a receiver of static type `dynamic`, are runtime errors. |
| `T` must be a subtype of `NativeFunction<T'>` for some `T'`. Let `F'` be the |
| Dart type which corresponds to static type of `T'`/`S`. |
| |
| - `T`, `S` and `F` must be constants; i.e., they must not reference any class or |
| function type parameters. |
| - `F'` must be a subtype of `F`. |