5b4c930272
Change-Id: I6e8bcfe8b8ad19726f5ccf9b64b3b45eec2d33ce Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/120793 Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Daco Harkes <dacoharkes@google.com>
70 lines
2.9 KiB
Markdown
70 lines
2.9 KiB
Markdown
# 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`.
|