From 2fabbd0a74dbca0fbefb2042f369e970b68ef560 Mon Sep 17 00:00:00 2001 From: Amin Pakseresht Date: Sun, 24 Jan 2021 22:22:53 -0500 Subject: [PATCH 1/2] Experimenting --- src/compiler/checker.ts | 1 - tests/cases/compiler/skipAssertion.ts | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/cases/compiler/skipAssertion.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 49c45384e6df5..610fabe1979df 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23411,7 +23411,6 @@ namespace ts { const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAssignmentTarget || isModuleExports || isBindingElement(declaration) || type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== 0 || isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || - node.parent.kind === SyntaxKind.NonNullExpression || declaration.kind === SyntaxKind.VariableDeclaration && (declaration).exclamationToken || declaration.flags & NodeFlags.Ambient; const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) : diff --git a/tests/cases/compiler/skipAssertion.ts b/tests/cases/compiler/skipAssertion.ts new file mode 100644 index 0000000000000..d9ab51233e222 --- /dev/null +++ b/tests/cases/compiler/skipAssertion.ts @@ -0,0 +1,16 @@ +// @noImplicitAny: true +// https://github.com/microsoft/TypeScript/issues/19577 + +function test(numbers: number[]) { + let last; + + for (const n of numbers) { + if (n % 2) { + return n; + } + + last = n; + } + + return last!; +} From 74351e1055610a4eb97f3a8a985c6848f40c9840 Mon Sep 17 00:00:00 2001 From: Amin Pakseresht Date: Sun, 24 Jan 2021 23:30:25 -0500 Subject: [PATCH 2/2] Allow NonNull assert to fallback to undefined if type is auto-type --- src/compiler/checker.ts | 9 +++-- .../initializerWithNonNullAssertion.js | 31 +++++++++++++++++ .../initializerWithNonNullAssertion.symbols | 30 ++++++++++++++++ .../initializerWithNonNullAssertion.types | 34 +++++++++++++++++++ ....ts => initializerWithNonNullAssertion.ts} | 0 5 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/initializerWithNonNullAssertion.js create mode 100644 tests/baselines/reference/initializerWithNonNullAssertion.symbols create mode 100644 tests/baselines/reference/initializerWithNonNullAssertion.types rename tests/cases/compiler/{skipAssertion.ts => initializerWithNonNullAssertion.ts} (100%) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 610fabe1979df..224aca97e43f6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23411,11 +23411,14 @@ namespace ts { const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAssignmentTarget || isModuleExports || isBindingElement(declaration) || type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== 0 || isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || + node.parent.kind === SyntaxKind.NonNullExpression || declaration.kind === SyntaxKind.VariableDeclaration && (declaration).exclamationToken || declaration.flags & NodeFlags.Ambient; - const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) : - type === autoType || type === autoArrayType ? undefinedType : - getOptionalType(type); + const initialType = assumeInitialized + ? isParameter + ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) + : (type === autoType || type === autoArrayType ? undefinedType : type) + : (type === autoType || type === autoArrayType ? undefinedType : getOptionalType(type)); const flowType = getFlowTypeOfReference(node, type, initialType, flowContainer, !assumeInitialized); // A variable is considered uninitialized when it is possible to analyze the entire control flow graph // from declaration to use, and when the variable's declared type doesn't include undefined but the diff --git a/tests/baselines/reference/initializerWithNonNullAssertion.js b/tests/baselines/reference/initializerWithNonNullAssertion.js new file mode 100644 index 0000000000000..06be92bc8dc0b --- /dev/null +++ b/tests/baselines/reference/initializerWithNonNullAssertion.js @@ -0,0 +1,31 @@ +//// [initializerWithNonNullAssertion.ts] +// https://github.com/microsoft/TypeScript/issues/19577 + +function test(numbers: number[]) { + let last; + + for (const n of numbers) { + if (n % 2) { + return n; + } + + last = n; + } + + return last!; +} + + +//// [initializerWithNonNullAssertion.js] +// https://github.com/microsoft/TypeScript/issues/19577 +function test(numbers) { + var last; + for (var _i = 0, numbers_1 = numbers; _i < numbers_1.length; _i++) { + var n = numbers_1[_i]; + if (n % 2) { + return n; + } + last = n; + } + return last; +} diff --git a/tests/baselines/reference/initializerWithNonNullAssertion.symbols b/tests/baselines/reference/initializerWithNonNullAssertion.symbols new file mode 100644 index 0000000000000..5c0e6617036da --- /dev/null +++ b/tests/baselines/reference/initializerWithNonNullAssertion.symbols @@ -0,0 +1,30 @@ +=== tests/cases/compiler/initializerWithNonNullAssertion.ts === +// https://github.com/microsoft/TypeScript/issues/19577 + +function test(numbers: number[]) { +>test : Symbol(test, Decl(initializerWithNonNullAssertion.ts, 0, 0)) +>numbers : Symbol(numbers, Decl(initializerWithNonNullAssertion.ts, 2, 14)) + + let last; +>last : Symbol(last, Decl(initializerWithNonNullAssertion.ts, 3, 7)) + + for (const n of numbers) { +>n : Symbol(n, Decl(initializerWithNonNullAssertion.ts, 5, 14)) +>numbers : Symbol(numbers, Decl(initializerWithNonNullAssertion.ts, 2, 14)) + + if (n % 2) { +>n : Symbol(n, Decl(initializerWithNonNullAssertion.ts, 5, 14)) + + return n; +>n : Symbol(n, Decl(initializerWithNonNullAssertion.ts, 5, 14)) + } + + last = n; +>last : Symbol(last, Decl(initializerWithNonNullAssertion.ts, 3, 7)) +>n : Symbol(n, Decl(initializerWithNonNullAssertion.ts, 5, 14)) + } + + return last!; +>last : Symbol(last, Decl(initializerWithNonNullAssertion.ts, 3, 7)) +} + diff --git a/tests/baselines/reference/initializerWithNonNullAssertion.types b/tests/baselines/reference/initializerWithNonNullAssertion.types new file mode 100644 index 0000000000000..5f2cdff15ab5e --- /dev/null +++ b/tests/baselines/reference/initializerWithNonNullAssertion.types @@ -0,0 +1,34 @@ +=== tests/cases/compiler/initializerWithNonNullAssertion.ts === +// https://github.com/microsoft/TypeScript/issues/19577 + +function test(numbers: number[]) { +>test : (numbers: number[]) => number +>numbers : number[] + + let last; +>last : any + + for (const n of numbers) { +>n : number +>numbers : number[] + + if (n % 2) { +>n % 2 : number +>n : number +>2 : 2 + + return n; +>n : number + } + + last = n; +>last = n : number +>last : any +>n : number + } + + return last!; +>last! : number +>last : number +} + diff --git a/tests/cases/compiler/skipAssertion.ts b/tests/cases/compiler/initializerWithNonNullAssertion.ts similarity index 100% rename from tests/cases/compiler/skipAssertion.ts rename to tests/cases/compiler/initializerWithNonNullAssertion.ts