Skip to content

Commit

Permalink
Merge pull request #11126 from Microsoft/nonWideningLiterals
Browse files Browse the repository at this point in the history
Non-widening explicit literal types
  • Loading branch information
ahejlsberg authored Sep 26, 2016
2 parents 3d92117 + b6b8e8c commit 76e71ab
Show file tree
Hide file tree
Showing 48 changed files with 1,448 additions and 231 deletions.
197 changes: 152 additions & 45 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/compiler/declarationEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,10 @@ namespace ts {
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) {
emitTypeOfVariableDeclarationFromTypeLiteral(node);
}
else if (resolver.isLiteralConstDeclaration(node)) {
write(" = ");
resolver.writeLiteralConstValue(node, writer);
}
else if (!hasModifier(node, ModifierFlags.Private)) {
writeTypeOfDeclaration(node, node.type, getVariableDeclarationTypeVisibilityError);
}
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,10 @@
"category": "Error",
"code": 1253
},
"A 'const' initializer in an ambient context must be a string or numeric literal.": {
"category": "Error",
"code": 1254
},
"'with' statements are not allowed in an async function block.": {
"category": "Error",
"code": 1300
Expand Down
14 changes: 10 additions & 4 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2167,6 +2167,8 @@ namespace ts {
getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): SourceFile;
getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): string[];
getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[];
isLiteralConstDeclaration(node: VariableDeclaration): boolean;
writeLiteralConstValue(node: VariableDeclaration, writer: SymbolWriter): void;
}

export const enum SymbolFlags {
Expand Down Expand Up @@ -2383,7 +2385,7 @@ namespace ts {
/* @internal */
ObjectLiteral = 1 << 23, // Originates in an object literal
/* @internal */
FreshObjectLiteral = 1 << 24, // Fresh object literal type
FreshLiteral = 1 << 24, // Fresh literal type
/* @internal */
ContainsWideningType = 1 << 25, // Type is or contains undefined or null widening type
/* @internal */
Expand All @@ -2396,6 +2398,7 @@ namespace ts {
/* @internal */
Nullable = Undefined | Null,
Literal = StringLiteral | NumberLiteral | BooleanLiteral | EnumLiteral,
StringOrNumberLiteral = StringLiteral | NumberLiteral,
/* @internal */
DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null,
PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean,
Expand Down Expand Up @@ -2437,12 +2440,15 @@ namespace ts {
/* @internal */
// Intrinsic types (TypeFlags.Intrinsic)
export interface IntrinsicType extends Type {
intrinsicName: string; // Name of intrinsic type
intrinsicName: string; // Name of intrinsic type
}

// String literal types (TypeFlags.StringLiteral)
// Numeric literal types (TypeFlags.NumberLiteral)
export interface LiteralType extends Type {
text: string; // Text of string literal
text: string; // Text of literal
freshType?: LiteralType; // Fresh version of type
regularType?: LiteralType; // Regular version of type
}

// Enum types (TypeFlags.Enum)
Expand All @@ -2452,7 +2458,7 @@ namespace ts {

// Enum types (TypeFlags.EnumLiteral)
export interface EnumLiteralType extends LiteralType {
baseType: EnumType & UnionType;
baseType: EnumType & UnionType; // Base enum type
}

// Object types (TypeFlags.ObjectType)
Expand Down
72 changes: 72 additions & 0 deletions tests/baselines/reference/ambientConstLiterals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//// [ambientConstLiterals.ts]

function f<T>(x: T): T {
return x;
}

enum E { A, B, C }

const c1 = "abc";
const c2 = 123;
const c3 = c1;
const c4 = c2;
const c5 = f(123);
const c6 = f(-123);
const c7 = true;
const c8 = E.A;
const c9 = { x: "abc" };
const c10 = [123];
const c11 = "abc" + "def";
const c12 = 123 + 456;
const c13 = Math.random() > 0.5 ? "abc" : "def";
const c14 = Math.random() > 0.5 ? 123 : 456;

//// [ambientConstLiterals.js]
function f(x) {
return x;
}
var E;
(function (E) {
E[E["A"] = 0] = "A";
E[E["B"] = 1] = "B";
E[E["C"] = 2] = "C";
})(E || (E = {}));
var c1 = "abc";
var c2 = 123;
var c3 = c1;
var c4 = c2;
var c5 = f(123);
var c6 = f(-123);
var c7 = true;
var c8 = E.A;
var c9 = { x: "abc" };
var c10 = [123];
var c11 = "abc" + "def";
var c12 = 123 + 456;
var c13 = Math.random() > 0.5 ? "abc" : "def";
var c14 = Math.random() > 0.5 ? 123 : 456;


//// [ambientConstLiterals.d.ts]
declare function f<T>(x: T): T;
declare enum E {
A = 0,
B = 1,
C = 2,
}
declare const c1 = "abc";
declare const c2 = 123;
declare const c3 = "abc";
declare const c4 = 123;
declare const c5 = 123;
declare const c6 = -123;
declare const c7: boolean;
declare const c8: E;
declare const c9: {
x: string;
};
declare const c10: number[];
declare const c11: string;
declare const c12: number;
declare const c13: string;
declare const c14: number;
75 changes: 75 additions & 0 deletions tests/baselines/reference/ambientConstLiterals.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
=== tests/cases/compiler/ambientConstLiterals.ts ===

function f<T>(x: T): T {
>f : Symbol(f, Decl(ambientConstLiterals.ts, 0, 0))
>T : Symbol(T, Decl(ambientConstLiterals.ts, 1, 11))
>x : Symbol(x, Decl(ambientConstLiterals.ts, 1, 14))
>T : Symbol(T, Decl(ambientConstLiterals.ts, 1, 11))
>T : Symbol(T, Decl(ambientConstLiterals.ts, 1, 11))

return x;
>x : Symbol(x, Decl(ambientConstLiterals.ts, 1, 14))
}

enum E { A, B, C }
>E : Symbol(E, Decl(ambientConstLiterals.ts, 3, 1))
>A : Symbol(E.A, Decl(ambientConstLiterals.ts, 5, 8))
>B : Symbol(E.B, Decl(ambientConstLiterals.ts, 5, 11))
>C : Symbol(E.C, Decl(ambientConstLiterals.ts, 5, 14))

const c1 = "abc";
>c1 : Symbol(c1, Decl(ambientConstLiterals.ts, 7, 5))

const c2 = 123;
>c2 : Symbol(c2, Decl(ambientConstLiterals.ts, 8, 5))

const c3 = c1;
>c3 : Symbol(c3, Decl(ambientConstLiterals.ts, 9, 5))
>c1 : Symbol(c1, Decl(ambientConstLiterals.ts, 7, 5))

const c4 = c2;
>c4 : Symbol(c4, Decl(ambientConstLiterals.ts, 10, 5))
>c2 : Symbol(c2, Decl(ambientConstLiterals.ts, 8, 5))

const c5 = f(123);
>c5 : Symbol(c5, Decl(ambientConstLiterals.ts, 11, 5))
>f : Symbol(f, Decl(ambientConstLiterals.ts, 0, 0))

const c6 = f(-123);
>c6 : Symbol(c6, Decl(ambientConstLiterals.ts, 12, 5))
>f : Symbol(f, Decl(ambientConstLiterals.ts, 0, 0))

const c7 = true;
>c7 : Symbol(c7, Decl(ambientConstLiterals.ts, 13, 5))

const c8 = E.A;
>c8 : Symbol(c8, Decl(ambientConstLiterals.ts, 14, 5))
>E.A : Symbol(E.A, Decl(ambientConstLiterals.ts, 5, 8))
>E : Symbol(E, Decl(ambientConstLiterals.ts, 3, 1))
>A : Symbol(E.A, Decl(ambientConstLiterals.ts, 5, 8))

const c9 = { x: "abc" };
>c9 : Symbol(c9, Decl(ambientConstLiterals.ts, 15, 5))
>x : Symbol(x, Decl(ambientConstLiterals.ts, 15, 12))

const c10 = [123];
>c10 : Symbol(c10, Decl(ambientConstLiterals.ts, 16, 5))

const c11 = "abc" + "def";
>c11 : Symbol(c11, Decl(ambientConstLiterals.ts, 17, 5))

const c12 = 123 + 456;
>c12 : Symbol(c12, Decl(ambientConstLiterals.ts, 18, 5))

const c13 = Math.random() > 0.5 ? "abc" : "def";
>c13 : Symbol(c13, Decl(ambientConstLiterals.ts, 19, 5))
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))

const c14 = Math.random() > 0.5 ? 123 : 456;
>c14 : Symbol(c14, Decl(ambientConstLiterals.ts, 20, 5))
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))

105 changes: 105 additions & 0 deletions tests/baselines/reference/ambientConstLiterals.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
=== tests/cases/compiler/ambientConstLiterals.ts ===

function f<T>(x: T): T {
>f : <T>(x: T) => T
>T : T
>x : T
>T : T
>T : T

return x;
>x : T
}

enum E { A, B, C }
>E : E
>A : E.A
>B : E.B
>C : E.C

const c1 = "abc";
>c1 : "abc"
>"abc" : "abc"

const c2 = 123;
>c2 : 123
>123 : 123

const c3 = c1;
>c3 : "abc"
>c1 : "abc"

const c4 = c2;
>c4 : 123
>c2 : 123

const c5 = f(123);
>c5 : 123
>f(123) : 123
>f : <T>(x: T) => T
>123 : 123

const c6 = f(-123);
>c6 : -123
>f(-123) : -123
>f : <T>(x: T) => T
>-123 : -123
>123 : 123

const c7 = true;
>c7 : true
>true : true

const c8 = E.A;
>c8 : E.A
>E.A : E.A
>E : typeof E
>A : E.A

const c9 = { x: "abc" };
>c9 : { x: string; }
>{ x: "abc" } : { x: string; }
>x : string
>"abc" : "abc"

const c10 = [123];
>c10 : number[]
>[123] : number[]
>123 : 123

const c11 = "abc" + "def";
>c11 : string
>"abc" + "def" : string
>"abc" : "abc"
>"def" : "def"

const c12 = 123 + 456;
>c12 : number
>123 + 456 : number
>123 : 123
>456 : 456

const c13 = Math.random() > 0.5 ? "abc" : "def";
>c13 : "abc" | "def"
>Math.random() > 0.5 ? "abc" : "def" : "abc" | "def"
>Math.random() > 0.5 : boolean
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>0.5 : 0.5
>"abc" : "abc"
>"def" : "def"

const c14 = Math.random() > 0.5 ? 123 : 456;
>c14 : 123 | 456
>Math.random() > 0.5 ? 123 : 456 : 123 | 456
>Math.random() > 0.5 : boolean
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>0.5 : 0.5
>123 : 123
>456 : 456

2 changes: 1 addition & 1 deletion tests/baselines/reference/arrayconcat.types
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class parser {
>this : this
>options : IOptions[]
>sort : (compareFn?: (a: IOptions, b: IOptions) => number) => IOptions[]
>function(a, b) { var aName = a.name.toLowerCase(); var bName = b.name.toLowerCase(); if (aName > bName) { return 1; } else if (aName < bName) { return -1; } else { return 0; } } : (a: IOptions, b: IOptions) => 0 | 1 | -1
>function(a, b) { var aName = a.name.toLowerCase(); var bName = b.name.toLowerCase(); if (aName > bName) { return 1; } else if (aName < bName) { return -1; } else { return 0; } } : (a: IOptions, b: IOptions) => 1 | -1 | 0
>a : IOptions
>b : IOptions

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var derived2: Derived2;

var r2 = true ? 1 : '';
>r2 : string | number
>true ? 1 : '' : "" | 1
>true ? 1 : '' : 1 | ""
>true : true
>1 : 1
>'' : ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ declare function foo<T>(obj: I<T>): T
foo({
>foo({ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]}) : string | number | boolean | (() => void) | number[]
>foo : <T>(obj: I<T>) => T
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | 0 | (() => void) | number[]; [x: number]: 0 | (() => void) | number[]; 0: () => void; p: ""; }
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | (() => void) | 0 | number[]; [x: number]: (() => void) | 0 | number[]; 0: () => void; p: ""; }

p: "",
>p : string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ declare function foo<T>(obj: I<T>): T
foo({
>foo({ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]}) : string | number | boolean | (() => void) | number[]
>foo : <T>(obj: I<T>) => T
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | 0 | (() => void) | number[]; [x: number]: 0 | (() => void) | number[]; 0: () => void; p: ""; }
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | (() => void) | 0 | number[]; [x: number]: (() => void) | 0 | number[]; 0: () => void; p: ""; }

p: "",
>p : string
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/conditionalExpression1.errors.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
tests/cases/compiler/conditionalExpression1.ts(1,5): error TS2322: Type '"" | 1' is not assignable to type 'boolean'.
Type '""' is not assignable to type 'boolean'.
tests/cases/compiler/conditionalExpression1.ts(1,5): error TS2322: Type '1 | ""' is not assignable to type 'boolean'.
Type '1' is not assignable to type 'boolean'.


==== tests/cases/compiler/conditionalExpression1.ts (1 errors) ====
var x: boolean = (true ? 1 : ""); // should be an error
~
!!! error TS2322: Type '"" | 1' is not assignable to type 'boolean'.
!!! error TS2322: Type '""' is not assignable to type 'boolean'.
!!! error TS2322: Type '1 | ""' is not assignable to type 'boolean'.
!!! error TS2322: Type '1' is not assignable to type 'boolean'.
2 changes: 1 addition & 1 deletion tests/baselines/reference/conditionalExpressions2.types
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var b = false ? undefined : 0;

var c = false ? 1 : 0;
>c : number
>false ? 1 : 0 : 0 | 1
>false ? 1 : 0 : 1 | 0
>false : false
>1 : 1
>0 : 0
Expand Down
Loading

0 comments on commit 76e71ab

Please sign in to comment.