// 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//P P//P P//P // a // P>//P> 1 ok 2 implicit downcast 3 implicit downcast // of argument: of argument: // static error static error // // P>//P> 4 ok 5 ok 6 fail at runtime // // P>//P> 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> { Pointer load(); } // ================================ // a a.value // inferred static type*//runtime type // P>//P> P//P // // P>//P> P//P // // P>//P> P//P // // * 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 P // a // P>//P> 1 ok 2 ok // // P>//P> 3 implicit downcast 4 ok // of returnvalue: ok // // P>//P> 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> a = calloc>(); final Pointer b = calloc(); a.value = b; calloc.free(a); calloc.free(b); } void store2() { final Pointer> a = calloc>(); final Pointer b = calloc(); // Reified Pointer at runtime. // Successful implicit downcast of argument at runtime. // Should succeed now, should statically be rejected when NNBD lands. a.value = b as Pointer; calloc.free(a); calloc.free(b); } void store3() { final Pointer> a = calloc>(); final Pointer b = calloc().cast>(); // Failing implicit downcast of argument at runtime. // Should fail now at runtime, should statically be rejected when NNBD lands. Expect.throws(() { a.value = b as Pointer; }); calloc.free(a); calloc.free(b); } void store4() { // Reified as Pointer> at runtime. final Pointer> a = calloc>(); final Pointer b = calloc(); a.value = b; calloc.free(a); calloc.free(b); } void store5() { // Reified as Pointer> at runtime. final Pointer> a = calloc>(); final Pointer b = calloc(); // Reified as Pointer at runtime. a.value = b; calloc.free(a); calloc.free(b); } void store6() { // Reified as Pointer> at runtime. final Pointer> a = calloc>(); final Pointer b = calloc().cast>(); // Fails on type check of argument. Expect.throws(() { a.value = b; }); calloc.free(a); calloc.free(b); } void store7() { final Pointer> a = calloc>(); final Pointer b = calloc(); a.value = b; calloc.free(a); calloc.free(b); } void store8() { final Pointer> a = calloc>(); // Reified as Pointer at runtime. final Pointer b = calloc(); a.value = b; calloc.free(a); calloc.free(b); } void store9() { final Pointer> a = calloc>(); final Pointer b = calloc().cast>(); 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> a = calloc>(); Pointer b = a.value; Expect.type>(b); calloc.free(a); } void load2() { final Pointer> a = calloc>(); Pointer b = a.value; Expect.type>(b); calloc.free(a); } void load3() { // Reified as Pointer> at runtime. final Pointer> a = calloc>(); Pointer b = a.value as Pointer; Expect.type>(b); calloc.free(a); } void load4() { // Reified as Pointer> at runtime. final Pointer> a = calloc>(); // Return value runtime type is Pointer. Pointer b = a.value; Expect.type>(b); calloc.free(a); } void load5() { final Pointer> a = calloc>(); // Failing implicit downcast of return value at runtime. // Should fail now at runtime, should statically be rejected when NNBD lands. Expect.throws(() { Pointer b = a.value as Pointer; }); calloc.free(a); } void load6() { final Pointer> a = calloc>(); Pointer b = a.value; Expect.type>(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(); } }