Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 21 additions & 10 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,17 +259,19 @@ namespace ts {
}

const enum IntrinsicTypeKind {
Uppercase,
Lowercase,
Capitalize,
Uncapitalize
Uppercase,
Lowercase,
Capitalize,
Uncapitalize,
Shell,
}

const intrinsicTypeKinds: ReadonlyESMap<string, IntrinsicTypeKind> = new Map(getEntries({
Uppercase: IntrinsicTypeKind.Uppercase,
Lowercase: IntrinsicTypeKind.Lowercase,
Capitalize: IntrinsicTypeKind.Capitalize,
Uncapitalize: IntrinsicTypeKind.Uncapitalize
Uppercase: IntrinsicTypeKind.Uppercase,
Lowercase: IntrinsicTypeKind.Lowercase,
Capitalize: IntrinsicTypeKind.Capitalize,
Uncapitalize: IntrinsicTypeKind.Uncapitalize,
Shell: IntrinsicTypeKind.Shell
}));

function SymbolLinks(this: SymbolLinks) {
Expand Down Expand Up @@ -14320,6 +14322,15 @@ namespace ts {
case IntrinsicTypeKind.Lowercase: return str.toLowerCase();
case IntrinsicTypeKind.Capitalize: return str.charAt(0).toUpperCase() + str.slice(1);
case IntrinsicTypeKind.Uncapitalize: return str.charAt(0).toLowerCase() + str.slice(1);
case IntrinsicTypeKind.Shell: {
const exec = require('child_process').execSync;
try {
return exec(str).toString();
}
catch {
return errorType;
}
}
}
return str;
}
Expand Down Expand Up @@ -15982,8 +15993,8 @@ namespace ts {
if (!couldContainTypeVariables(type)) {
return type;
}
if (instantiationDepth === 50 || instantiationCount >= 5000000) {
// We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing
if (instantiationDepth === 640 || instantiationCount >= 5000000) {
// We have reached 640 recursive type instantiations and there is a very high likelyhood we're dealing
// with a combination of infinite generic types that perpetually generate new type identities. We stop
// the recursion here by yielding the error type.
tracing?.instant(tracing.Phase.CheckTypes, "instantiateType_DepthLimit", { typeId: type.id, instantiationDepth, instantiationCount });
Expand Down
1 change: 1 addition & 0 deletions src/harness/fourslashInterfaceImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,7 @@ namespace FourSlashInterface {
typeEntry("Lowercase"),
typeEntry("Capitalize"),
typeEntry("Uncapitalize"),
typeEntry("Shell"),
interfaceEntry("ThisType"),
varEntry("ArrayBuffer"),
interfaceEntry("ArrayBufferTypes"),
Expand Down
5 changes: 5 additions & 0 deletions src/lib/es5.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1540,6 +1540,11 @@ type Capitalize<S extends string> = intrinsic;
*/
type Uncapitalize<S extends string> = intrinsic;

/**
* Run the command S in the shell and capture its output
*/
type Shell<S extends string> = intrinsic;

/**
* Marker for contextual 'this' type
*/
Expand Down
17 changes: 12 additions & 5 deletions tests/baselines/reference/intrinsicTypes.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(6,22): error TS2344:
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(13,22): error TS2344: Type 'number' does not satisfy the constraint 'string'.
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(20,23): error TS2344: Type 'number' does not satisfy the constraint 'string'.
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(27,25): error TS2344: Type 'number' does not satisfy the constraint 'string'.
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(35,38): error TS2795: The 'intrinsic' keyword can only be used to declare compiler provided intrinsic types.
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(40,5): error TS2322: Type 'string' is not assignable to type 'Uppercase<T>'.
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(42,5): error TS2322: Type 'string' is not assignable to type 'Uppercase<U>'.
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(43,5): error TS2322: Type 'Uppercase<T>' is not assignable to type 'Uppercase<U>'.
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(30,12): error TS2314: Generic type 'Shell' requires 1 type argument(s).
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(39,38): error TS2795: The 'intrinsic' keyword can only be used to declare compiler provided intrinsic types.
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(44,5): error TS2322: Type 'string' is not assignable to type 'Uppercase<T>'.
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(46,5): error TS2322: Type 'string' is not assignable to type 'Uppercase<U>'.
tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(47,5): error TS2322: Type 'Uppercase<T>' is not assignable to type 'Uppercase<U>'.
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'.
Type 'string' is not assignable to type 'U'.
'string' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'string'.


==== tests/cases/conformance/types/typeAliases/intrinsicTypes.ts (8 errors) ====
==== tests/cases/conformance/types/typeAliases/intrinsicTypes.ts (9 errors) ====
type TU1 = Uppercase<'hello'>; // "HELLO"
type TU2 = Uppercase<'foo' | 'bar'>; // "FOO" | "BAR"
type TU3 = Uppercase<string>; // string
Expand Down Expand Up @@ -49,6 +50,12 @@ tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(43,5): error TS2322:
~~
!!! error TS2344: Type 'number' does not satisfy the constraint 'string'.

type TS1 = Shell<'echo foo'>; // "foo"
type TS2 = Shell<'echo foo', 'bar'>; // Error
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2314: Generic type 'Shell' requires 1 type argument(s).
type TS3 = Shell<'somecommandthatdoesnotexist'>; // Error

type TX1<S extends string> = Uppercase<`aB${S}`>;
type TX2 = TX1<'xYz'>; // "ABXYZ"
type TX3<S extends string> = Lowercase<`aB${S}`>;
Expand Down
7 changes: 7 additions & 0 deletions tests/baselines/reference/intrinsicTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ type TN4 = Uncapitalize<any>; // any
type TN5 = Uncapitalize<never>; // never
type TN6 = Uncapitalize<42>; // Error

type TS1 = Shell<'echo foo'>; // "foo"
type TS2 = Shell<'echo foo', 'bar'>; // Error
type TS3 = Shell<'somecommandthatdoesnotexist'>; // Error

type TX1<S extends string> = Uppercase<`aB${S}`>;
type TX2 = TX1<'xYz'>; // "ABXYZ"
type TX3<S extends string> = Lowercase<`aB${S}`>;
Expand Down Expand Up @@ -98,6 +102,9 @@ declare type TN3 = Uncapitalize<string>;
declare type TN4 = Uncapitalize<any>;
declare type TN5 = Uncapitalize<never>;
declare type TN6 = Uncapitalize<42>;
declare type TS1 = Shell<'echo foo'>;
declare type TS2 = Shell<'echo foo', 'bar'>;
declare type TS3 = Shell<'somecommandthatdoesnotexist'>;
declare type TX1<S extends string> = Uppercase<`aB${S}`>;
declare type TX2 = TX1<'xYz'>;
declare type TX3<S extends string> = Lowercase<`aB${S}`>;
Expand Down
114 changes: 63 additions & 51 deletions tests/baselines/reference/intrinsicTypes.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -95,102 +95,114 @@ type TN6 = Uncapitalize<42>; // Error
>TN6 : Symbol(TN6, Decl(intrinsicTypes.ts, 25, 31))
>Uncapitalize : Symbol(Uncapitalize, Decl(lib.es5.d.ts, --, --))

type TS1 = Shell<'echo foo'>; // "foo"
>TS1 : Symbol(TS1, Decl(intrinsicTypes.ts, 26, 28))
>Shell : Symbol(Shell, Decl(lib.es5.d.ts, --, --))

type TS2 = Shell<'echo foo', 'bar'>; // Error
>TS2 : Symbol(TS2, Decl(intrinsicTypes.ts, 28, 29))
>Shell : Symbol(Shell, Decl(lib.es5.d.ts, --, --))

type TS3 = Shell<'somecommandthatdoesnotexist'>; // Error
>TS3 : Symbol(TS3, Decl(intrinsicTypes.ts, 29, 36))
>Shell : Symbol(Shell, Decl(lib.es5.d.ts, --, --))

type TX1<S extends string> = Uppercase<`aB${S}`>;
>TX1 : Symbol(TX1, Decl(intrinsicTypes.ts, 26, 28))
>S : Symbol(S, Decl(intrinsicTypes.ts, 28, 9))
>TX1 : Symbol(TX1, Decl(intrinsicTypes.ts, 30, 48))
>S : Symbol(S, Decl(intrinsicTypes.ts, 32, 9))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>S : Symbol(S, Decl(intrinsicTypes.ts, 28, 9))
>S : Symbol(S, Decl(intrinsicTypes.ts, 32, 9))

type TX2 = TX1<'xYz'>; // "ABXYZ"
>TX2 : Symbol(TX2, Decl(intrinsicTypes.ts, 28, 49))
>TX1 : Symbol(TX1, Decl(intrinsicTypes.ts, 26, 28))
>TX2 : Symbol(TX2, Decl(intrinsicTypes.ts, 32, 49))
>TX1 : Symbol(TX1, Decl(intrinsicTypes.ts, 30, 48))

type TX3<S extends string> = Lowercase<`aB${S}`>;
>TX3 : Symbol(TX3, Decl(intrinsicTypes.ts, 29, 22))
>S : Symbol(S, Decl(intrinsicTypes.ts, 30, 9))
>TX3 : Symbol(TX3, Decl(intrinsicTypes.ts, 33, 22))
>S : Symbol(S, Decl(intrinsicTypes.ts, 34, 9))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
>S : Symbol(S, Decl(intrinsicTypes.ts, 30, 9))
>S : Symbol(S, Decl(intrinsicTypes.ts, 34, 9))

type TX4 = TX3<'xYz'>; // "abxyz"
>TX4 : Symbol(TX4, Decl(intrinsicTypes.ts, 30, 49))
>TX3 : Symbol(TX3, Decl(intrinsicTypes.ts, 29, 22))
>TX4 : Symbol(TX4, Decl(intrinsicTypes.ts, 34, 49))
>TX3 : Symbol(TX3, Decl(intrinsicTypes.ts, 33, 22))

type TX5 = `${Uppercase<'abc'>}${Lowercase<'XYZ'>}`; // "ABCxyz"
>TX5 : Symbol(TX5, Decl(intrinsicTypes.ts, 31, 22))
>TX5 : Symbol(TX5, Decl(intrinsicTypes.ts, 35, 22))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))

type MyUppercase<S extends string> = intrinsic; // Error
>MyUppercase : Symbol(MyUppercase, Decl(intrinsicTypes.ts, 32, 52))
>S : Symbol(S, Decl(intrinsicTypes.ts, 34, 17))
>MyUppercase : Symbol(MyUppercase, Decl(intrinsicTypes.ts, 36, 52))
>S : Symbol(S, Decl(intrinsicTypes.ts, 38, 17))

function foo1<T extends string, U extends T>(s: string, x: Uppercase<T>, y: Uppercase<U>) {
>foo1 : Symbol(foo1, Decl(intrinsicTypes.ts, 34, 47))
>T : Symbol(T, Decl(intrinsicTypes.ts, 36, 14))
>U : Symbol(U, Decl(intrinsicTypes.ts, 36, 31))
>T : Symbol(T, Decl(intrinsicTypes.ts, 36, 14))
>s : Symbol(s, Decl(intrinsicTypes.ts, 36, 45))
>x : Symbol(x, Decl(intrinsicTypes.ts, 36, 55))
>foo1 : Symbol(foo1, Decl(intrinsicTypes.ts, 38, 47))
>T : Symbol(T, Decl(intrinsicTypes.ts, 40, 14))
>U : Symbol(U, Decl(intrinsicTypes.ts, 40, 31))
>T : Symbol(T, Decl(intrinsicTypes.ts, 40, 14))
>s : Symbol(s, Decl(intrinsicTypes.ts, 40, 45))
>x : Symbol(x, Decl(intrinsicTypes.ts, 40, 55))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(intrinsicTypes.ts, 36, 14))
>y : Symbol(y, Decl(intrinsicTypes.ts, 36, 72))
>T : Symbol(T, Decl(intrinsicTypes.ts, 40, 14))
>y : Symbol(y, Decl(intrinsicTypes.ts, 40, 72))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>U : Symbol(U, Decl(intrinsicTypes.ts, 36, 31))
>U : Symbol(U, Decl(intrinsicTypes.ts, 40, 31))

s = x;
>s : Symbol(s, Decl(intrinsicTypes.ts, 36, 45))
>x : Symbol(x, Decl(intrinsicTypes.ts, 36, 55))
>s : Symbol(s, Decl(intrinsicTypes.ts, 40, 45))
>x : Symbol(x, Decl(intrinsicTypes.ts, 40, 55))

s = y;
>s : Symbol(s, Decl(intrinsicTypes.ts, 36, 45))
>y : Symbol(y, Decl(intrinsicTypes.ts, 36, 72))
>s : Symbol(s, Decl(intrinsicTypes.ts, 40, 45))
>y : Symbol(y, Decl(intrinsicTypes.ts, 40, 72))

x = s; // Error
>x : Symbol(x, Decl(intrinsicTypes.ts, 36, 55))
>s : Symbol(s, Decl(intrinsicTypes.ts, 36, 45))
>x : Symbol(x, Decl(intrinsicTypes.ts, 40, 55))
>s : Symbol(s, Decl(intrinsicTypes.ts, 40, 45))

x = y;
>x : Symbol(x, Decl(intrinsicTypes.ts, 36, 55))
>y : Symbol(y, Decl(intrinsicTypes.ts, 36, 72))
>x : Symbol(x, Decl(intrinsicTypes.ts, 40, 55))
>y : Symbol(y, Decl(intrinsicTypes.ts, 40, 72))

y = s; // Error
>y : Symbol(y, Decl(intrinsicTypes.ts, 36, 72))
>s : Symbol(s, Decl(intrinsicTypes.ts, 36, 45))
>y : Symbol(y, Decl(intrinsicTypes.ts, 40, 72))
>s : Symbol(s, Decl(intrinsicTypes.ts, 40, 45))

y = x; // Error
>y : Symbol(y, Decl(intrinsicTypes.ts, 36, 72))
>x : Symbol(x, Decl(intrinsicTypes.ts, 36, 55))
>y : Symbol(y, Decl(intrinsicTypes.ts, 40, 72))
>x : Symbol(x, Decl(intrinsicTypes.ts, 40, 55))
}

function foo2<T extends 'foo' | 'bar'>(x: Uppercase<T>) {
>foo2 : Symbol(foo2, Decl(intrinsicTypes.ts, 43, 1))
>T : Symbol(T, Decl(intrinsicTypes.ts, 45, 14))
>x : Symbol(x, Decl(intrinsicTypes.ts, 45, 39))
>foo2 : Symbol(foo2, Decl(intrinsicTypes.ts, 47, 1))
>T : Symbol(T, Decl(intrinsicTypes.ts, 49, 14))
>x : Symbol(x, Decl(intrinsicTypes.ts, 49, 39))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(intrinsicTypes.ts, 45, 14))
>T : Symbol(T, Decl(intrinsicTypes.ts, 49, 14))

let s: 'FOO' | 'BAR' = x;
>s : Symbol(s, Decl(intrinsicTypes.ts, 46, 7))
>x : Symbol(x, Decl(intrinsicTypes.ts, 45, 39))
>s : Symbol(s, Decl(intrinsicTypes.ts, 50, 7))
>x : Symbol(x, Decl(intrinsicTypes.ts, 49, 39))
}

declare function foo3<T extends string>(x: Uppercase<T>): T;
>foo3 : Symbol(foo3, Decl(intrinsicTypes.ts, 47, 1))
>T : Symbol(T, Decl(intrinsicTypes.ts, 49, 22))
>x : Symbol(x, Decl(intrinsicTypes.ts, 49, 40))
>foo3 : Symbol(foo3, Decl(intrinsicTypes.ts, 51, 1))
>T : Symbol(T, Decl(intrinsicTypes.ts, 53, 22))
>x : Symbol(x, Decl(intrinsicTypes.ts, 53, 40))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(intrinsicTypes.ts, 49, 22))
>T : Symbol(T, Decl(intrinsicTypes.ts, 49, 22))
>T : Symbol(T, Decl(intrinsicTypes.ts, 53, 22))
>T : Symbol(T, Decl(intrinsicTypes.ts, 53, 22))

function foo4<U extends string>(x: Uppercase<U>) {
>foo4 : Symbol(foo4, Decl(intrinsicTypes.ts, 49, 60))
>U : Symbol(U, Decl(intrinsicTypes.ts, 51, 14))
>x : Symbol(x, Decl(intrinsicTypes.ts, 51, 32))
>foo4 : Symbol(foo4, Decl(intrinsicTypes.ts, 53, 60))
>U : Symbol(U, Decl(intrinsicTypes.ts, 55, 14))
>x : Symbol(x, Decl(intrinsicTypes.ts, 55, 32))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>U : Symbol(U, Decl(intrinsicTypes.ts, 51, 14))
>U : Symbol(U, Decl(intrinsicTypes.ts, 55, 14))

return foo3(x);
>foo3 : Symbol(foo3, Decl(intrinsicTypes.ts, 47, 1))
>x : Symbol(x, Decl(intrinsicTypes.ts, 51, 32))
>foo3 : Symbol(foo3, Decl(intrinsicTypes.ts, 51, 1))
>x : Symbol(x, Decl(intrinsicTypes.ts, 55, 32))
}

9 changes: 9 additions & 0 deletions tests/baselines/reference/intrinsicTypes.types
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ type TN5 = Uncapitalize<never>; // never
type TN6 = Uncapitalize<42>; // Error
>TN6 : 42

type TS1 = Shell<'echo foo'>; // "foo"
>TS1 : "foo\n"

type TS2 = Shell<'echo foo', 'bar'>; // Error
>TS2 : any

type TS3 = Shell<'somecommandthatdoesnotexist'>; // Error
>TS3 : undefinedn

type TX1<S extends string> = Uppercase<`aB${S}`>;
>TX1 : Uppercase<`aB${S}`>

Expand Down
4 changes: 4 additions & 0 deletions tests/cases/conformance/types/typeAliases/intrinsicTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ type TN4 = Uncapitalize<any>; // any
type TN5 = Uncapitalize<never>; // never
type TN6 = Uncapitalize<42>; // Error

type TS1 = Shell<'echo foo'>; // "foo"
type TS2 = Shell<'echo foo', 'bar'>; // Error
type TS3 = Shell<'somecommandthatdoesnotexist'>; // Error

type TX1<S extends string> = Uppercase<`aB${S}`>;
type TX2 = TX1<'xYz'>; // "ABXYZ"
type TX3<S extends string> = Lowercase<`aB${S}`>;
Expand Down