Remove ordering restrictions in control flow analysis (#37134)

* Don't reset CFA type for x.y when x is narrowed

* Add tests

* Accept new baselines

* Remove unnecessary type assertion
This commit is contained in:
Anders Hejlsberg
2020-02-29 12:03:09 -08:00
committed by GitHub
parent f914db0667
commit a5796cf3b2
6 changed files with 279 additions and 24 deletions

View File

@@ -3238,7 +3238,7 @@ namespace ts {
// If this is a property-parameter, then also declare the property symbol into the
// containing class.
if (isParameterPropertyDeclaration(node, node.parent)) {
const classDeclaration = <ClassLikeDeclaration>node.parent.parent;
const classDeclaration = node.parent.parent;
declareSymbol(classDeclaration.symbol.members!, classDeclaration.symbol, node, SymbolFlags.Property | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
}
}

View File

@@ -18903,10 +18903,6 @@ namespace ts {
return false;
}
function isSyntheticThisPropertyAccess(expr: Node) {
return isAccessExpression(expr) && expr.expression.kind === SyntaxKind.ThisKeyword && !!(expr.expression.flags & NodeFlags.Synthesized);
}
function findDiscriminantProperties(sourceProperties: Symbol[], target: Type): Symbol[] | undefined {
let result: Symbol[] | undefined;
for (const sourceProperty of sourceProperties) {
@@ -19634,7 +19630,7 @@ namespace ts {
// on empty arrays are possible without implicit any errors and new element types can be inferred without
// type mismatch errors.
const resultType = getObjectFlags(evolvedType) & ObjectFlags.EvolvingArray && isEvolvingArrayOperationTarget(reference) ? autoArrayType : finalizeEvolvingArrayType(evolvedType);
if (resultType === unreachableNeverType|| reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
if (resultType === unreachableNeverType || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
return declaredType;
}
return resultType;
@@ -20241,11 +20237,6 @@ namespace ts {
if (strictNullChecks && optionalChainContainsReference(target, reference) && assumeTrue === (literal.text !== "undefined")) {
return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull);
}
// For a reference of the form 'x.y', a 'typeof x === ...' type guard resets the
// narrowed type of 'y' to its declared type.
if (containsMatchingReference(reference, target)) {
return declaredType;
}
return type;
}
if (type.flags & TypeFlags.Any && literal.text === "function") {
@@ -20427,16 +20418,6 @@ namespace ts {
if (assumeTrue && strictNullChecks && optionalChainContainsReference(left, reference)) {
return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull);
}
// For a reference of the form 'x.y', an 'x instanceof T' type guard resets the
// narrowed type of 'y' to its declared type. We do this because preceding 'x.y'
// references might reference a different 'y' property. However, we make an exception
// for property accesses where x is a synthetic 'this' expression, indicating that we
// were called from isPropertyInitializedInConstructor. Without this exception,
// initializations of 'this' properties that occur before a 'this instanceof XXX'
// check would not be considered.
if (containsMatchingReference(reference, left) && !isSyntheticThisPropertyAccess(reference)) {
return declaredType;
}
return type;
}
@@ -20517,9 +20498,6 @@ namespace ts {
!(getTypeFacts(predicate.type) & TypeFacts.EQUndefined)) {
return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull);
}
if (containsMatchingReference(reference, predicateArgument)) {
return declaredType;
}
}
}
return type;