Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-widening explicit literal types #11126

Merged
merged 12 commits into from
Sep 26, 2016
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 @@ -2156,6 +2156,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 @@ -2372,7 +2374,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 @@ -2385,6 +2387,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 @@ -2426,12 +2429,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 @@ -2441,7 +2447,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