Skip to content

Commit 3853bb8

Browse files
committed
Merge pull request #7140 from Microsoft/strictNullChecks
Non-nullable types
2 parents 7c99c8f + fb6255a commit 3853bb8

39 files changed

+1261
-980
lines changed

src/compiler/checker.ts

Lines changed: 700 additions & 267 deletions
Large diffs are not rendered by default.

src/compiler/commandLineParser.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,11 @@ namespace ts {
331331
name: "noImplicitUseStrict",
332332
type: "boolean",
333333
description: Diagnostics.Do_not_emit_use_strict_directives_in_module_output
334+
},
335+
{
336+
name: "strictNullChecks",
337+
type: "boolean",
338+
description: Diagnostics.Enable_strict_null_checks
334339
}
335340
];
336341

src/compiler/core.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,14 @@ namespace ts {
242242
const count = array.length;
243243
if (count > 0) {
244244
let pos = 0;
245-
let result = arguments.length <= 2 ? array[pos] : initial;
246-
pos++;
245+
let result: T | U;
246+
if (arguments.length <= 2) {
247+
result = array[pos];
248+
pos++;
249+
}
250+
else {
251+
result = initial;
252+
}
247253
while (pos < count) {
248254
result = f(<U>result, array[pos]);
249255
pos++;
@@ -260,8 +266,14 @@ namespace ts {
260266
if (array) {
261267
let pos = array.length - 1;
262268
if (pos >= 0) {
263-
let result = arguments.length <= 2 ? array[pos] : initial;
264-
pos--;
269+
let result: T | U;
270+
if (arguments.length <= 2) {
271+
result = array[pos];
272+
pos--;
273+
}
274+
else {
275+
result = initial;
276+
}
265277
while (pos >= 0) {
266278
result = f(<U>result, array[pos]);
267279
pos--;

src/compiler/declarationEmitter.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ namespace ts {
367367
case SyntaxKind.BooleanKeyword:
368368
case SyntaxKind.SymbolKeyword:
369369
case SyntaxKind.VoidKeyword:
370+
case SyntaxKind.UndefinedKeyword:
371+
case SyntaxKind.NullKeyword:
370372
case SyntaxKind.ThisType:
371373
case SyntaxKind.StringLiteralType:
372374
return writeTextOfNode(currentText, type);

src/compiler/diagnosticMessages.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,10 @@
11031103
"category": "Error",
11041104
"code": 2365
11051105
},
1106+
"Function lacks ending return statement and return type does not include 'undefined'.": {
1107+
"category": "Error",
1108+
"code": 2366
1109+
},
11061110
"Type parameter name cannot be '{0}'": {
11071111
"category": "Error",
11081112
"code": 2368
@@ -1423,6 +1427,10 @@
14231427
"category": "Error",
14241428
"code": 2453
14251429
},
1430+
"Variable '{0}' is used before being assigned.": {
1431+
"category": "Error",
1432+
"code": 2454
1433+
},
14261434
"Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'.": {
14271435
"category": "Error",
14281436
"code": 2455
@@ -1719,6 +1727,10 @@
17191727
"category": "Error",
17201728
"code": 2530
17211729
},
1730+
"Object is possibly 'null' or 'undefined'.": {
1731+
"category": "Error",
1732+
"code": 2531
1733+
},
17221734
"JSX element attributes type '{0}' may not be a union type.": {
17231735
"category": "Error",
17241736
"code": 2600
@@ -2604,6 +2616,11 @@
26042616
"category": "Message",
26052617
"code": 6112
26062618
},
2619+
"Enable strict null checks.": {
2620+
"category": "Message",
2621+
"code": 6113
2622+
},
2623+
26072624
"Variable '{0}' implicitly has an '{1}' type.": {
26082625
"category": "Error",
26092626
"code": 7005

src/compiler/emitter.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,6 +1533,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
15331533
case SyntaxKind.JsxSpreadAttribute:
15341534
case SyntaxKind.JsxExpression:
15351535
case SyntaxKind.NewExpression:
1536+
case SyntaxKind.NonNullExpression:
15361537
case SyntaxKind.ParenthesizedExpression:
15371538
case SyntaxKind.PostfixUnaryExpression:
15381539
case SyntaxKind.PrefixUnaryExpression:
@@ -2077,8 +2078,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
20772078
function parenthesizeForAccess(expr: Expression): LeftHandSideExpression {
20782079
// When diagnosing whether the expression needs parentheses, the decision should be based
20792080
// on the innermost expression in a chain of nested type assertions.
2080-
while (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) {
2081-
expr = (<AssertionExpression>expr).expression;
2081+
while (expr.kind === SyntaxKind.TypeAssertionExpression ||
2082+
expr.kind === SyntaxKind.AsExpression ||
2083+
expr.kind === SyntaxKind.NonNullExpression) {
2084+
expr = (<AssertionExpression | NonNullExpression>expr).expression;
20822085
}
20832086

20842087
// isLeftHandSideExpression is almost the correct criterion for when it is not necessary
@@ -2343,8 +2346,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
23432346
}
23442347

23452348
function skipParentheses(node: Expression): Expression {
2346-
while (node.kind === SyntaxKind.ParenthesizedExpression || node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression) {
2347-
node = (<ParenthesizedExpression | AssertionExpression>node).expression;
2349+
while (node.kind === SyntaxKind.ParenthesizedExpression ||
2350+
node.kind === SyntaxKind.TypeAssertionExpression ||
2351+
node.kind === SyntaxKind.AsExpression ||
2352+
node.kind === SyntaxKind.NonNullExpression) {
2353+
node = (<ParenthesizedExpression | AssertionExpression | NonNullExpression>node).expression;
23482354
}
23492355
return node;
23502356
}
@@ -2518,13 +2524,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
25182524
// not the user. If we didn't want them, the emitter would not have put them
25192525
// there.
25202526
if (!nodeIsSynthesized(node) && node.parent.kind !== SyntaxKind.ArrowFunction) {
2521-
if (node.expression.kind === SyntaxKind.TypeAssertionExpression || node.expression.kind === SyntaxKind.AsExpression) {
2522-
let operand = (<TypeAssertion>node.expression).expression;
2527+
if (node.expression.kind === SyntaxKind.TypeAssertionExpression ||
2528+
node.expression.kind === SyntaxKind.AsExpression ||
2529+
node.expression.kind === SyntaxKind.NonNullExpression) {
2530+
let operand = (<TypeAssertion | NonNullExpression>node.expression).expression;
25232531

25242532
// Make sure we consider all nested cast expressions, e.g.:
25252533
// (<any><number><any>-A).x;
2526-
while (operand.kind === SyntaxKind.TypeAssertionExpression || operand.kind === SyntaxKind.AsExpression) {
2527-
operand = (<TypeAssertion>operand).expression;
2534+
while (operand.kind === SyntaxKind.TypeAssertionExpression ||
2535+
operand.kind === SyntaxKind.AsExpression ||
2536+
operand.kind === SyntaxKind.NonNullExpression) {
2537+
operand = (<TypeAssertion | NonNullExpression>operand).expression;
25282538
}
25292539

25302540
// We have an expression of the form: (<Type>SubExpr)
@@ -7928,9 +7938,9 @@ const _super = (function (geti, seti) {
79287938
case SyntaxKind.TaggedTemplateExpression:
79297939
return emitTaggedTemplateExpression(<TaggedTemplateExpression>node);
79307940
case SyntaxKind.TypeAssertionExpression:
7931-
return emit((<TypeAssertion>node).expression);
79327941
case SyntaxKind.AsExpression:
7933-
return emit((<AsExpression>node).expression);
7942+
case SyntaxKind.NonNullExpression:
7943+
return emit((<AssertionExpression | NonNullExpression>node).expression);
79347944
case SyntaxKind.ParenthesizedExpression:
79357945
return emitParenExpression(<ParenthesizedExpression>node);
79367946
case SyntaxKind.FunctionDeclaration:

src/compiler/parser.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ namespace ts {
177177
case SyntaxKind.AsExpression:
178178
return visitNode(cbNode, (<AsExpression>node).expression) ||
179179
visitNode(cbNode, (<AsExpression>node).type);
180+
case SyntaxKind.NonNullExpression:
181+
return visitNode(cbNode, (<NonNullExpression>node).expression);
180182
case SyntaxKind.ConditionalExpression:
181183
return visitNode(cbNode, (<ConditionalExpression>node).condition) ||
182184
visitNode(cbNode, (<ConditionalExpression>node).questionToken) ||
@@ -2361,12 +2363,14 @@ namespace ts {
23612363
case SyntaxKind.NumberKeyword:
23622364
case SyntaxKind.BooleanKeyword:
23632365
case SyntaxKind.SymbolKeyword:
2366+
case SyntaxKind.UndefinedKeyword:
23642367
// If these are followed by a dot, then parse these out as a dotted type reference instead.
23652368
const node = tryParse(parseKeywordAndNoDot);
23662369
return node || parseTypeReference();
23672370
case SyntaxKind.StringLiteral:
23682371
return parseStringLiteralTypeNode();
23692372
case SyntaxKind.VoidKeyword:
2373+
case SyntaxKind.NullKeyword:
23702374
return parseTokenNode<TypeNode>();
23712375
case SyntaxKind.ThisKeyword: {
23722376
const thisKeyword = parseThisTypeNode();
@@ -2398,6 +2402,8 @@ namespace ts {
23982402
case SyntaxKind.BooleanKeyword:
23992403
case SyntaxKind.SymbolKeyword:
24002404
case SyntaxKind.VoidKeyword:
2405+
case SyntaxKind.UndefinedKeyword:
2406+
case SyntaxKind.NullKeyword:
24012407
case SyntaxKind.ThisKeyword:
24022408
case SyntaxKind.TypeOfKeyword:
24032409
case SyntaxKind.OpenBraceToken:
@@ -3724,6 +3730,14 @@ namespace ts {
37243730
continue;
37253731
}
37263732

3733+
if (token === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
3734+
nextToken();
3735+
const nonNullExpression = <NonNullExpression>createNode(SyntaxKind.NonNullExpression, expression.pos);
3736+
nonNullExpression.expression = expression;
3737+
expression = finishNode(nonNullExpression);
3738+
continue;
3739+
}
3740+
37273741
// when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName
37283742
if (!inDecoratorContext() && parseOptional(SyntaxKind.OpenBracketToken)) {
37293743
const indexedAccess = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, expression.pos);

src/compiler/scanner.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ namespace ts {
114114
"try": SyntaxKind.TryKeyword,
115115
"type": SyntaxKind.TypeKeyword,
116116
"typeof": SyntaxKind.TypeOfKeyword,
117+
"undefined": SyntaxKind.UndefinedKeyword,
117118
"var": SyntaxKind.VarKeyword,
118119
"void": SyntaxKind.VoidKeyword,
119120
"while": SyntaxKind.WhileKeyword,

src/compiler/types.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ namespace ts {
171171
StringKeyword,
172172
SymbolKeyword,
173173
TypeKeyword,
174+
UndefinedKeyword,
174175
FromKeyword,
175176
GlobalKeyword,
176177
OfKeyword, // LastKeyword and LastToken
@@ -240,6 +241,7 @@ namespace ts {
240241
OmittedExpression,
241242
ExpressionWithTypeArguments,
242243
AsExpression,
244+
NonNullExpression,
243245

244246
// Misc
245247
TemplateSpan,
@@ -475,6 +477,11 @@ namespace ts {
475477
originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later
476478
}
477479

480+
// Transient identifier node (marked by id === -1)
481+
export interface TransientIdentifier extends Identifier {
482+
resolvedSymbol: Symbol;
483+
}
484+
478485
// @kind(SyntaxKind.QualifiedName)
479486
export interface QualifiedName extends Node {
480487
// Must have same layout as PropertyAccess
@@ -968,6 +975,8 @@ namespace ts {
968975
name: Identifier;
969976
}
970977

978+
export type IdentifierOrPropertyAccess = Identifier | PropertyAccessExpression;
979+
971980
// @kind(SyntaxKind.ElementAccessExpression)
972981
export interface ElementAccessExpression extends MemberExpression {
973982
expression: LeftHandSideExpression;
@@ -1012,6 +1021,11 @@ namespace ts {
10121021

10131022
export type AssertionExpression = TypeAssertion | AsExpression;
10141023

1024+
// @kind(SyntaxKind.NonNullExpression)
1025+
export interface NonNullExpression extends LeftHandSideExpression {
1026+
expression: Expression;
1027+
}
1028+
10151029
/// A JSX expression of the form <TagName attrs>...</TagName>
10161030
// @kind(SyntaxKind.JsxElement)
10171031
export interface JsxElement extends PrimaryExpression {
@@ -2029,7 +2043,9 @@ namespace ts {
20292043
exportsChecked?: boolean; // True if exports of external module have been checked
20302044
isDeclarationWithCollidingName?: boolean; // True if symbol is block scoped redeclaration
20312045
bindingElement?: BindingElement; // Binding element associated with property symbol
2032-
exportsSomeValue?: boolean; // true if module exports some value (not just types)
2046+
exportsSomeValue?: boolean; // True if module exports some value (not just types)
2047+
firstAssignmentChecked?: boolean; // True if first assignment node has been computed
2048+
firstAssignment?: Node; // First assignment node (undefined if no assignments)
20332049
}
20342050

20352051
/* @internal */
@@ -2072,7 +2088,7 @@ namespace ts {
20722088
isVisible?: boolean; // Is this node visible
20732089
generatedName?: string; // Generated name for module, enum, or import declaration
20742090
generatedNames?: Map<string>; // Generated names table for source file
2075-
assignmentChecks?: Map<boolean>; // Cache of assignment checks
2091+
assignmentMap?: Map<boolean>; // Cached map of references assigned within this node
20762092
hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context
20772093
importOnRightSide?: Symbol; // for import declarations - import that appear on the right side
20782094
jsxFlags?: JsxFlags; // flags for knowing what kind of element/attributes we're dealing with
@@ -2106,7 +2122,7 @@ namespace ts {
21062122
/* @internal */
21072123
FreshObjectLiteral = 0x00100000, // Fresh object literal type
21082124
/* @internal */
2109-
ContainsUndefinedOrNull = 0x00200000, // Type is or contains Undefined or Null type
2125+
ContainsUndefinedOrNull = 0x00200000, // Type is or contains undefined or null type
21102126
/* @internal */
21112127
ContainsObjectLiteral = 0x00400000, // Type is or contains object literal type
21122128
/* @internal */
@@ -2115,6 +2131,8 @@ namespace ts {
21152131
ThisType = 0x02000000, // This type
21162132
ObjectLiteralPatternWithComputedProperties = 0x04000000, // Object literal type implied by binding pattern has computed properties
21172133

2134+
/* @internal */
2135+
Nullable = Undefined | Null,
21182136
/* @internal */
21192137
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null,
21202138
/* @internal */
@@ -2439,6 +2457,7 @@ namespace ts {
24392457
allowSyntheticDefaultImports?: boolean;
24402458
allowJs?: boolean;
24412459
noImplicitUseStrict?: boolean;
2460+
strictNullChecks?: boolean;
24422461
lib?: string[];
24432462
/* @internal */ stripInternal?: boolean;
24442463

src/compiler/utilities.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ namespace ts {
511511
case SyntaxKind.StringKeyword:
512512
case SyntaxKind.BooleanKeyword:
513513
case SyntaxKind.SymbolKeyword:
514+
case SyntaxKind.UndefinedKeyword:
514515
return true;
515516
case SyntaxKind.VoidKeyword:
516517
return node.parent.kind !== SyntaxKind.VoidExpression;
@@ -968,6 +969,7 @@ namespace ts {
968969
case SyntaxKind.TaggedTemplateExpression:
969970
case SyntaxKind.AsExpression:
970971
case SyntaxKind.TypeAssertionExpression:
972+
case SyntaxKind.NonNullExpression:
971973
case SyntaxKind.ParenthesizedExpression:
972974
case SyntaxKind.FunctionExpression:
973975
case SyntaxKind.ClassExpression:
@@ -2406,6 +2408,7 @@ namespace ts {
24062408
case SyntaxKind.ElementAccessExpression:
24072409
case SyntaxKind.NewExpression:
24082410
case SyntaxKind.CallExpression:
2411+
case SyntaxKind.NonNullExpression:
24092412
case SyntaxKind.JsxElement:
24102413
case SyntaxKind.JsxSelfClosingElement:
24112414
case SyntaxKind.TaggedTemplateExpression:

0 commit comments

Comments
 (0)