From cbe9d79f56b49e25cde9c7a2883031d8c7aec563 Mon Sep 17 00:00:00 2001 From: Carter Snook Date: Mon, 27 Jun 2022 07:41:58 -0500 Subject: [PATCH] fix(dts/ffi): non-exact types break FFI inference (#14968) --- cli/dts/lib.deno.unstable.d.ts | 71 +++++++++++++---------- test_ffi/tests/ffi_types.ts | 102 +++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 30 deletions(-) diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index 643386ced4..ab6f8634f6 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -362,48 +362,59 @@ declare namespace Deno { export type NativeResultType = NativeType | NativeVoidType; + type ToNativeTypeMap = + & Record + & Record + & Record + & Record; + /** Type conversion for foreign symbol parameters and unsafe callback return types */ - type ToNativeType = T extends - NativeNumberType ? number - : T extends NativeBigIntType ? bigint | number - : T extends NativePointerType ? TypedArray | bigint | null - : T extends NativeFunctionType ? bigint | null - : never; + type ToNativeType = ToNativeTypeMap[T]; + + type ToNativeResultTypeMap = ToNativeTypeMap & Record; /** Type conversion for unsafe callback return types */ type ToNativeResultType = - T extends NativeType ? ToNativeType - : T extends NativeVoidType ? void + ToNativeResultTypeMap[T]; + + type ToNativeParameterTypes = + // + [(T[number])[]] extends [T] ? ToNativeType[] + : [readonly (T[number])[]] extends [T] + ? readonly ToNativeType[] + : T extends readonly [...NativeType[]] ? { + [K in keyof T]: ToNativeType; + } : never; - type ToNativeParameterTypes = T extends - readonly [] ? [] - : T extends readonly [ - infer U extends NativeType, - ...(infer V extends NativeType[]), - ] ? [ToNativeType, ...ToNativeParameterTypes] - : never; + type FromNativeTypeMap = + & Record + & Record + & Record + & Record; /** Type conversion for foreign symbol return types and unsafe callback parameters */ - type FromNativeType = T extends - NativeNumberType ? number - : T extends NativeBigIntType | NativePointerType | NativeFunctionType - ? bigint - : never; + type FromNativeType = FromNativeTypeMap[T]; + + type FromNativeResultTypeMap = + & FromNativeTypeMap + & Record; /** Type conversion for foregin symbol return types */ type FromNativeResultType = - T extends NativeType ? FromNativeType - : T extends NativeVoidType ? void - : never; + FromNativeResultTypeMap[T]; - type FromNativeParameterTypes = T extends - readonly [] ? [] - : T extends readonly [ - infer U extends NativeType, - ...(infer V extends NativeType[]), - ] ? [FromNativeType, ...FromNativeParameterTypes] - : never; + type FromNativeParameterTypes< + T extends readonly NativeType[], + > = + // + [(T[number])[]] extends [T] ? FromNativeType[] + : [readonly (T[number])[]] extends [T] + ? readonly FromNativeType[] + : T extends readonly [...NativeType[]] ? { + [K in keyof T]: FromNativeType; + } + : never; /** A foreign function as defined by its parameter and result types */ export interface ForeignFunction< diff --git a/test_ffi/tests/ffi_types.ts b/test_ffi/tests/ffi_types.ts index 742f92748e..dde08155d1 100644 --- a/test_ffi/tests/ffi_types.ts +++ b/test_ffi/tests/ffi_types.ts @@ -285,3 +285,105 @@ const static13_right: number = remote.symbols.static13; // @ts-expect-error: Invalid member type const static14_wrong: null = remote.symbols.static14; const static14_right: number = remote.symbols.static14; + +// Adapted from https://stackoverflow.com/a/53808212/10873797 +type Equal = (() => G extends T ? 1 : 2) extends + (() => G extends U ? 1 : 2) ? true + : false; + +type AssertEqual< + Expected extends $, + Got extends $$, + $ = [Equal] extends [true] ? Expected + : ([Expected] extends [Got] ? never : Got), + $$ = [Equal] extends [true] ? Got + : ([Got] extends [Expected] ? never : Got), +> = never; + +type AssertNotEqual< + Expected extends $, + Got, + $ = [Equal] extends [true] ? never : Expected, +> = never; + +type TypedArray = + | Int8Array + | Uint8Array + | Int16Array + | Uint16Array + | Int32Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | BigInt64Array + | BigUint64Array; + +type __Tests__ = [ + empty: AssertEqual< + { symbols: Record; close(): void }, + Deno.DynamicLibrary> + >, + basic: AssertEqual< + { symbols: { add: (n1: number, n2: number) => number }; close(): void }, + Deno.DynamicLibrary<{ add: { parameters: ["i32", "u8"]; result: "i32" } }> + >, + higher_order_params: AssertEqual< + { + symbols: { + pushBuf: (ptr: bigint | TypedArray | null, func: bigint | null) => void; + }; + close(): void; + }, + Deno.DynamicLibrary< + { pushBuf: { parameters: ["pointer", "function"]; result: "void" } } + > + >, + higher_order_returns: AssertEqual< + { + symbols: { + pushBuf: ( + ptr: bigint | TypedArray | null, + func: bigint | null, + ) => bigint; + }; + close(): void; + }, + Deno.DynamicLibrary< + { pushBuf: { parameters: ["pointer", "function"]; result: "pointer" } } + > + >, + non_exact_params: AssertEqual< + { + symbols: { + foo: (...args: (number | bigint | TypedArray | null)[]) => bigint; + }; + close(): void; + }, + Deno.DynamicLibrary< + { foo: { parameters: ("i32" | "pointer")[]; result: "u64" } } + > + >, + non_exact_params_empty: AssertEqual< + { + symbols: { + foo: () => number; + }; + close(): void; + }, + Deno.DynamicLibrary< + { foo: { parameters: []; result: "i32" } } + > + >, + non_exact_params_empty: AssertNotEqual< + { + symbols: { + foo: (a: number) => number; + }; + close(): void; + }, + Deno.DynamicLibrary< + { foo: { parameters: []; result: "i32" } } + > + >, +];