|  | // 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. | 
|  | // | 
|  | // This program tests interaction with generic Pointers. | 
|  | // | 
|  | // Notation used in following tables: | 
|  | // * static_type//dynamic_type | 
|  | // * P = Pointer | 
|  | // * I = Int8 | 
|  | // * NT = NativeType | 
|  | // | 
|  | // Note #1: When NNBD is landed, implicit downcasts will be static errors. | 
|  | // | 
|  | // Note #2: When we switch to extension methods we will _only_ use the static | 
|  | //          type of the container. | 
|  | // | 
|  | // ===== a.value = b ====== | 
|  | // Does a.value = b, where a and b have specific static and dynamic types: run | 
|  | // fine, fail at compile time, or fail at runtime? | 
|  | // ======================= | 
|  | //                  b     P<I>//P<I>   P<NT>//P<I>           P<NT>//P<NT> | 
|  | // a | 
|  | // P<P<I>>//P<P<I>>     1 ok         2 implicit downcast   3 implicit downcast | 
|  | //                                     of argument:          of argument: | 
|  | //                                     static error          static error | 
|  | // | 
|  | // P<P<NT>>//P<P<I>>    4 ok         5 ok                  6 fail at runtime | 
|  | // | 
|  | // P<P<NT>>//P<P<NT>>   7 ok         8 ok                  9 ok | 
|  | // | 
|  | // ====== final c = a.value ====== | 
|  | // What is the (inferred) static type and runtime type of `a.value`. Note that | 
|  | // we assume extension method here: on Pointer<PointerT>> { Pointer<T> load(); } | 
|  | // ================================ | 
|  | // a                    a.value | 
|  | //                      inferred static type*//runtime type | 
|  | // P<P<I>>//P<P<I>>     P<I>//P<I> | 
|  | // | 
|  | // P<P<NT>>//P<P<I>>    P<NT>//P<I> | 
|  | // | 
|  | // P<P<NT>>//P<P<NT>>   P<NT>//P<NT> | 
|  | // | 
|  | // * The inferred static type when we get extension methods. | 
|  | // | 
|  | // ====== b = a.value ====== | 
|  | // What happens when we try to assign the result of a.value to variable b with | 
|  | // a specific static type: runs fine, fails at compile time, or fails at runtime. | 
|  | // ========================== | 
|  | //                  b     P<I>                        P<NT> | 
|  | // a | 
|  | // P<P<I>>//P<P<I>>     1 ok                        2 ok | 
|  | // | 
|  | // P<P<NT>>//P<P<I>>    3 implicit downcast         4 ok | 
|  | //                        of returnvalue: ok | 
|  | // | 
|  | // P<P<NT>>//P<P<NT>>   5 implicit downcast         6 ok | 
|  | //                        of returnvalue: fail | 
|  | //                        at runtime | 
|  | // | 
|  | // These are the normal Dart assignment rules. | 
|  |  | 
|  | import 'dart:ffi'; | 
|  |  | 
|  | import "package:expect/expect.dart"; | 
|  | import "package:ffi/ffi.dart"; | 
|  |  | 
|  | // ===== a.value = b ====== | 
|  | // The tests follow table cells left to right, top to bottom. | 
|  | void store1() { | 
|  | final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>(); | 
|  | final Pointer<Int8> b = calloc<Int8>(); | 
|  |  | 
|  | a.value = b; | 
|  |  | 
|  | calloc.free(a); | 
|  | calloc.free(b); | 
|  | } | 
|  |  | 
|  | void store2() { | 
|  | final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>(); | 
|  | final Pointer<NativeType> b = | 
|  | calloc<Int8>(); // Reified Pointer<Int8> at runtime. | 
|  |  | 
|  | // Successful implicit downcast of argument at runtime. | 
|  | // Should succeed now, should statically be rejected when NNBD lands. | 
|  | a.value = b as Pointer<Int8>; | 
|  |  | 
|  | calloc.free(a); | 
|  | calloc.free(b); | 
|  | } | 
|  |  | 
|  | void store3() { | 
|  | final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>(); | 
|  | final Pointer<NativeType> b = calloc<Int8>().cast<Pointer<NativeType>>(); | 
|  |  | 
|  | // Type arguments are not reified. | 
|  | a.value = b as Pointer<Int8>; | 
|  |  | 
|  | calloc.free(a); | 
|  | calloc.free(b); | 
|  | } | 
|  |  | 
|  | void store4() { | 
|  | // Type arguments are not reified. | 
|  | final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>(); | 
|  |  | 
|  | final Pointer<Int8> b = calloc<Int8>(); | 
|  |  | 
|  | a.value = b; | 
|  |  | 
|  | calloc.free(a); | 
|  | calloc.free(b); | 
|  | } | 
|  |  | 
|  | void store5() { | 
|  | // Reified as Pointer<Pointer<Int8>> at runtime. | 
|  | final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>(); | 
|  |  | 
|  | final Pointer<NativeType> b = | 
|  | calloc<Int8>(); // Reified as Pointer<Int8> at runtime. | 
|  |  | 
|  | a.value = b; | 
|  |  | 
|  | calloc.free(a); | 
|  | calloc.free(b); | 
|  | } | 
|  |  | 
|  | void store6() { | 
|  | // Reified as Pointer<Pointer<Int8>> at runtime. | 
|  | final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>(); | 
|  | final Pointer<NativeType> b = calloc<Int8>().cast<Pointer<NativeType>>(); | 
|  |  | 
|  | // Type arguments are not reified. | 
|  | a.value = b; | 
|  |  | 
|  | calloc.free(a); | 
|  | calloc.free(b); | 
|  | } | 
|  |  | 
|  | void store7() { | 
|  | final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>(); | 
|  | final Pointer<Int8> b = calloc<Int8>(); | 
|  |  | 
|  | a.value = b; | 
|  |  | 
|  | calloc.free(a); | 
|  | calloc.free(b); | 
|  | } | 
|  |  | 
|  | void store8() { | 
|  | final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>(); | 
|  |  | 
|  | // Type arguments are not reified. | 
|  | final Pointer<NativeType> b = calloc<Int8>(); | 
|  |  | 
|  | a.value = b; | 
|  |  | 
|  | calloc.free(a); | 
|  | calloc.free(b); | 
|  | } | 
|  |  | 
|  | void store9() { | 
|  | final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>(); | 
|  | final Pointer<NativeType> b = calloc<Int8>().cast<Pointer<NativeType>>(); | 
|  |  | 
|  | a.value = b; | 
|  |  | 
|  | calloc.free(a); | 
|  | calloc.free(b); | 
|  | } | 
|  |  | 
|  | // ====== b = a.value ====== | 
|  | // The tests follow table cells left to right, top to bottom. | 
|  | void load1() { | 
|  | final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>(); | 
|  |  | 
|  | Pointer<Int8> b = a.value; | 
|  | Expect.type<Pointer<Int8>>(b); | 
|  |  | 
|  | calloc.free(a); | 
|  | } | 
|  |  | 
|  | void load2() { | 
|  | final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>(); | 
|  |  | 
|  | Pointer<NativeType> b = a.value; | 
|  | Expect.type<Pointer<Int8>>(b); | 
|  |  | 
|  | calloc.free(a); | 
|  | } | 
|  |  | 
|  | void load3() { | 
|  | // Reified as Pointer<Pointer<Int8>> at runtime. | 
|  | final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>(); | 
|  |  | 
|  | Pointer<Int8> b = a.value as Pointer<Int8>; | 
|  | Expect.type<Pointer<Int8>>(b); | 
|  |  | 
|  | calloc.free(a); | 
|  | } | 
|  |  | 
|  | void load4() { | 
|  | // Reified as Pointer<Pointer<Int8>> at runtime. | 
|  | final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>(); | 
|  |  | 
|  | // Return value runtime type is Pointer<Int8>. | 
|  | Pointer<NativeType> b = a.value; | 
|  | Expect.type<Pointer<Int8>>(b); | 
|  |  | 
|  | calloc.free(a); | 
|  | } | 
|  |  | 
|  | void load5() { | 
|  | final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>(); | 
|  |  | 
|  | // Type arguments are not reified. | 
|  | // ignore: unused_local_variable | 
|  | Pointer<Int8> b = a.value as Pointer<Int8>; | 
|  |  | 
|  | calloc.free(a); | 
|  | } | 
|  |  | 
|  | void load6() { | 
|  | final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>(); | 
|  |  | 
|  | Pointer<NativeType> b = a.value; | 
|  | Expect.type<Pointer<NativeType>>(b); | 
|  |  | 
|  | calloc.free(a); | 
|  | } | 
|  |  | 
|  | void main() { | 
|  | for (int i = 0; i < 100; i++) { | 
|  | store1(); | 
|  | store2(); | 
|  | store3(); | 
|  | store4(); | 
|  | store5(); | 
|  | store6(); | 
|  | store7(); | 
|  | store8(); | 
|  | store9(); | 
|  | load1(); | 
|  | load2(); | 
|  | load3(); | 
|  | load4(); | 
|  | load5(); | 
|  | load6(); | 
|  | } | 
|  | } |