Merge pull request #7140 from Microsoft/strictNullChecks

Non-nullable types
This commit is contained in:
Anders Hejlsberg
2016-03-21 16:52:43 -07:00
39 changed files with 1267 additions and 986 deletions
+706 -273
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -331,6 +331,11 @@ namespace ts {
name: "noImplicitUseStrict",
type: "boolean",
description: Diagnostics.Do_not_emit_use_strict_directives_in_module_output
},
{
name: "strictNullChecks",
type: "boolean",
description: Diagnostics.Enable_strict_null_checks
}
];
+16 -4
View File
@@ -242,8 +242,14 @@ namespace ts {
const count = array.length;
if (count > 0) {
let pos = 0;
let result = arguments.length <= 2 ? array[pos] : initial;
pos++;
let result: T | U;
if (arguments.length <= 2) {
result = array[pos];
pos++;
}
else {
result = initial;
}
while (pos < count) {
result = f(<U>result, array[pos]);
pos++;
@@ -260,8 +266,14 @@ namespace ts {
if (array) {
let pos = array.length - 1;
if (pos >= 0) {
let result = arguments.length <= 2 ? array[pos] : initial;
pos--;
let result: T | U;
if (arguments.length <= 2) {
result = array[pos];
pos--;
}
else {
result = initial;
}
while (pos >= 0) {
result = f(<U>result, array[pos]);
pos--;
+2
View File
@@ -367,6 +367,8 @@ namespace ts {
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.ThisType:
case SyntaxKind.StringLiteralType:
return writeTextOfNode(currentText, type);
+17
View File
@@ -1103,6 +1103,10 @@
"category": "Error",
"code": 2365
},
"Function lacks ending return statement and return type does not include 'undefined'.": {
"category": "Error",
"code": 2366
},
"Type parameter name cannot be '{0}'": {
"category": "Error",
"code": 2368
@@ -1423,6 +1427,10 @@
"category": "Error",
"code": 2453
},
"Variable '{0}' is used before being assigned.": {
"category": "Error",
"code": 2454
},
"Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'.": {
"category": "Error",
"code": 2455
@@ -1719,6 +1727,10 @@
"category": "Error",
"code": 2530
},
"Object is possibly 'null' or 'undefined'.": {
"category": "Error",
"code": 2531
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
@@ -2604,6 +2616,11 @@
"category": "Message",
"code": 6112
},
"Enable strict null checks.": {
"category": "Message",
"code": 6113
},
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
"code": 7005
+20 -10
View File
@@ -1533,6 +1533,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
case SyntaxKind.JsxSpreadAttribute:
case SyntaxKind.JsxExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.NonNullExpression:
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.PostfixUnaryExpression:
case SyntaxKind.PrefixUnaryExpression:
@@ -2077,8 +2078,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function parenthesizeForAccess(expr: Expression): LeftHandSideExpression {
// When diagnosing whether the expression needs parentheses, the decision should be based
// on the innermost expression in a chain of nested type assertions.
while (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) {
expr = (<AssertionExpression>expr).expression;
while (expr.kind === SyntaxKind.TypeAssertionExpression ||
expr.kind === SyntaxKind.AsExpression ||
expr.kind === SyntaxKind.NonNullExpression) {
expr = (<AssertionExpression | NonNullExpression>expr).expression;
}
// 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
}
function skipParentheses(node: Expression): Expression {
while (node.kind === SyntaxKind.ParenthesizedExpression || node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression) {
node = (<ParenthesizedExpression | AssertionExpression>node).expression;
while (node.kind === SyntaxKind.ParenthesizedExpression ||
node.kind === SyntaxKind.TypeAssertionExpression ||
node.kind === SyntaxKind.AsExpression ||
node.kind === SyntaxKind.NonNullExpression) {
node = (<ParenthesizedExpression | AssertionExpression | NonNullExpression>node).expression;
}
return node;
}
@@ -2518,13 +2524,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
// not the user. If we didn't want them, the emitter would not have put them
// there.
if (!nodeIsSynthesized(node) && node.parent.kind !== SyntaxKind.ArrowFunction) {
if (node.expression.kind === SyntaxKind.TypeAssertionExpression || node.expression.kind === SyntaxKind.AsExpression) {
let operand = (<TypeAssertion>node.expression).expression;
if (node.expression.kind === SyntaxKind.TypeAssertionExpression ||
node.expression.kind === SyntaxKind.AsExpression ||
node.expression.kind === SyntaxKind.NonNullExpression) {
let operand = (<TypeAssertion | NonNullExpression>node.expression).expression;
// Make sure we consider all nested cast expressions, e.g.:
// (<any><number><any>-A).x;
while (operand.kind === SyntaxKind.TypeAssertionExpression || operand.kind === SyntaxKind.AsExpression) {
operand = (<TypeAssertion>operand).expression;
while (operand.kind === SyntaxKind.TypeAssertionExpression ||
operand.kind === SyntaxKind.AsExpression ||
operand.kind === SyntaxKind.NonNullExpression) {
operand = (<TypeAssertion | NonNullExpression>operand).expression;
}
// We have an expression of the form: (<Type>SubExpr)
@@ -7928,9 +7938,9 @@ const _super = (function (geti, seti) {
case SyntaxKind.TaggedTemplateExpression:
return emitTaggedTemplateExpression(<TaggedTemplateExpression>node);
case SyntaxKind.TypeAssertionExpression:
return emit((<TypeAssertion>node).expression);
case SyntaxKind.AsExpression:
return emit((<AsExpression>node).expression);
case SyntaxKind.NonNullExpression:
return emit((<AssertionExpression | NonNullExpression>node).expression);
case SyntaxKind.ParenthesizedExpression:
return emitParenExpression(<ParenthesizedExpression>node);
case SyntaxKind.FunctionDeclaration:
+14
View File
@@ -177,6 +177,8 @@ namespace ts {
case SyntaxKind.AsExpression:
return visitNode(cbNode, (<AsExpression>node).expression) ||
visitNode(cbNode, (<AsExpression>node).type);
case SyntaxKind.NonNullExpression:
return visitNode(cbNode, (<NonNullExpression>node).expression);
case SyntaxKind.ConditionalExpression:
return visitNode(cbNode, (<ConditionalExpression>node).condition) ||
visitNode(cbNode, (<ConditionalExpression>node).questionToken) ||
@@ -2361,12 +2363,14 @@ namespace ts {
case SyntaxKind.NumberKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.UndefinedKeyword:
// If these are followed by a dot, then parse these out as a dotted type reference instead.
const node = tryParse(parseKeywordAndNoDot);
return node || parseTypeReference();
case SyntaxKind.StringLiteral:
return parseStringLiteralTypeNode();
case SyntaxKind.VoidKeyword:
case SyntaxKind.NullKeyword:
return parseTokenNode<TypeNode>();
case SyntaxKind.ThisKeyword: {
const thisKeyword = parseThisTypeNode();
@@ -2398,6 +2402,8 @@ namespace ts {
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.ThisKeyword:
case SyntaxKind.TypeOfKeyword:
case SyntaxKind.OpenBraceToken:
@@ -3724,6 +3730,14 @@ namespace ts {
continue;
}
if (token === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
nextToken();
const nonNullExpression = <NonNullExpression>createNode(SyntaxKind.NonNullExpression, expression.pos);
nonNullExpression.expression = expression;
expression = finishNode(nonNullExpression);
continue;
}
// when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName
if (!inDecoratorContext() && parseOptional(SyntaxKind.OpenBracketToken)) {
const indexedAccess = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, expression.pos);
+1
View File
@@ -114,6 +114,7 @@ namespace ts {
"try": SyntaxKind.TryKeyword,
"type": SyntaxKind.TypeKeyword,
"typeof": SyntaxKind.TypeOfKeyword,
"undefined": SyntaxKind.UndefinedKeyword,
"var": SyntaxKind.VarKeyword,
"void": SyntaxKind.VoidKeyword,
"while": SyntaxKind.WhileKeyword,
+22 -3
View File
@@ -171,6 +171,7 @@ namespace ts {
StringKeyword,
SymbolKeyword,
TypeKeyword,
UndefinedKeyword,
FromKeyword,
GlobalKeyword,
OfKeyword, // LastKeyword and LastToken
@@ -240,6 +241,7 @@ namespace ts {
OmittedExpression,
ExpressionWithTypeArguments,
AsExpression,
NonNullExpression,
// Misc
TemplateSpan,
@@ -475,6 +477,11 @@ namespace ts {
originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later
}
// Transient identifier node (marked by id === -1)
export interface TransientIdentifier extends Identifier {
resolvedSymbol: Symbol;
}
// @kind(SyntaxKind.QualifiedName)
export interface QualifiedName extends Node {
// Must have same layout as PropertyAccess
@@ -968,6 +975,8 @@ namespace ts {
name: Identifier;
}
export type IdentifierOrPropertyAccess = Identifier | PropertyAccessExpression;
// @kind(SyntaxKind.ElementAccessExpression)
export interface ElementAccessExpression extends MemberExpression {
expression: LeftHandSideExpression;
@@ -1012,6 +1021,11 @@ namespace ts {
export type AssertionExpression = TypeAssertion | AsExpression;
// @kind(SyntaxKind.NonNullExpression)
export interface NonNullExpression extends LeftHandSideExpression {
expression: Expression;
}
/// A JSX expression of the form <TagName attrs>...</TagName>
// @kind(SyntaxKind.JsxElement)
export interface JsxElement extends PrimaryExpression {
@@ -2029,7 +2043,9 @@ namespace ts {
exportsChecked?: boolean; // True if exports of external module have been checked
isDeclarationWithCollidingName?: boolean; // True if symbol is block scoped redeclaration
bindingElement?: BindingElement; // Binding element associated with property symbol
exportsSomeValue?: boolean; // true if module exports some value (not just types)
exportsSomeValue?: boolean; // True if module exports some value (not just types)
firstAssignmentChecked?: boolean; // True if first assignment node has been computed
firstAssignment?: Node; // First assignment node (undefined if no assignments)
}
/* @internal */
@@ -2072,7 +2088,7 @@ namespace ts {
isVisible?: boolean; // Is this node visible
generatedName?: string; // Generated name for module, enum, or import declaration
generatedNames?: Map<string>; // Generated names table for source file
assignmentChecks?: Map<boolean>; // Cache of assignment checks
assignmentMap?: Map<boolean>; // Cached map of references assigned within this node
hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context
importOnRightSide?: Symbol; // for import declarations - import that appear on the right side
jsxFlags?: JsxFlags; // flags for knowing what kind of element/attributes we're dealing with
@@ -2106,7 +2122,7 @@ namespace ts {
/* @internal */
FreshObjectLiteral = 0x00100000, // Fresh object literal type
/* @internal */
ContainsUndefinedOrNull = 0x00200000, // Type is or contains Undefined or Null type
ContainsUndefinedOrNull = 0x00200000, // Type is or contains undefined or null type
/* @internal */
ContainsObjectLiteral = 0x00400000, // Type is or contains object literal type
/* @internal */
@@ -2115,6 +2131,8 @@ namespace ts {
ThisType = 0x02000000, // This type
ObjectLiteralPatternWithComputedProperties = 0x04000000, // Object literal type implied by binding pattern has computed properties
/* @internal */
Nullable = Undefined | Null,
/* @internal */
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null,
/* @internal */
@@ -2439,6 +2457,7 @@ namespace ts {
allowSyntheticDefaultImports?: boolean;
allowJs?: boolean;
noImplicitUseStrict?: boolean;
strictNullChecks?: boolean;
lib?: string[];
/* @internal */ stripInternal?: boolean;
+3
View File
@@ -511,6 +511,7 @@ namespace ts {
case SyntaxKind.StringKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.UndefinedKeyword:
return true;
case SyntaxKind.VoidKeyword:
return node.parent.kind !== SyntaxKind.VoidExpression;
@@ -968,6 +969,7 @@ namespace ts {
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.AsExpression:
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.NonNullExpression:
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ClassExpression:
@@ -2406,6 +2408,7 @@ namespace ts {
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.CallExpression:
case SyntaxKind.NonNullExpression:
case SyntaxKind.JsxElement:
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.TaggedTemplateExpression: