Introduce nullable types in checker

This commit is contained in:
Anders Hejlsberg
2016-02-15 09:34:14 -08:00
parent e79df80e22
commit 6d6d2a11bc
2 changed files with 61 additions and 5 deletions

View File

@@ -51,6 +51,8 @@ namespace ts {
const languageVersion = compilerOptions.target || ScriptTarget.ES3;
const modulekind = getEmitModuleKind(compilerOptions);
const allowSyntheticDefaultImports = typeof compilerOptions.allowSyntheticDefaultImports !== "undefined" ? compilerOptions.allowSyntheticDefaultImports : modulekind === ModuleKind.System;
const strictNullChecks = compilerOptions.strictNullChecks;
const emitResolver = createResolver();
@@ -2340,6 +2342,7 @@ namespace ts {
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
case SyntaxKind.ParenthesizedType:
case SyntaxKind.NullableType:
return isDeclarationVisible(<Declaration>node.parent);
// Default binding, import specifier and namespace import is visible
@@ -4664,6 +4667,14 @@ namespace ts {
return links.resolvedType;
}
function getTypeFromNullableTypeNode(node: NullableTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = getNullableType(getTypeFromTypeNode(node.type));
}
return links.resolvedType;
}
function addTypeToSet(typeSet: Type[], type: Type, typeSetKind: TypeFlags) {
if (type.flags & typeSetKind) {
addTypesToSet(typeSet, (<UnionOrIntersectionType>type).types, typeSetKind);
@@ -4736,8 +4747,10 @@ namespace ts {
return anyType;
}
if (noSubtypeReduction) {
removeAllButLast(typeSet, undefinedType);
removeAllButLast(typeSet, nullType);
if (!strictNullChecks) {
removeAllButLast(typeSet, undefinedType);
removeAllButLast(typeSet, nullType);
}
}
else {
removeSubtypes(typeSet);
@@ -4920,6 +4933,8 @@ namespace ts {
return getTypeFromUnionTypeNode(<UnionTypeNode>node);
case SyntaxKind.IntersectionType:
return getTypeFromIntersectionTypeNode(<IntersectionTypeNode>node);
case SyntaxKind.NullableType:
return getTypeFromNullableTypeNode(<NullableTypeNode>node);
case SyntaxKind.ParenthesizedType:
case SyntaxKind.JSDocNullableType:
case SyntaxKind.JSDocNonNullableType:
@@ -5415,7 +5430,9 @@ namespace ts {
}
if (isTypeAny(target)) return Ternary.True;
if (source.flags & TypeFlags.Undefined) return Ternary.True;
if (source.flags & TypeFlags.Undefined) {
if (!strictNullChecks || target.flags & TypeFlags.Undefined) return Ternary.True;
}
if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True;
if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum) {
if (result = enumRelatedTo(source, target)) {
@@ -6262,6 +6279,41 @@ namespace ts {
return !!(type.flags & TypeFlags.Tuple);
}
function isNullableType(type: Type): boolean {
if (type.flags & TypeFlags.Undefined) {
return true;
}
if (type.flags & TypeFlags.Union) {
for (const t of (type as UnionType).types) {
if (t.flags & TypeFlags.Undefined) {
return true;
}
}
}
return false;
}
function getNullableType(type: Type): Type {
if (!strictNullChecks) {
return type;
}
if (!type.nullableType) {
type.nullableType = isNullableType(type) ? type : getUnionType([type, undefinedType]);
}
return type.nullableType;
}
function getNonNullableTypeFromUnionType(type: UnionType): Type {
if (!type.nonNullableType) {
type.nonNullableType = removeTypesFromUnionOrIntersection(type, [undefinedType, nullType]);
}
return type.nonNullableType;
}
function getNonNullableType(type: Type): Type {
return strictNullChecks && type.flags & TypeFlags.Union ? getNonNullableTypeFromUnionType(type as UnionType) : type;
}
function getRegularTypeOfObjectLiteral(type: Type): Type {
if (type.flags & TypeFlags.FreshObjectLiteral) {
let regularType = (<FreshObjectLiteralType>type).regularType;
@@ -14988,7 +15040,8 @@ namespace ts {
case SyntaxKind.IntersectionType:
return checkUnionOrIntersectionType(<UnionOrIntersectionTypeNode>node);
case SyntaxKind.ParenthesizedType:
return checkSourceElement((<ParenthesizedTypeNode>node).type);
case SyntaxKind.NullableType:
return checkSourceElement((<ParenthesizedTypeNode | NullableTypeNode>node).type);
case SyntaxKind.FunctionDeclaration:
return checkFunctionDeclaration(<FunctionDeclaration>node);
case SyntaxKind.Block:

View File

@@ -2125,6 +2125,7 @@ namespace ts {
/* @internal */ id: number; // Unique ID
symbol?: Symbol; // Symbol associated with type (if any)
pattern?: DestructuringPattern; // Destructuring pattern represented by type (if any)
nullableType?: Type; // Cached nullable form of this type
}
/* @internal */
@@ -2197,7 +2198,9 @@ namespace ts {
resolvedProperties: SymbolTable; // Cache of resolved properties
}
export interface UnionType extends UnionOrIntersectionType { }
export interface UnionType extends UnionOrIntersectionType {
nonNullableType?: Type; // Cached non-nullable form of type
}
export interface IntersectionType extends UnionOrIntersectionType { }