diff options
author | Carter Snook <cartersnook04@gmail.com> | 2022-06-27 07:41:58 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-27 18:11:58 +0530 |
commit | 89fc24086142d019c9fad75fad31f97b21e0de73 (patch) | |
tree | c800c5cadd5bc4d9280769eff4b69d5130ce90e4 | |
parent | 2d1c48ce171b32eb24a8438d9056ff46c44c1be8 (diff) |
fix(dts/ffi): non-exact types break FFI inference (#14968)
-rw-r--r-- | cli/dts/lib.deno.unstable.d.ts | 71 | ||||
-rw-r--r-- | 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 643386ced..ab6f8634f 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -362,49 +362,60 @@ declare namespace Deno { export type NativeResultType = NativeType | NativeVoidType; + type ToNativeTypeMap = + & Record<NativeNumberType, number> + & Record<NativeBigIntType, bigint | number> + & Record<NativePointerType, TypedArray | bigint | null> + & Record<NativeFunctionType, bigint | null>; + /** Type conversion for foreign symbol parameters and unsafe callback return types */ - type ToNativeType<T extends NativeType = NativeType> = T extends - NativeNumberType ? number - : T extends NativeBigIntType ? bigint | number - : T extends NativePointerType ? TypedArray | bigint | null - : T extends NativeFunctionType ? bigint | null - : never; + type ToNativeType<T extends NativeType = NativeType> = ToNativeTypeMap[T]; + + type ToNativeResultTypeMap = ToNativeTypeMap & Record<NativeVoidType, void>; /** Type conversion for unsafe callback return types */ type ToNativeResultType<T extends NativeResultType = NativeResultType> = - T extends NativeType ? ToNativeType<T> - : T extends NativeVoidType ? void + ToNativeResultTypeMap[T]; + + type ToNativeParameterTypes<T extends readonly NativeType[]> = + // + [(T[number])[]] extends [T] ? ToNativeType<T[number]>[] + : [readonly (T[number])[]] extends [T] + ? readonly ToNativeType<T[number]>[] + : T extends readonly [...NativeType[]] ? { + [K in keyof T]: ToNativeType<T[K]>; + } : never; - type ToNativeParameterTypes<T extends readonly NativeType[]> = T extends - readonly [] ? [] - : T extends readonly [ - infer U extends NativeType, - ...(infer V extends NativeType[]), - ] ? [ToNativeType<U>, ...ToNativeParameterTypes<V>] - : never; + type FromNativeTypeMap = + & Record<NativeNumberType, number> + & Record<NativeBigIntType, bigint> + & Record<NativePointerType, bigint> + & Record<NativeFunctionType, bigint>; /** Type conversion for foreign symbol return types and unsafe callback parameters */ - type FromNativeType<T extends NativeType = NativeType> = T extends - NativeNumberType ? number - : T extends NativeBigIntType | NativePointerType | NativeFunctionType - ? bigint - : never; + type FromNativeType<T extends NativeType = NativeType> = FromNativeTypeMap[T]; + + type FromNativeResultTypeMap = + & FromNativeTypeMap + & Record<NativeVoidType, void>; /** Type conversion for foregin symbol return types */ type FromNativeResultType<T extends NativeResultType = NativeResultType> = - T extends NativeType ? FromNativeType<T> - : T extends NativeVoidType ? void + FromNativeResultTypeMap[T]; + + type FromNativeParameterTypes< + T extends readonly NativeType[], + > = + // + [(T[number])[]] extends [T] ? FromNativeType<T[number]>[] + : [readonly (T[number])[]] extends [T] + ? readonly FromNativeType<T[number]>[] + : T extends readonly [...NativeType[]] ? { + [K in keyof T]: FromNativeType<T[K]>; + } : never; - type FromNativeParameterTypes<T extends readonly NativeType[]> = T extends - readonly [] ? [] - : T extends readonly [ - infer U extends NativeType, - ...(infer V extends NativeType[]), - ] ? [FromNativeType<U>, ...FromNativeParameterTypes<V>] - : never; - /** A foreign function as defined by its parameter and result types */ export interface ForeignFunction< Parameters extends readonly NativeType[] = readonly NativeType[], diff --git a/test_ffi/tests/ffi_types.ts b/test_ffi/tests/ffi_types.ts index 742f92748..dde08155d 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<T, U> = (<G>() => G extends T ? 1 : 2) extends + (<G>() => G extends U ? 1 : 2) ? true + : false; + +type AssertEqual< + Expected extends $, + Got extends $$, + $ = [Equal<Got, Expected>] extends [true] ? Expected + : ([Expected] extends [Got] ? never : Got), + $$ = [Equal<Expected, Got>] extends [true] ? Got + : ([Got] extends [Expected] ? never : Got), +> = never; + +type AssertNotEqual< + Expected extends $, + Got, + $ = [Equal<Expected, Got>] extends [true] ? never : Expected, +> = never; + +type TypedArray = + | Int8Array + | Uint8Array + | Int16Array + | Uint16Array + | Int32Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | BigInt64Array + | BigUint64Array; + +type __Tests__ = [ + empty: AssertEqual< + { symbols: Record<never, never>; close(): void }, + Deno.DynamicLibrary<Record<never, never>> + >, + 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" } } + > + >, +]; |