From 251723826962cc3fa3cc2d766c17dc197099cce3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg <andersh@microsoft.com> Date: Thu, 2 Jun 2016 06:32:14 -0700 Subject: [PATCH 1/3] Add non-widening forms of null and undefined --- src/compiler/checker.ts | 37 ++++++++++++++++++++----------------- src/compiler/types.ts | 6 +++--- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 06ef246340252..6166234dcf4d3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -110,16 +110,17 @@ namespace ts { const unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown"); const resolvingSymbol = createSymbol(SymbolFlags.Transient, "__resolving__"); - const nullableWideningFlags = strictNullChecks ? 0 : TypeFlags.ContainsUndefinedOrNull; const anyType = createIntrinsicType(TypeFlags.Any, "any"); const stringType = createIntrinsicType(TypeFlags.String, "string"); const numberType = createIntrinsicType(TypeFlags.Number, "number"); const booleanType = createIntrinsicType(TypeFlags.Boolean, "boolean"); const esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol"); const voidType = createIntrinsicType(TypeFlags.Void, "void"); - const undefinedType = createIntrinsicType(TypeFlags.Undefined | nullableWideningFlags, "undefined"); - const nullType = createIntrinsicType(TypeFlags.Null | nullableWideningFlags, "null"); - const emptyArrayElementType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsUndefinedOrNull, "undefined"); + const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined"); + const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined"); + const nullType = createIntrinsicType(TypeFlags.Null, "null"); + const nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null | TypeFlags.ContainsWideningType, "null"); + const emptyArrayElementType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined"); const unknownType = createIntrinsicType(TypeFlags.Any, "unknown"); const neverType = createIntrinsicType(TypeFlags.Never, "never"); @@ -3405,7 +3406,7 @@ namespace ts { error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, symbolToString(type.symbol)); return type.resolvedBaseConstructorType = unknownType; } - if (baseConstructorType !== unknownType && baseConstructorType !== nullType && !isConstructorType(baseConstructorType)) { + if (baseConstructorType !== unknownType && baseConstructorType !== nullWideningType && !isConstructorType(baseConstructorType)) { error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, typeToString(baseConstructorType)); return type.resolvedBaseConstructorType = unknownType; } @@ -5011,6 +5012,7 @@ namespace ts { containsAny?: boolean; containsUndefined?: boolean; containsNull?: boolean; + containsNonWideningType?: boolean; } function addTypeToSet(typeSet: TypeSet, type: Type, typeSetKind: TypeFlags) { @@ -5021,6 +5023,7 @@ namespace ts { if (type.flags & TypeFlags.Any) typeSet.containsAny = true; if (type.flags & TypeFlags.Undefined) typeSet.containsUndefined = true; if (type.flags & TypeFlags.Null) typeSet.containsNull = true; + if (!(type.flags & TypeFlags.ContainsWideningType)) typeSet.containsNonWideningType = true; } else if (type !== neverType && !contains(typeSet, type)) { typeSet.push(type); @@ -5081,8 +5084,8 @@ namespace ts { removeSubtypes(typeSet); } if (typeSet.length === 0) { - return typeSet.containsNull ? nullType : - typeSet.containsUndefined ? undefinedType : + return typeSet.containsNull ? typeSet.containsNonWideningType ? nullType : nullWideningType : + typeSet.containsUndefined ? typeSet.containsNonWideningType ? undefinedType : undefinedWideningType : neverType; } else if (typeSet.length === 1) { @@ -5882,7 +5885,7 @@ namespace ts { if (!(target.flags & TypeFlags.Never)) { if (target.flags & TypeFlags.Any || source.flags & TypeFlags.Never) return Ternary.True; if (source.flags & TypeFlags.Undefined) { - if (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void) || source === emptyArrayElementType) return Ternary.True; + if (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void)) return Ternary.True; } if (source.flags & TypeFlags.Null) { if (!strictNullChecks || target.flags & TypeFlags.Null) return Ternary.True; @@ -6972,7 +6975,7 @@ namespace ts { if (type.flags & TypeFlags.ObjectLiteral) { for (const p of getPropertiesOfObjectType(type)) { const t = getTypeOfSymbol(p); - if (t.flags & TypeFlags.ContainsUndefinedOrNull) { + if (t.flags & TypeFlags.ContainsWideningType) { if (!reportWideningErrorsInType(t)) { error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(getWidenedType(t))); } @@ -7019,7 +7022,7 @@ namespace ts { } function reportErrorsFromWidening(declaration: Declaration, type: Type) { - if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsUndefinedOrNull) { + if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsWideningType) { // Report implicit any error within type if possible, otherwise report error on declaration if (!reportWideningErrorsInType(type)) { reportImplicitAnyError(declaration, type); @@ -8311,7 +8314,7 @@ namespace ts { const classInstanceType = <InterfaceType>getDeclaredTypeOfSymbol(classSymbol); const baseConstructorType = getBaseConstructorTypeOfClass(classInstanceType); - return baseConstructorType === nullType; + return baseConstructorType === nullWideningType; } function checkThisExpression(node: Node): Type { @@ -9202,7 +9205,7 @@ namespace ts { } } } - return createArrayType(elementTypes.length ? getUnionType(elementTypes) : emptyArrayElementType); + return createArrayType(elementTypes.length ? getUnionType(elementTypes) : strictNullChecks ? neverType : undefinedWideningType); } function isNumericName(name: DeclarationName): boolean { @@ -12002,7 +12005,7 @@ namespace ts { function checkVoidExpression(node: VoidExpression): Type { checkExpression(node.expression); - return undefinedType; + return undefinedWideningType; } function checkAwaitExpression(node: AwaitExpression): Type { @@ -12409,7 +12412,7 @@ namespace ts { case SyntaxKind.InKeyword: return checkInExpression(left, right, leftType, rightType); case SyntaxKind.AmpersandAmpersandToken: - return addNullableKind(rightType, getNullableKind(leftType)); + return strictNullChecks ? addNullableKind(rightType, getNullableKind(leftType)) : rightType; case SyntaxKind.BarBarToken: return getUnionType([getNonNullableType(leftType), rightType]); case SyntaxKind.EqualsToken: @@ -12676,7 +12679,7 @@ namespace ts { case SyntaxKind.SuperKeyword: return checkSuperExpression(node); case SyntaxKind.NullKeyword: - return nullType; + return nullWideningType; case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: return booleanType; @@ -12734,7 +12737,7 @@ namespace ts { case SyntaxKind.SpreadElementExpression: return checkSpreadElementExpression(<SpreadElementExpression>node, contextualMapper); case SyntaxKind.OmittedExpression: - return undefinedType; + return undefinedWideningType; case SyntaxKind.YieldExpression: return checkYieldExpression(<YieldExpression>node); case SyntaxKind.JsxExpression: @@ -17648,7 +17651,7 @@ namespace ts { // Setup global builtins addToSymbolTable(globals, builtinGlobals, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0); - getSymbolLinks(undefinedSymbol).type = undefinedType; + getSymbolLinks(undefinedSymbol).type = undefinedWideningType; getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments"); getSymbolLinks(unknownSymbol).type = unknownType; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c7e14a1003108..4c0e7a036dbf4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2197,7 +2197,7 @@ namespace ts { /* @internal */ FreshObjectLiteral = 0x00100000, // Fresh object literal type /* @internal */ - ContainsUndefinedOrNull = 0x00200000, // Type is or contains undefined or null type + ContainsWideningType = 0x00200000, // Type is or contains undefined or null widening type /* @internal */ ContainsObjectLiteral = 0x00400000, // Type is or contains object literal type /* @internal */ @@ -2220,9 +2220,9 @@ namespace ts { StructuredType = ObjectType | Union | Intersection, Narrowable = Any | ObjectType | Union | TypeParameter, /* @internal */ - RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral, + RequiresWidening = ContainsWideningType | ContainsObjectLiteral, /* @internal */ - PropagatingFlags = ContainsUndefinedOrNull | ContainsObjectLiteral | ContainsAnyFunctionType + PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | ContainsAnyFunctionType } export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; From 20bab14224bf9f7a7228f416a61807b1f7f73e4a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg <andersh@microsoft.com> Date: Thu, 2 Jun 2016 09:39:47 -0700 Subject: [PATCH 2/3] Add tests --- .../reference/arrayLiteralWidened.js | 15 ++++ .../reference/arrayLiteralWidened.symbols | 38 +++++++-- .../reference/arrayLiteralWidened.types | 29 +++++++ .../reference/initializersWidened.js | 42 +++++++++- .../reference/initializersWidened.symbols | 55 ++++++++++++- .../reference/initializersWidened.types | 77 ++++++++++++++++++- .../logicalAndOperatorWithEveryType.types | 2 +- .../reference/objectLiteralWidened.js | 40 +++++++++- .../reference/objectLiteralWidened.symbols | 53 +++++++++++-- .../reference/objectLiteralWidened.types | 54 ++++++++++++- .../reference/strictNullChecksNoWidening.js | 31 ++++++++ .../strictNullChecksNoWidening.symbols | 48 ++++++++++++ .../strictNullChecksNoWidening.types | 67 ++++++++++++++++ .../widenedTypes/arrayLiteralWidened.ts | 9 +++ .../widenedTypes/initializersWidened.ts | 24 +++++- .../widenedTypes/objectLiteralWidened.ts | 22 +++++- .../strictNullChecksNoWidening.ts | 17 ++++ 17 files changed, 584 insertions(+), 39 deletions(-) create mode 100644 tests/baselines/reference/strictNullChecksNoWidening.js create mode 100644 tests/baselines/reference/strictNullChecksNoWidening.symbols create mode 100644 tests/baselines/reference/strictNullChecksNoWidening.types create mode 100644 tests/cases/conformance/types/typeRelationships/widenedTypes/strictNullChecksNoWidening.ts diff --git a/tests/baselines/reference/arrayLiteralWidened.js b/tests/baselines/reference/arrayLiteralWidened.js index a250c47849d57..5b7346b87381b 100644 --- a/tests/baselines/reference/arrayLiteralWidened.js +++ b/tests/baselines/reference/arrayLiteralWidened.js @@ -2,6 +2,7 @@ // array literals are widened upon assignment according to their element type var a = []; // any[] +var a = [,,]; var a = [null, null]; var a = [undefined, undefined]; @@ -12,11 +13,20 @@ var b = [[undefined, undefined]]; var c = [[[]]]; // any[][][] var c = [[[null]],[undefined]] + +// no widening when one or more elements are non-widening + +var x: undefined = undefined; + +var d = [x]; +var d = [, x]; +var d = [undefined, x]; //// [arrayLiteralWidened.js] // array literals are widened upon assignment according to their element type var a = []; // any[] +var a = [, ,]; var a = [null, null]; var a = [undefined, undefined]; var b = [[], [null, null]]; // any[][] @@ -24,3 +34,8 @@ var b = [[], []]; var b = [[undefined, undefined]]; var c = [[[]]]; // any[][][] var c = [[[null]], [undefined]]; +// no widening when one or more elements are non-widening +var x = undefined; +var d = [x]; +var d = [, x]; +var d = [undefined, x]; diff --git a/tests/baselines/reference/arrayLiteralWidened.symbols b/tests/baselines/reference/arrayLiteralWidened.symbols index ba058aeded114..48137812a5dfc 100644 --- a/tests/baselines/reference/arrayLiteralWidened.symbols +++ b/tests/baselines/reference/arrayLiteralWidened.symbols @@ -2,31 +2,53 @@ // array literals are widened upon assignment according to their element type var a = []; // any[] ->a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 4, 3), Decl(arrayLiteralWidened.ts, 5, 3)) +>a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 3, 3), Decl(arrayLiteralWidened.ts, 5, 3), Decl(arrayLiteralWidened.ts, 6, 3)) + +var a = [,,]; +>a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 3, 3), Decl(arrayLiteralWidened.ts, 5, 3), Decl(arrayLiteralWidened.ts, 6, 3)) var a = [null, null]; ->a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 4, 3), Decl(arrayLiteralWidened.ts, 5, 3)) +>a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 3, 3), Decl(arrayLiteralWidened.ts, 5, 3), Decl(arrayLiteralWidened.ts, 6, 3)) var a = [undefined, undefined]; ->a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 4, 3), Decl(arrayLiteralWidened.ts, 5, 3)) +>a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 3, 3), Decl(arrayLiteralWidened.ts, 5, 3), Decl(arrayLiteralWidened.ts, 6, 3)) >undefined : Symbol(undefined) >undefined : Symbol(undefined) var b = [[], [null, null]]; // any[][] ->b : Symbol(b, Decl(arrayLiteralWidened.ts, 7, 3), Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3)) +>b : Symbol(b, Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3), Decl(arrayLiteralWidened.ts, 10, 3)) var b = [[], []]; ->b : Symbol(b, Decl(arrayLiteralWidened.ts, 7, 3), Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3)) +>b : Symbol(b, Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3), Decl(arrayLiteralWidened.ts, 10, 3)) var b = [[undefined, undefined]]; ->b : Symbol(b, Decl(arrayLiteralWidened.ts, 7, 3), Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3)) +>b : Symbol(b, Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3), Decl(arrayLiteralWidened.ts, 10, 3)) >undefined : Symbol(undefined) >undefined : Symbol(undefined) var c = [[[]]]; // any[][][] ->c : Symbol(c, Decl(arrayLiteralWidened.ts, 11, 3), Decl(arrayLiteralWidened.ts, 12, 3)) +>c : Symbol(c, Decl(arrayLiteralWidened.ts, 12, 3), Decl(arrayLiteralWidened.ts, 13, 3)) var c = [[[null]],[undefined]] ->c : Symbol(c, Decl(arrayLiteralWidened.ts, 11, 3), Decl(arrayLiteralWidened.ts, 12, 3)) +>c : Symbol(c, Decl(arrayLiteralWidened.ts, 12, 3), Decl(arrayLiteralWidened.ts, 13, 3)) +>undefined : Symbol(undefined) + +// no widening when one or more elements are non-widening + +var x: undefined = undefined; +>x : Symbol(x, Decl(arrayLiteralWidened.ts, 17, 3)) +>undefined : Symbol(undefined) + +var d = [x]; +>d : Symbol(d, Decl(arrayLiteralWidened.ts, 19, 3), Decl(arrayLiteralWidened.ts, 20, 3), Decl(arrayLiteralWidened.ts, 21, 3)) +>x : Symbol(x, Decl(arrayLiteralWidened.ts, 17, 3)) + +var d = [, x]; +>d : Symbol(d, Decl(arrayLiteralWidened.ts, 19, 3), Decl(arrayLiteralWidened.ts, 20, 3), Decl(arrayLiteralWidened.ts, 21, 3)) +>x : Symbol(x, Decl(arrayLiteralWidened.ts, 17, 3)) + +var d = [undefined, x]; +>d : Symbol(d, Decl(arrayLiteralWidened.ts, 19, 3), Decl(arrayLiteralWidened.ts, 20, 3), Decl(arrayLiteralWidened.ts, 21, 3)) >undefined : Symbol(undefined) +>x : Symbol(x, Decl(arrayLiteralWidened.ts, 17, 3)) diff --git a/tests/baselines/reference/arrayLiteralWidened.types b/tests/baselines/reference/arrayLiteralWidened.types index 83db7046eed4a..6237cd79a7edb 100644 --- a/tests/baselines/reference/arrayLiteralWidened.types +++ b/tests/baselines/reference/arrayLiteralWidened.types @@ -5,6 +5,12 @@ var a = []; // any[] >a : any[] >[] : undefined[] +var a = [,,]; +>a : any[] +>[,,] : undefined[] +> : undefined +> : undefined + var a = [null, null]; >a : any[] >[null, null] : null[] @@ -53,3 +59,26 @@ var c = [[[null]],[undefined]] >[undefined] : undefined[] >undefined : undefined +// no widening when one or more elements are non-widening + +var x: undefined = undefined; +>x : undefined +>undefined : undefined + +var d = [x]; +>d : undefined[] +>[x] : undefined[] +>x : undefined + +var d = [, x]; +>d : undefined[] +>[, x] : undefined[] +> : undefined +>x : undefined + +var d = [undefined, x]; +>d : undefined[] +>[undefined, x] : undefined[] +>undefined : undefined +>x : undefined + diff --git a/tests/baselines/reference/initializersWidened.js b/tests/baselines/reference/initializersWidened.js index fce0750a600c8..3954735ee6ede 100644 --- a/tests/baselines/reference/initializersWidened.js +++ b/tests/baselines/reference/initializersWidened.js @@ -1,10 +1,44 @@ //// [initializersWidened.ts] // these are widened to any at the point of assignment -var x = null; -var y = undefined; +var x1 = null; +var y1 = undefined; +var z1 = void 0; + +// these are not widened + +var x2: null; +var y2: undefined; + +var x3: null = null; +var y3: undefined = undefined; +var z3: undefined = void 0; + +// widen only when all constituents of union are widening + +var x4 = null || null; +var y4 = undefined || undefined; +var z4 = void 0 || void 0; + +var x5 = null || x2; +var y5 = undefined || y2; +var z5 = void 0 || y2; //// [initializersWidened.js] // these are widened to any at the point of assignment -var x = null; -var y = undefined; +var x1 = null; +var y1 = undefined; +var z1 = void 0; +// these are not widened +var x2; +var y2; +var x3 = null; +var y3 = undefined; +var z3 = void 0; +// widen only when all constituents of union are widening +var x4 = null || null; +var y4 = undefined || undefined; +var z4 = void 0 || void 0; +var x5 = null || x2; +var y5 = undefined || y2; +var z5 = void 0 || y2; diff --git a/tests/baselines/reference/initializersWidened.symbols b/tests/baselines/reference/initializersWidened.symbols index 625c066a0587e..252a248bec867 100644 --- a/tests/baselines/reference/initializersWidened.symbols +++ b/tests/baselines/reference/initializersWidened.symbols @@ -1,10 +1,57 @@ === tests/cases/conformance/types/typeRelationships/widenedTypes/initializersWidened.ts === // these are widened to any at the point of assignment -var x = null; ->x : Symbol(x, Decl(initializersWidened.ts, 2, 3)) +var x1 = null; +>x1 : Symbol(x1, Decl(initializersWidened.ts, 2, 3)) -var y = undefined; ->y : Symbol(y, Decl(initializersWidened.ts, 3, 3)) +var y1 = undefined; +>y1 : Symbol(y1, Decl(initializersWidened.ts, 3, 3)) >undefined : Symbol(undefined) +var z1 = void 0; +>z1 : Symbol(z1, Decl(initializersWidened.ts, 4, 3)) + +// these are not widened + +var x2: null; +>x2 : Symbol(x2, Decl(initializersWidened.ts, 8, 3)) + +var y2: undefined; +>y2 : Symbol(y2, Decl(initializersWidened.ts, 9, 3)) + +var x3: null = null; +>x3 : Symbol(x3, Decl(initializersWidened.ts, 11, 3)) + +var y3: undefined = undefined; +>y3 : Symbol(y3, Decl(initializersWidened.ts, 12, 3)) +>undefined : Symbol(undefined) + +var z3: undefined = void 0; +>z3 : Symbol(z3, Decl(initializersWidened.ts, 13, 3)) + +// widen only when all constituents of union are widening + +var x4 = null || null; +>x4 : Symbol(x4, Decl(initializersWidened.ts, 17, 3)) + +var y4 = undefined || undefined; +>y4 : Symbol(y4, Decl(initializersWidened.ts, 18, 3)) +>undefined : Symbol(undefined) +>undefined : Symbol(undefined) + +var z4 = void 0 || void 0; +>z4 : Symbol(z4, Decl(initializersWidened.ts, 19, 3)) + +var x5 = null || x2; +>x5 : Symbol(x5, Decl(initializersWidened.ts, 21, 3)) +>x2 : Symbol(x2, Decl(initializersWidened.ts, 8, 3)) + +var y5 = undefined || y2; +>y5 : Symbol(y5, Decl(initializersWidened.ts, 22, 3)) +>undefined : Symbol(undefined) +>y2 : Symbol(y2, Decl(initializersWidened.ts, 9, 3)) + +var z5 = void 0 || y2; +>z5 : Symbol(z5, Decl(initializersWidened.ts, 23, 3)) +>y2 : Symbol(y2, Decl(initializersWidened.ts, 9, 3)) + diff --git a/tests/baselines/reference/initializersWidened.types b/tests/baselines/reference/initializersWidened.types index 157055892460a..766f859029af9 100644 --- a/tests/baselines/reference/initializersWidened.types +++ b/tests/baselines/reference/initializersWidened.types @@ -1,11 +1,80 @@ === tests/cases/conformance/types/typeRelationships/widenedTypes/initializersWidened.ts === // these are widened to any at the point of assignment -var x = null; ->x : any +var x1 = null; +>x1 : any >null : null -var y = undefined; ->y : any +var y1 = undefined; +>y1 : any >undefined : undefined +var z1 = void 0; +>z1 : any +>void 0 : undefined +>0 : number + +// these are not widened + +var x2: null; +>x2 : null +>null : null + +var y2: undefined; +>y2 : undefined + +var x3: null = null; +>x3 : null +>null : null +>null : null + +var y3: undefined = undefined; +>y3 : undefined +>undefined : undefined + +var z3: undefined = void 0; +>z3 : undefined +>void 0 : undefined +>0 : number + +// widen only when all constituents of union are widening + +var x4 = null || null; +>x4 : any +>null || null : null +>null : null +>null : null + +var y4 = undefined || undefined; +>y4 : any +>undefined || undefined : undefined +>undefined : undefined +>undefined : undefined + +var z4 = void 0 || void 0; +>z4 : any +>void 0 || void 0 : undefined +>void 0 : undefined +>0 : number +>void 0 : undefined +>0 : number + +var x5 = null || x2; +>x5 : null +>null || x2 : null +>null : null +>x2 : null + +var y5 = undefined || y2; +>y5 : undefined +>undefined || y2 : undefined +>undefined : undefined +>y2 : undefined + +var z5 = void 0 || y2; +>z5 : undefined +>void 0 || y2 : undefined +>void 0 : undefined +>0 : number +>y2 : undefined + diff --git a/tests/baselines/reference/logicalAndOperatorWithEveryType.types b/tests/baselines/reference/logicalAndOperatorWithEveryType.types index b2628eed9219f..bd913e94da58c 100644 --- a/tests/baselines/reference/logicalAndOperatorWithEveryType.types +++ b/tests/baselines/reference/logicalAndOperatorWithEveryType.types @@ -623,7 +623,7 @@ var rj8 = a8 && undefined; var rj9 = null && undefined; >rj9 : any ->null && undefined : null +>null && undefined : undefined >null : null >undefined : undefined diff --git a/tests/baselines/reference/objectLiteralWidened.js b/tests/baselines/reference/objectLiteralWidened.js index 4de228cb14a7f..98d79133540bd 100644 --- a/tests/baselines/reference/objectLiteralWidened.js +++ b/tests/baselines/reference/objectLiteralWidened.js @@ -1,29 +1,61 @@ //// [objectLiteralWidened.ts] // object literal properties are widened to any -var x = { +var x1 = { foo: null, bar: undefined } -var y = { +var y1 = { foo: null, bar: { baz: null, boo: undefined } +} + +// these are not widened + +var u: undefined = undefined; +var n: null = null; + +var x2 = { + foo: n, + bar: u +} + +var y2 = { + foo: n, + bar: { + baz: n, + boo: u + } } //// [objectLiteralWidened.js] // object literal properties are widened to any -var x = { +var x1 = { foo: null, bar: undefined }; -var y = { +var y1 = { foo: null, bar: { baz: null, boo: undefined } }; +// these are not widened +var u = undefined; +var n = null; +var x2 = { + foo: n, + bar: u +}; +var y2 = { + foo: n, + bar: { + baz: n, + boo: u + } +}; diff --git a/tests/baselines/reference/objectLiteralWidened.symbols b/tests/baselines/reference/objectLiteralWidened.symbols index 0bf077cd9d8a1..4b2a1b4a00185 100644 --- a/tests/baselines/reference/objectLiteralWidened.symbols +++ b/tests/baselines/reference/objectLiteralWidened.symbols @@ -1,22 +1,22 @@ === tests/cases/conformance/types/typeRelationships/widenedTypes/objectLiteralWidened.ts === // object literal properties are widened to any -var x = { ->x : Symbol(x, Decl(objectLiteralWidened.ts, 2, 3)) +var x1 = { +>x1 : Symbol(x1, Decl(objectLiteralWidened.ts, 2, 3)) foo: null, ->foo : Symbol(foo, Decl(objectLiteralWidened.ts, 2, 9)) +>foo : Symbol(foo, Decl(objectLiteralWidened.ts, 2, 10)) bar: undefined >bar : Symbol(bar, Decl(objectLiteralWidened.ts, 3, 14)) >undefined : Symbol(undefined) } -var y = { ->y : Symbol(y, Decl(objectLiteralWidened.ts, 7, 3)) +var y1 = { +>y1 : Symbol(y1, Decl(objectLiteralWidened.ts, 7, 3)) foo: null, ->foo : Symbol(foo, Decl(objectLiteralWidened.ts, 7, 9)) +>foo : Symbol(foo, Decl(objectLiteralWidened.ts, 7, 10)) bar: { >bar : Symbol(bar, Decl(objectLiteralWidened.ts, 8, 14)) @@ -29,3 +29,44 @@ var y = { >undefined : Symbol(undefined) } } + +// these are not widened + +var u: undefined = undefined; +>u : Symbol(u, Decl(objectLiteralWidened.ts, 17, 3)) +>undefined : Symbol(undefined) + +var n: null = null; +>n : Symbol(n, Decl(objectLiteralWidened.ts, 18, 3)) + +var x2 = { +>x2 : Symbol(x2, Decl(objectLiteralWidened.ts, 20, 3)) + + foo: n, +>foo : Symbol(foo, Decl(objectLiteralWidened.ts, 20, 10)) +>n : Symbol(n, Decl(objectLiteralWidened.ts, 18, 3)) + + bar: u +>bar : Symbol(bar, Decl(objectLiteralWidened.ts, 21, 11)) +>u : Symbol(u, Decl(objectLiteralWidened.ts, 17, 3)) +} + +var y2 = { +>y2 : Symbol(y2, Decl(objectLiteralWidened.ts, 25, 3)) + + foo: n, +>foo : Symbol(foo, Decl(objectLiteralWidened.ts, 25, 10)) +>n : Symbol(n, Decl(objectLiteralWidened.ts, 18, 3)) + + bar: { +>bar : Symbol(bar, Decl(objectLiteralWidened.ts, 26, 11)) + + baz: n, +>baz : Symbol(baz, Decl(objectLiteralWidened.ts, 27, 10)) +>n : Symbol(n, Decl(objectLiteralWidened.ts, 18, 3)) + + boo: u +>boo : Symbol(boo, Decl(objectLiteralWidened.ts, 28, 15)) +>u : Symbol(u, Decl(objectLiteralWidened.ts, 17, 3)) + } +} diff --git a/tests/baselines/reference/objectLiteralWidened.types b/tests/baselines/reference/objectLiteralWidened.types index 9f47e47795d56..66309202617d9 100644 --- a/tests/baselines/reference/objectLiteralWidened.types +++ b/tests/baselines/reference/objectLiteralWidened.types @@ -1,8 +1,8 @@ === tests/cases/conformance/types/typeRelationships/widenedTypes/objectLiteralWidened.ts === // object literal properties are widened to any -var x = { ->x : { foo: any; bar: any; } +var x1 = { +>x1 : { foo: any; bar: any; } >{ foo: null, bar: undefined} : { foo: null; bar: undefined; } foo: null, @@ -14,8 +14,8 @@ var x = { >undefined : undefined } -var y = { ->y : { foo: any; bar: { baz: any; boo: any; }; } +var y1 = { +>y1 : { foo: any; bar: { baz: any; boo: any; }; } >{ foo: null, bar: { baz: null, boo: undefined }} : { foo: null; bar: { baz: null; boo: undefined; }; } foo: null, @@ -35,3 +35,49 @@ var y = { >undefined : undefined } } + +// these are not widened + +var u: undefined = undefined; +>u : undefined +>undefined : undefined + +var n: null = null; +>n : null +>null : null +>null : null + +var x2 = { +>x2 : { foo: null; bar: undefined; } +>{ foo: n, bar: u} : { foo: null; bar: undefined; } + + foo: n, +>foo : null +>n : null + + bar: u +>bar : undefined +>u : undefined +} + +var y2 = { +>y2 : { foo: null; bar: { baz: null; boo: undefined; }; } +>{ foo: n, bar: { baz: n, boo: u }} : { foo: null; bar: { baz: null; boo: undefined; }; } + + foo: n, +>foo : null +>n : null + + bar: { +>bar : { baz: null; boo: undefined; } +>{ baz: n, boo: u } : { baz: null; boo: undefined; } + + baz: n, +>baz : null +>n : null + + boo: u +>boo : undefined +>u : undefined + } +} diff --git a/tests/baselines/reference/strictNullChecksNoWidening.js b/tests/baselines/reference/strictNullChecksNoWidening.js new file mode 100644 index 0000000000000..ba26a04fc131a --- /dev/null +++ b/tests/baselines/reference/strictNullChecksNoWidening.js @@ -0,0 +1,31 @@ +//// [strictNullChecksNoWidening.ts] + +var a1 = null; +var a2 = undefined; +var a3 = void 0; + +var b1 = []; +var b2 = [,]; +var b3 = [undefined]; +var b4 = [[], []]; +var b5 = [[], [,]]; + +declare function f<T>(x: T): T; + +var c1 = f(null); +var c2 = f(undefined); +var c3 = f([]); + + +//// [strictNullChecksNoWidening.js] +var a1 = null; +var a2 = undefined; +var a3 = void 0; +var b1 = []; +var b2 = [,]; +var b3 = [undefined]; +var b4 = [[], []]; +var b5 = [[], [,]]; +var c1 = f(null); +var c2 = f(undefined); +var c3 = f([]); diff --git a/tests/baselines/reference/strictNullChecksNoWidening.symbols b/tests/baselines/reference/strictNullChecksNoWidening.symbols new file mode 100644 index 0000000000000..a23a0d2e926c0 --- /dev/null +++ b/tests/baselines/reference/strictNullChecksNoWidening.symbols @@ -0,0 +1,48 @@ +=== tests/cases/conformance/types/typeRelationships/widenedTypes/strictNullChecksNoWidening.ts === + +var a1 = null; +>a1 : Symbol(a1, Decl(strictNullChecksNoWidening.ts, 1, 3)) + +var a2 = undefined; +>a2 : Symbol(a2, Decl(strictNullChecksNoWidening.ts, 2, 3)) +>undefined : Symbol(undefined) + +var a3 = void 0; +>a3 : Symbol(a3, Decl(strictNullChecksNoWidening.ts, 3, 3)) + +var b1 = []; +>b1 : Symbol(b1, Decl(strictNullChecksNoWidening.ts, 5, 3)) + +var b2 = [,]; +>b2 : Symbol(b2, Decl(strictNullChecksNoWidening.ts, 6, 3)) + +var b3 = [undefined]; +>b3 : Symbol(b3, Decl(strictNullChecksNoWidening.ts, 7, 3)) +>undefined : Symbol(undefined) + +var b4 = [[], []]; +>b4 : Symbol(b4, Decl(strictNullChecksNoWidening.ts, 8, 3)) + +var b5 = [[], [,]]; +>b5 : Symbol(b5, Decl(strictNullChecksNoWidening.ts, 9, 3)) + +declare function f<T>(x: T): T; +>f : Symbol(f, Decl(strictNullChecksNoWidening.ts, 9, 19)) +>T : Symbol(T, Decl(strictNullChecksNoWidening.ts, 11, 19)) +>x : Symbol(x, Decl(strictNullChecksNoWidening.ts, 11, 22)) +>T : Symbol(T, Decl(strictNullChecksNoWidening.ts, 11, 19)) +>T : Symbol(T, Decl(strictNullChecksNoWidening.ts, 11, 19)) + +var c1 = f(null); +>c1 : Symbol(c1, Decl(strictNullChecksNoWidening.ts, 13, 3)) +>f : Symbol(f, Decl(strictNullChecksNoWidening.ts, 9, 19)) + +var c2 = f(undefined); +>c2 : Symbol(c2, Decl(strictNullChecksNoWidening.ts, 14, 3)) +>f : Symbol(f, Decl(strictNullChecksNoWidening.ts, 9, 19)) +>undefined : Symbol(undefined) + +var c3 = f([]); +>c3 : Symbol(c3, Decl(strictNullChecksNoWidening.ts, 15, 3)) +>f : Symbol(f, Decl(strictNullChecksNoWidening.ts, 9, 19)) + diff --git a/tests/baselines/reference/strictNullChecksNoWidening.types b/tests/baselines/reference/strictNullChecksNoWidening.types new file mode 100644 index 0000000000000..6dd2ee3fb4cfb --- /dev/null +++ b/tests/baselines/reference/strictNullChecksNoWidening.types @@ -0,0 +1,67 @@ +=== tests/cases/conformance/types/typeRelationships/widenedTypes/strictNullChecksNoWidening.ts === + +var a1 = null; +>a1 : null +>null : null + +var a2 = undefined; +>a2 : undefined +>undefined : undefined + +var a3 = void 0; +>a3 : undefined +>void 0 : undefined +>0 : number + +var b1 = []; +>b1 : never[] +>[] : never[] + +var b2 = [,]; +>b2 : undefined[] +>[,] : undefined[] +> : undefined + +var b3 = [undefined]; +>b3 : undefined[] +>[undefined] : undefined[] +>undefined : undefined + +var b4 = [[], []]; +>b4 : never[][] +>[[], []] : never[][] +>[] : never[] +>[] : never[] + +var b5 = [[], [,]]; +>b5 : undefined[][] +>[[], [,]] : undefined[][] +>[] : never[] +>[,] : undefined[] +> : undefined + +declare function f<T>(x: T): T; +>f : <T>(x: T) => T +>T : T +>x : T +>T : T +>T : T + +var c1 = f(null); +>c1 : null +>f(null) : null +>f : <T>(x: T) => T +>null : null + +var c2 = f(undefined); +>c2 : undefined +>f(undefined) : undefined +>f : <T>(x: T) => T +>undefined : undefined + +var c3 = f([]); +>c3 : never[] +>f([]) : never[] +>f : <T>(x: T) => T +>[] : never[] + diff --git a/tests/cases/conformance/types/typeRelationships/widenedTypes/arrayLiteralWidened.ts b/tests/cases/conformance/types/typeRelationships/widenedTypes/arrayLiteralWidened.ts index 8af0a5842cc2e..05428422129c6 100644 --- a/tests/cases/conformance/types/typeRelationships/widenedTypes/arrayLiteralWidened.ts +++ b/tests/cases/conformance/types/typeRelationships/widenedTypes/arrayLiteralWidened.ts @@ -1,6 +1,7 @@ // array literals are widened upon assignment according to their element type var a = []; // any[] +var a = [,,]; var a = [null, null]; var a = [undefined, undefined]; @@ -11,3 +12,11 @@ var b = [[undefined, undefined]]; var c = [[[]]]; // any[][][] var c = [[[null]],[undefined]] + +// no widening when one or more elements are non-widening + +var x: undefined = undefined; + +var d = [x]; +var d = [, x]; +var d = [undefined, x]; diff --git a/tests/cases/conformance/types/typeRelationships/widenedTypes/initializersWidened.ts b/tests/cases/conformance/types/typeRelationships/widenedTypes/initializersWidened.ts index e79cdc9e16834..2eeb96194b753 100644 --- a/tests/cases/conformance/types/typeRelationships/widenedTypes/initializersWidened.ts +++ b/tests/cases/conformance/types/typeRelationships/widenedTypes/initializersWidened.ts @@ -1,4 +1,24 @@ // these are widened to any at the point of assignment -var x = null; -var y = undefined; \ No newline at end of file +var x1 = null; +var y1 = undefined; +var z1 = void 0; + +// these are not widened + +var x2: null; +var y2: undefined; + +var x3: null = null; +var y3: undefined = undefined; +var z3: undefined = void 0; + +// widen only when all constituents of union are widening + +var x4 = null || null; +var y4 = undefined || undefined; +var z4 = void 0 || void 0; + +var x5 = null || x2; +var y5 = undefined || y2; +var z5 = void 0 || y2; \ No newline at end of file diff --git a/tests/cases/conformance/types/typeRelationships/widenedTypes/objectLiteralWidened.ts b/tests/cases/conformance/types/typeRelationships/widenedTypes/objectLiteralWidened.ts index cde44f9116856..8b51e526882e7 100644 --- a/tests/cases/conformance/types/typeRelationships/widenedTypes/objectLiteralWidened.ts +++ b/tests/cases/conformance/types/typeRelationships/widenedTypes/objectLiteralWidened.ts @@ -1,14 +1,32 @@ // object literal properties are widened to any -var x = { +var x1 = { foo: null, bar: undefined } -var y = { +var y1 = { foo: null, bar: { baz: null, boo: undefined } +} + +// these are not widened + +var u: undefined = undefined; +var n: null = null; + +var x2 = { + foo: n, + bar: u +} + +var y2 = { + foo: n, + bar: { + baz: n, + boo: u + } } \ No newline at end of file diff --git a/tests/cases/conformance/types/typeRelationships/widenedTypes/strictNullChecksNoWidening.ts b/tests/cases/conformance/types/typeRelationships/widenedTypes/strictNullChecksNoWidening.ts new file mode 100644 index 0000000000000..8f5b4709abf9e --- /dev/null +++ b/tests/cases/conformance/types/typeRelationships/widenedTypes/strictNullChecksNoWidening.ts @@ -0,0 +1,17 @@ +// @strictNullChecks: true + +var a1 = null; +var a2 = undefined; +var a3 = void 0; + +var b1 = []; +var b2 = [,]; +var b3 = [undefined]; +var b4 = [[], []]; +var b5 = [[], [,]]; + +declare function f<T>(x: T): T; + +var c1 = f(null); +var c2 = f(undefined); +var c3 = f([]); From fb2df77a59453e72e3bbc92ab4bb9e5c68cb4a8a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg <andersh@microsoft.com> Date: Thu, 2 Jun 2016 10:47:47 -0700 Subject: [PATCH 3/3] Remove unused variable --- src/compiler/checker.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6166234dcf4d3..b8f078ea9a56b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -120,7 +120,6 @@ namespace ts { const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined"); const nullType = createIntrinsicType(TypeFlags.Null, "null"); const nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null | TypeFlags.ContainsWideningType, "null"); - const emptyArrayElementType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined"); const unknownType = createIntrinsicType(TypeFlags.Any, "unknown"); const neverType = createIntrinsicType(TypeFlags.Never, "never");