mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
fix(19577): fix regression with fully inferred types and non-null assertions (#50092)
This commit is contained in:
parent
4615e52d93
commit
7b2b6a8cc2
@ -27936,6 +27936,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const isOuterVariable = flowContainer !== declarationContainer;
|
||||
const isSpreadDestructuringAssignmentTarget = node.parent && node.parent.parent && isSpreadAssignment(node.parent) && isDestructuringAssignmentTarget(node.parent.parent);
|
||||
const isModuleExports = symbol.flags & SymbolFlags.ModuleExports;
|
||||
const typeIsAutomatic = type === autoType || type === autoArrayType;
|
||||
const isAutomaticTypeInNonNull = typeIsAutomatic && node.parent.kind === SyntaxKind.NonNullExpression;
|
||||
// When the control flow originates in a function expression or arrow function and we are referencing
|
||||
// a const variable or parameter from an outer function, we extend the origin of the control flow
|
||||
// analysis to include the immediately enclosing function.
|
||||
@ -27953,10 +27955,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
node.parent.kind === SyntaxKind.NonNullExpression ||
|
||||
declaration.kind === SyntaxKind.VariableDeclaration && (declaration as VariableDeclaration).exclamationToken ||
|
||||
declaration.flags & NodeFlags.Ambient;
|
||||
const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) :
|
||||
type === autoType || type === autoArrayType ? undefinedType :
|
||||
getOptionalType(type);
|
||||
const flowType = getFlowTypeOfReference(node, type, initialType, flowContainer);
|
||||
const initialType = isAutomaticTypeInNonNull ? undefinedType :
|
||||
assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) :
|
||||
typeIsAutomatic ? undefinedType : getOptionalType(type);
|
||||
const flowType = isAutomaticTypeInNonNull ? getNonNullableType(getFlowTypeOfReference(node, type, initialType, flowContainer)) :
|
||||
getFlowTypeOfReference(node, type, initialType, flowContainer);
|
||||
// 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
|
||||
// control flow based type does include undefined.
|
||||
|
||||
63
tests/baselines/reference/nonNullFullInference.js
Normal file
63
tests/baselines/reference/nonNullFullInference.js
Normal file
@ -0,0 +1,63 @@
|
||||
//// [nonNullFullInference.ts]
|
||||
// https://github.com/microsoft/TypeScript/issues/19577
|
||||
|
||||
function testNonNullInference(numbers: number[]) {
|
||||
let last;
|
||||
|
||||
for (const n of numbers) {
|
||||
if (n % 2) {
|
||||
return n;
|
||||
}
|
||||
|
||||
last = n;
|
||||
}
|
||||
|
||||
last;
|
||||
last!;
|
||||
}
|
||||
|
||||
function testNonNullInferenceWithArrays(numbers: number[]) {
|
||||
let result;
|
||||
const arr = [];
|
||||
|
||||
for (const n of numbers) {
|
||||
if (n % 2) {
|
||||
return [n];
|
||||
}
|
||||
|
||||
arr.push(n);
|
||||
result = arr;
|
||||
}
|
||||
|
||||
result;
|
||||
result!;
|
||||
}
|
||||
|
||||
//// [nonNullFullInference.js]
|
||||
// https://github.com/microsoft/TypeScript/issues/19577
|
||||
function testNonNullInference(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;
|
||||
}
|
||||
last;
|
||||
last;
|
||||
}
|
||||
function testNonNullInferenceWithArrays(numbers) {
|
||||
var result;
|
||||
var arr = [];
|
||||
for (var _i = 0, numbers_2 = numbers; _i < numbers_2.length; _i++) {
|
||||
var n = numbers_2[_i];
|
||||
if (n % 2) {
|
||||
return [n];
|
||||
}
|
||||
arr.push(n);
|
||||
result = arr;
|
||||
}
|
||||
result;
|
||||
result;
|
||||
}
|
||||
71
tests/baselines/reference/nonNullFullInference.symbols
Normal file
71
tests/baselines/reference/nonNullFullInference.symbols
Normal file
@ -0,0 +1,71 @@
|
||||
=== tests/cases/compiler/nonNullFullInference.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/19577
|
||||
|
||||
function testNonNullInference(numbers: number[]) {
|
||||
>testNonNullInference : Symbol(testNonNullInference, Decl(nonNullFullInference.ts, 0, 0))
|
||||
>numbers : Symbol(numbers, Decl(nonNullFullInference.ts, 2, 30))
|
||||
|
||||
let last;
|
||||
>last : Symbol(last, Decl(nonNullFullInference.ts, 3, 7))
|
||||
|
||||
for (const n of numbers) {
|
||||
>n : Symbol(n, Decl(nonNullFullInference.ts, 5, 14))
|
||||
>numbers : Symbol(numbers, Decl(nonNullFullInference.ts, 2, 30))
|
||||
|
||||
if (n % 2) {
|
||||
>n : Symbol(n, Decl(nonNullFullInference.ts, 5, 14))
|
||||
|
||||
return n;
|
||||
>n : Symbol(n, Decl(nonNullFullInference.ts, 5, 14))
|
||||
}
|
||||
|
||||
last = n;
|
||||
>last : Symbol(last, Decl(nonNullFullInference.ts, 3, 7))
|
||||
>n : Symbol(n, Decl(nonNullFullInference.ts, 5, 14))
|
||||
}
|
||||
|
||||
last;
|
||||
>last : Symbol(last, Decl(nonNullFullInference.ts, 3, 7))
|
||||
|
||||
last!;
|
||||
>last : Symbol(last, Decl(nonNullFullInference.ts, 3, 7))
|
||||
}
|
||||
|
||||
function testNonNullInferenceWithArrays(numbers: number[]) {
|
||||
>testNonNullInferenceWithArrays : Symbol(testNonNullInferenceWithArrays, Decl(nonNullFullInference.ts, 15, 1))
|
||||
>numbers : Symbol(numbers, Decl(nonNullFullInference.ts, 17, 40))
|
||||
|
||||
let result;
|
||||
>result : Symbol(result, Decl(nonNullFullInference.ts, 18, 7))
|
||||
|
||||
const arr = [];
|
||||
>arr : Symbol(arr, Decl(nonNullFullInference.ts, 19, 9))
|
||||
|
||||
for (const n of numbers) {
|
||||
>n : Symbol(n, Decl(nonNullFullInference.ts, 21, 14))
|
||||
>numbers : Symbol(numbers, Decl(nonNullFullInference.ts, 17, 40))
|
||||
|
||||
if (n % 2) {
|
||||
>n : Symbol(n, Decl(nonNullFullInference.ts, 21, 14))
|
||||
|
||||
return [n];
|
||||
>n : Symbol(n, Decl(nonNullFullInference.ts, 21, 14))
|
||||
}
|
||||
|
||||
arr.push(n);
|
||||
>arr.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(nonNullFullInference.ts, 19, 9))
|
||||
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
|
||||
>n : Symbol(n, Decl(nonNullFullInference.ts, 21, 14))
|
||||
|
||||
result = arr;
|
||||
>result : Symbol(result, Decl(nonNullFullInference.ts, 18, 7))
|
||||
>arr : Symbol(arr, Decl(nonNullFullInference.ts, 19, 9))
|
||||
}
|
||||
|
||||
result;
|
||||
>result : Symbol(result, Decl(nonNullFullInference.ts, 18, 7))
|
||||
|
||||
result!;
|
||||
>result : Symbol(result, Decl(nonNullFullInference.ts, 18, 7))
|
||||
}
|
||||
82
tests/baselines/reference/nonNullFullInference.types
Normal file
82
tests/baselines/reference/nonNullFullInference.types
Normal file
@ -0,0 +1,82 @@
|
||||
=== tests/cases/compiler/nonNullFullInference.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/19577
|
||||
|
||||
function testNonNullInference(numbers: number[]) {
|
||||
>testNonNullInference : (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
|
||||
}
|
||||
|
||||
last;
|
||||
>last : number
|
||||
|
||||
last!;
|
||||
>last! : number
|
||||
>last : number
|
||||
}
|
||||
|
||||
function testNonNullInferenceWithArrays(numbers: number[]) {
|
||||
>testNonNullInferenceWithArrays : (numbers: number[]) => number[]
|
||||
>numbers : number[]
|
||||
|
||||
let result;
|
||||
>result : any
|
||||
|
||||
const arr = [];
|
||||
>arr : any[]
|
||||
>[] : undefined[]
|
||||
|
||||
for (const n of numbers) {
|
||||
>n : number
|
||||
>numbers : number[]
|
||||
|
||||
if (n % 2) {
|
||||
>n % 2 : number
|
||||
>n : number
|
||||
>2 : 2
|
||||
|
||||
return [n];
|
||||
>[n] : number[]
|
||||
>n : number
|
||||
}
|
||||
|
||||
arr.push(n);
|
||||
>arr.push(n) : number
|
||||
>arr.push : (...items: any[]) => number
|
||||
>arr : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>n : number
|
||||
|
||||
result = arr;
|
||||
>result = arr : number[]
|
||||
>result : any
|
||||
>arr : number[]
|
||||
}
|
||||
|
||||
result;
|
||||
>result : number[]
|
||||
|
||||
result!;
|
||||
>result! : number[]
|
||||
>result : number[]
|
||||
}
|
||||
34
tests/cases/compiler/nonNullFullInference.ts
Normal file
34
tests/cases/compiler/nonNullFullInference.ts
Normal file
@ -0,0 +1,34 @@
|
||||
// @noImplicitAny: true
|
||||
// https://github.com/microsoft/TypeScript/issues/19577
|
||||
|
||||
function testNonNullInference(numbers: number[]) {
|
||||
let last;
|
||||
|
||||
for (const n of numbers) {
|
||||
if (n % 2) {
|
||||
return n;
|
||||
}
|
||||
|
||||
last = n;
|
||||
}
|
||||
|
||||
last;
|
||||
last!;
|
||||
}
|
||||
|
||||
function testNonNullInferenceWithArrays(numbers: number[]) {
|
||||
let result;
|
||||
const arr = [];
|
||||
|
||||
for (const n of numbers) {
|
||||
if (n % 2) {
|
||||
return [n];
|
||||
}
|
||||
|
||||
arr.push(n);
|
||||
result = arr;
|
||||
}
|
||||
|
||||
result;
|
||||
result!;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user