@@ -56,7 +56,6 @@ namespace ts {
56
56
let enumCount = 0;
57
57
let symbolInstantiationDepth = 0;
58
58
59
- const emptyArray: any[] = [];
60
59
const emptySymbols = createSymbolTable();
61
60
62
61
const compilerOptions = host.getCompilerOptions();
@@ -84,9 +83,9 @@ namespace ts {
84
83
// extra cost of calling `getParseTreeNode` when calling these functions from inside the
85
84
// checker.
86
85
const checker: TypeChecker = {
87
- getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"),
88
- getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
89
- getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount") + symbolCount,
86
+ getNodeCount: () => sum<"nodeCount"> (host.getSourceFiles(), "nodeCount"),
87
+ getIdentifierCount: () => sum<"identifierCount"> (host.getSourceFiles(), "identifierCount"),
88
+ getSymbolCount: () => sum<"symbolCount"> (host.getSourceFiles(), "symbolCount") + symbolCount,
90
89
getTypeCount: () => typeCount,
91
90
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
92
91
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
@@ -8735,11 +8734,12 @@ namespace ts {
8735
8734
containingMessageChain?: DiagnosticMessageChain): boolean {
8736
8735
8737
8736
let errorInfo: DiagnosticMessageChain;
8737
+ let maybeKeys: string[];
8738
8738
let sourceStack: Type[];
8739
8739
let targetStack: Type[];
8740
- let maybeStack: Map<RelationComparisonResult>[];
8741
- let expandingFlags: number;
8740
+ let maybeCount = 0;
8742
8741
let depth = 0;
8742
+ let expandingFlags = 0;
8743
8743
let overflow = false;
8744
8744
let isIntersectionConstituent = false;
8745
8745
@@ -9107,10 +9107,15 @@ namespace ts {
9107
9107
return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
9108
9108
}
9109
9109
}
9110
- if (depth > 0) {
9111
- for (let i = 0; i < depth; i++) {
9110
+ if (!maybeKeys) {
9111
+ maybeKeys = [];
9112
+ sourceStack = [];
9113
+ targetStack = [];
9114
+ }
9115
+ else {
9116
+ for (let i = 0; i < maybeCount; i++) {
9112
9117
// If source and target are already being compared, consider them related with assumptions
9113
- if (maybeStack [i].get(id) ) {
9118
+ if (id === maybeKeys [i]) {
9114
9119
return Ternary.Maybe;
9115
9120
}
9116
9121
}
@@ -9119,16 +9124,11 @@ namespace ts {
9119
9124
return Ternary.False;
9120
9125
}
9121
9126
}
9122
- else {
9123
- sourceStack = [];
9124
- targetStack = [];
9125
- maybeStack = [];
9126
- expandingFlags = 0;
9127
- }
9127
+ const maybeStart = maybeCount;
9128
+ maybeKeys[maybeCount] = id;
9129
+ maybeCount++;
9128
9130
sourceStack[depth] = source;
9129
9131
targetStack[depth] = target;
9130
- maybeStack[depth] = createMap<RelationComparisonResult>();
9131
- maybeStack[depth].set(id, RelationComparisonResult.Succeeded);
9132
9132
depth++;
9133
9133
const saveExpandingFlags = expandingFlags;
9134
9134
if (!(expandingFlags & 1) && isDeeplyNestedType(source, sourceStack, depth)) expandingFlags |= 1;
@@ -9137,15 +9137,19 @@ namespace ts {
9137
9137
expandingFlags = saveExpandingFlags;
9138
9138
depth--;
9139
9139
if (result) {
9140
- const maybeCache = maybeStack[depth];
9141
- // If result is definitely true, copy assumptions to global cache, else copy to next level up
9142
- const destinationCache = (result === Ternary.True || depth === 0) ? relation : maybeStack[depth - 1];
9143
- copyEntries(maybeCache, destinationCache);
9140
+ if (result === Ternary.True || depth === 0) {
9141
+ // If result is definitely true, record all maybe keys as having succeeded
9142
+ for (let i = maybeStart; i < maybeCount; i++) {
9143
+ relation.set(maybeKeys[i], RelationComparisonResult.Succeeded);
9144
+ }
9145
+ maybeCount = maybeStart;
9146
+ }
9144
9147
}
9145
9148
else {
9146
- // A false result goes straight into global cache (when something is false under assumptions it
9147
- // will also be false without assumptions)
9149
+ // A false result goes straight into global cache (when something is false under
9150
+ // assumptions it will also be false without assumptions)
9148
9151
relation.set(id, reportErrors ? RelationComparisonResult.FailedAndReported : RelationComparisonResult.Failed);
9152
+ maybeCount = maybeStart;
9149
9153
}
9150
9154
return result;
9151
9155
}
@@ -12004,9 +12008,9 @@ namespace ts {
12004
12008
}
12005
12009
12006
12010
const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol);
12011
+ let declaration = localOrExportSymbol.valueDeclaration;
12007
12012
12008
12013
if (localOrExportSymbol.flags & SymbolFlags.Class) {
12009
- const declaration = localOrExportSymbol.valueDeclaration;
12010
12014
// Due to the emit for class decorators, any reference to the class from inside of the class body
12011
12015
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
12012
12016
// behavior of class names in ES6.
@@ -12048,7 +12052,6 @@ namespace ts {
12048
12052
checkNestedBlockScopedBinding(node, symbol);
12049
12053
12050
12054
const type = getDeclaredOrApparentType(localOrExportSymbol, node);
12051
- const declaration = localOrExportSymbol.valueDeclaration;
12052
12055
const assignmentKind = getAssignmentTargetKind(node);
12053
12056
12054
12057
if (assignmentKind) {
@@ -12062,11 +12065,26 @@ namespace ts {
12062
12065
}
12063
12066
}
12064
12067
12068
+ const isAlias = localOrExportSymbol.flags & SymbolFlags.Alias;
12069
+
12065
12070
// We only narrow variables and parameters occurring in a non-assignment position. For all other
12066
12071
// entities we simply return the declared type.
12067
- if (!(localOrExportSymbol.flags & SymbolFlags.Variable) || assignmentKind === AssignmentKind.Definite || !declaration) {
12072
+ if (localOrExportSymbol.flags & SymbolFlags.Variable) {
12073
+ if (assignmentKind === AssignmentKind.Definite) {
12074
+ return type;
12075
+ }
12076
+ }
12077
+ else if (isAlias) {
12078
+ declaration = find<Declaration>(symbol.declarations, isSomeImportDeclaration);
12079
+ }
12080
+ else {
12068
12081
return type;
12069
12082
}
12083
+
12084
+ if (!declaration) {
12085
+ return type;
12086
+ }
12087
+
12070
12088
// The declaration container is the innermost function that encloses the declaration of the variable
12071
12089
// or parameter. The flow container is the innermost function starting with which we analyze the control
12072
12090
// flow graph to determine the control flow based type.
@@ -12085,7 +12103,7 @@ namespace ts {
12085
12103
// We only look for uninitialized variables in strict null checking mode, and only when we can analyze
12086
12104
// the entire control flow graph from the variable's declaration (i.e. when the flow container and
12087
12105
// declaration container are the same).
12088
- const assumeInitialized = isParameter || isOuterVariable ||
12106
+ const assumeInitialized = isParameter || isAlias || isOuterVariable ||
12089
12107
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) ||
12090
12108
node.parent.kind === SyntaxKind.NonNullExpression ||
12091
12109
isInAmbientContext(declaration);
@@ -24771,4 +24789,19 @@ namespace ts {
24771
24789
return isDeclarationName(name);
24772
24790
}
24773
24791
}
24792
+
24793
+ function isSomeImportDeclaration(decl: Node): boolean {
24794
+ switch (decl.kind) {
24795
+ case SyntaxKind.ImportClause: // For default import
24796
+ case SyntaxKind.ImportEqualsDeclaration:
24797
+ case SyntaxKind.NamespaceImport:
24798
+ case SyntaxKind.ImportSpecifier: // For rename import `x as y`
24799
+ return true;
24800
+ case SyntaxKind.Identifier:
24801
+ // For regular import, `decl` is an Identifier under the ImportSpecifier.
24802
+ return decl.parent.kind === SyntaxKind.ImportSpecifier;
24803
+ default:
24804
+ return false;
24805
+ }
24806
+ }
24774
24807
}
0 commit comments