blob: ed1ce4186acb148828d335aa8195515929d6f421 [file] [log] [blame] [view]
# 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`.