Skip to content

Commit

Permalink
Add math intrinsic types
Browse files Browse the repository at this point in the history
  • Loading branch information
skeate committed Jun 1, 2024
1 parent ef514af commit 526f96a
Show file tree
Hide file tree
Showing 15 changed files with 2,032 additions and 820 deletions.
186 changes: 163 additions & 23 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6222,6 +6222,7 @@ export const enum TypeFlags {
Reserved1 = 1 << 29, // Used by union/intersection type construction
/** @internal */
Reserved2 = 1 << 30, // Used by union/intersection type construction
Calculation = 1 << 31, // Math type

/** @internal */
AnyOrUnknown = Any | Unknown,
Expand All @@ -6239,7 +6240,7 @@ export const enum TypeFlags {
/** @internal */
Intrinsic = Any | Unknown | String | Number | BigInt | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive,
StringLike = String | StringLiteral | TemplateLiteral | StringMapping,
NumberLike = Number | NumberLiteral | Enum,
NumberLike = Number | NumberLiteral | Enum | Calculation,
BigIntLike = BigInt | BigIntLiteral,
BooleanLike = Boolean | BooleanLiteral,
EnumLike = Enum | EnumLiteral,
Expand All @@ -6255,7 +6256,7 @@ export const enum TypeFlags {
StructuredType = Object | Union | Intersection,
TypeVariable = TypeParameter | IndexedAccess,
InstantiableNonPrimitive = TypeVariable | Conditional | Substitution,
InstantiablePrimitive = Index | TemplateLiteral | StringMapping,
InstantiablePrimitive = Index | TemplateLiteral | StringMapping | Calculation,
Instantiable = InstantiableNonPrimitive | InstantiablePrimitive,
StructuredOrInstantiable = StructuredType | Instantiable,
/** @internal */
Expand Down Expand Up @@ -6826,6 +6827,11 @@ export interface StringMappingType extends InstantiableType {
type: Type;
}

export interface CalculationType extends InstantiableType {
symbol: Symbol;
types: [Type] | [Type, Type];
}

// Type parameter substitution (TypeFlags.Substitution)
// Substitution types are created for type parameters or indexed access types that occur in the
// true branch of a conditional type. For example, in 'T extends string ? Foo<T> : Bar<T>', the
Expand Down
5 changes: 5 additions & 0 deletions src/harness/fourslashInterfaceImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,11 @@ export namespace Completion {
typeEntry("Lowercase"),
typeEntry("Capitalize"),
typeEntry("Uncapitalize"),
typeEntry("Integer"),
typeEntry("Add"),
typeEntry("Subtract"),
typeEntry("Multiply"),
typeEntry("Divide"),
typeEntry("NoInfer"),
interfaceEntry("ThisType"),
varEntry("ArrayBuffer"),
Expand Down
25 changes: 25 additions & 0 deletions src/lib/es5.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,31 @@ type Capitalize<S extends string> = intrinsic;
*/
type Uncapitalize<S extends string> = intrinsic;

/**
* Convert number literal type to integer
*/
type Integer<N extends number> = intrinsic;

/**
* Add two literal numbers
*/
type Add<M extends number, N extends number> = intrinsic;

/**
* Subtract two literal numbers
*/
type Subtract<M extends number, N extends number> = intrinsic;

/**
* Multiply two literal numbers
*/
type Multiply<M extends number, N extends number> = intrinsic;

/**
* Divide two literal numbers
*/
type Divide<M extends number, N extends number> = intrinsic;

/**
* Marker for non-inference type position
*/
Expand Down
2 changes: 0 additions & 2 deletions tests/baselines/reference/intrinsicTypes.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ intrinsicTypes.ts(43,5): error TS2322: Type 'Uppercase<T>' is not assignable to
Type 'T' is not assignable to type 'U'.
'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'string'.


==== intrinsicTypes.ts (8 errors) ====
type TU1 = Uppercase<'hello'>; // "HELLO"
type TU2 = Uppercase<'foo' | 'bar'>; // "FOO" | "BAR"
type TU3 = Uppercase<string>; // Uppercase<string>
Expand Down
207 changes: 207 additions & 0 deletions tests/baselines/reference/intrinsicTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,113 @@ declare function foo3<T extends string>(x: Uppercase<T>): T;
function foo4<U extends string>(x: Uppercase<U>) {
return foo3(x);
}

type TI1 = Integer<3.5>; // 3
type TI2 = Integer<2.5 | 3.4>; // 2 | 3
type TI3 = Integer<number>; // number
type TI4 = Integer<any>; // any
type TI5 = Integer<never>; // never
type TI6 = Integer<'42'>; // Error

type TA1 = Add<4, 2>; // 6
type TA2L = Add<4 | 5, 2>; // 6 | 7
type TA2R = Add<4, 2 | 3>; // 6 | 7
type TA2LR = Add<4 | 5, 2 | 3>; // 6 | 7 | 8
type TA3L = Add<number, 2>; // number
type TA3R = Add<4, number>; // number
type TA3LR = Add<number, number>; // number
type TA4L = Add<any, 2>; // any
type TA4R = Add<4, any>; // any
type TA4LR = Add<any, any>; // any
type TA5L = Add<never, 2>; // never
type TA5R = Add<4, never>; // never
type TA5LR = Add<never, never>; // never
type TA6L = Add<'4', 2>; // Error
type TA6R = Add<4, '2'>; // Error
type TA6LR = Add<'4', '2'>; // Error

type TS1 = Subtract<4, 2>; // 2
type TS2L = Subtract<4 | 5, 2>; // 2 | 3
type TS2R = Subtract<4, 2 | 3>; // 2 | 1
type TS2LR = Subtract<4 | 5, 2 | 3>; // 2 | 1 | 3
type TS3L = Subtract<number, 2>; // number
type TS3R = Subtract<4, number>; // number
type TS3LR = Subtract<number, number>; // number
type TS4L = Subtract<any, 2>; // any
type TS4R = Subtract<4, any>; // any
type TS4LR = Subtract<any, any>; // any
type TS5L = Subtract<never, 2>; // never
type TS5R = Subtract<4, never>; // never
type TS5LR = Subtract<never, never>; // never
type TS6L = Subtract<'4', 2>; // Error
type TS6R = Subtract<4, '2'>; // Error
type TS6LR = Subtract<'4', '2'>; // Error

type TM1 = Multiply<4, 2>; // 8
type TM2L = Multiply<4 | 5, 2>; // 8 | 10
type TM2R = Multiply<4, 2 | 3>; // 8 | 12
type TM2LR = Multiply<4 | 5, 2 | 3>; // 8 | 12 | 10 | 15
type TM3L = Multiply<number, 2>; // number
type TM3R = Multiply<4, number>; // number
type TM3LR = Multiply<number, number>; // number
type TM4L = Multiply<any, 2>; // any
type TM4R = Multiply<4, any>; // any
type TM4LR = Multiply<any, any>; // any
type TM5L = Multiply<never, 2>; // never
type TM5R = Multiply<4, never>; // never
type TM5LR = Multiply<never, never>; // never
type TM6L = Multiply<'4', 2>; // Error
type TM6R = Multiply<4, '2'>; // Error
type TM6LR = Multiply<'4', '2'>; // Error

type TD1 = Divide<4, 2>; // 2
type TD2L = Divide<4 | 5, 2>; // 2 | 2.5
type TD2R = Divide<4, 2 | 4>; // 2 | 1
type TD2LR = Divide<4 | 5, 2 | 4>; // 2 | 1 | 2.5 | 1.25
type TD3L = Divide<number, 2>; // number
type TD3R = Divide<4, number>; // number
type TD3LR = Divide<number, number>; // number
type TD4L = Divide<any, 2>; // any
type TD4R = Divide<4, any>; // any
type TD4LR = Divide<any, any>; // any
type TD5L = Divide<never, 2>; // never
type TD5R = Divide<4, never>; // never
type TD5LR = Divide<never, never>; // never
type TD6L = Divide<'4', 2>; // Error
type TD6R = Divide<4, '2'>; // Error
type TD6LR = Divide<'4', '2'>; // Error
type TD7 = Divide<1, 0>; // never

type TIX1<S extends number> = Integer<S>;
type TIX2 = TIX1<4.2>; // 4
type TAX1<M extends number, N extends number> = Add<M, N>;
type TAX2 = TAX1<4, 2>; // 6
type TSX1<M extends number, N extends number> = Subtract<M, N>;
type TSX2 = TSX1<4, 2>; // 6
type TMX1<M extends number, N extends number> = Multiply<M, N>;
type TMX2 = TMX1<4, 2>; // 8
type TDX1<M extends number, N extends number> = Divide<M, N>;
type TDX2 = TDX1<4, 2>; // 2
type TAMX = Add<2, Multiply<5, 8>> // 42

function foo5<T extends number, U extends T>(s: number, x: Add<T, U>, y: Multiply<T, U>) {
s = x;
s = y;
x = s; // Error
x = y; // Error
y = s; // Error
y = x; // Error
}

function foo6<T extends 0 | 1>(x: Add<T, 3>) {
let s: 3 | 4 = x;
}

declare function foo7<T extends number>(x: Integer<T>): T;

function foo8<U extends number>(x: Integer<U>) {
return foo7(x);
}


//// [intrinsicTypes.js]
Expand All @@ -73,6 +180,20 @@ function foo2(x) {
function foo4(x) {
return foo3(x);
}
function foo5(s, x, y) {
s = x;
s = y;
x = s; // Error
x = y; // Error
y = s; // Error
y = x; // Error
}
function foo6(x) {
var s = x;
}
function foo8(x) {
return foo7(x);
}


//// [intrinsicTypes.d.ts]
Expand Down Expand Up @@ -110,3 +231,89 @@ declare function foo1<T extends string, U extends T>(s: string, x: Uppercase<T>,
declare function foo2<T extends 'foo' | 'bar'>(x: Uppercase<T>): void;
declare function foo3<T extends string>(x: Uppercase<T>): T;
declare function foo4<U extends string>(x: Uppercase<U>): U;
declare type TI1 = Integer<3.5>;
declare type TI2 = Integer<2.5 | 3.4>;
declare type TI3 = Integer<number>;
declare type TI4 = Integer<any>;
declare type TI5 = Integer<never>;
declare type TI6 = Integer<'42'>;
declare type TA1 = Add<4, 2>;
declare type TA2L = Add<4 | 5, 2>;
declare type TA2R = Add<4, 2 | 3>;
declare type TA2LR = Add<4 | 5, 2 | 3>;
declare type TA3L = Add<number, 2>;
declare type TA3R = Add<4, number>;
declare type TA3LR = Add<number, number>;
declare type TA4L = Add<any, 2>;
declare type TA4R = Add<4, any>;
declare type TA4LR = Add<any, any>;
declare type TA5L = Add<never, 2>;
declare type TA5R = Add<4, never>;
declare type TA5LR = Add<never, never>;
declare type TA6L = Add<'4', 2>;
declare type TA6R = Add<4, '2'>;
declare type TA6LR = Add<'4', '2'>;
declare type TS1 = Subtract<4, 2>;
declare type TS2L = Subtract<4 | 5, 2>;
declare type TS2R = Subtract<4, 2 | 3>;
declare type TS2LR = Subtract<4 | 5, 2 | 3>;
declare type TS3L = Subtract<number, 2>;
declare type TS3R = Subtract<4, number>;
declare type TS3LR = Subtract<number, number>;
declare type TS4L = Subtract<any, 2>;
declare type TS4R = Subtract<4, any>;
declare type TS4LR = Subtract<any, any>;
declare type TS5L = Subtract<never, 2>;
declare type TS5R = Subtract<4, never>;
declare type TS5LR = Subtract<never, never>;
declare type TS6L = Subtract<'4', 2>;
declare type TS6R = Subtract<4, '2'>;
declare type TS6LR = Subtract<'4', '2'>;
declare type TM1 = Multiply<4, 2>;
declare type TM2L = Multiply<4 | 5, 2>;
declare type TM2R = Multiply<4, 2 | 3>;
declare type TM2LR = Multiply<4 | 5, 2 | 3>;
declare type TM3L = Multiply<number, 2>;
declare type TM3R = Multiply<4, number>;
declare type TM3LR = Multiply<number, number>;
declare type TM4L = Multiply<any, 2>;
declare type TM4R = Multiply<4, any>;
declare type TM4LR = Multiply<any, any>;
declare type TM5L = Multiply<never, 2>;
declare type TM5R = Multiply<4, never>;
declare type TM5LR = Multiply<never, never>;
declare type TM6L = Multiply<'4', 2>;
declare type TM6R = Multiply<4, '2'>;
declare type TM6LR = Multiply<'4', '2'>;
declare type TD1 = Divide<4, 2>;
declare type TD2L = Divide<4 | 5, 2>;
declare type TD2R = Divide<4, 2 | 4>;
declare type TD2LR = Divide<4 | 5, 2 | 4>;
declare type TD3L = Divide<number, 2>;
declare type TD3R = Divide<4, number>;
declare type TD3LR = Divide<number, number>;
declare type TD4L = Divide<any, 2>;
declare type TD4R = Divide<4, any>;
declare type TD4LR = Divide<any, any>;
declare type TD5L = Divide<never, 2>;
declare type TD5R = Divide<4, never>;
declare type TD5LR = Divide<never, never>;
declare type TD6L = Divide<'4', 2>;
declare type TD6R = Divide<4, '2'>;
declare type TD6LR = Divide<'4', '2'>;
declare type TD7 = Divide<1, 0>;
declare type TIX1<S extends number> = Integer<S>;
declare type TIX2 = TIX1<4.2>;
declare type TAX1<M extends number, N extends number> = Add<M, N>;
declare type TAX2 = TAX1<4, 2>;
declare type TSX1<M extends number, N extends number> = Subtract<M, N>;
declare type TSX2 = TSX1<4, 2>;
declare type TMX1<M extends number, N extends number> = Multiply<M, N>;
declare type TMX2 = TMX1<4, 2>;
declare type TDX1<M extends number, N extends number> = Divide<M, N>;
declare type TDX2 = TDX1<4, 2>;
declare type TAMX = Add<2, Multiply<5, 8>>;
declare function foo5<T extends number, U extends T>(s: number, x: Add<T, U>, y: Multiply<T, U>): void;
declare function foo6<T extends 0 | 1>(x: Add<T, 3>): void;
declare function foo7<T extends number>(x: Integer<T>): T;
declare function foo8<U extends number>(x: Integer<U>): U;
Loading

0 comments on commit 526f96a

Please sign in to comment.