mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #11432 from Microsoft/controlFlowArrays
Control flow analysis for array construction
This commit is contained in:
@@ -785,6 +785,15 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode {
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowArrayMutation>{
|
||||
flags: FlowFlags.ArrayMutation,
|
||||
antecedent,
|
||||
node
|
||||
};
|
||||
}
|
||||
|
||||
function finishFlowLabel(flow: FlowLabel): FlowNode {
|
||||
const antecedents = flow.antecedents;
|
||||
if (!antecedents) {
|
||||
@@ -1165,6 +1174,12 @@ namespace ts {
|
||||
forEachChild(node, bind);
|
||||
if (operator === SyntaxKind.EqualsToken && !isAssignmentTarget(node)) {
|
||||
bindAssignmentTargetFlow(node.left);
|
||||
if (node.left.kind === SyntaxKind.ElementAccessExpression) {
|
||||
const elementAccess = <ElementAccessExpression>node.left;
|
||||
if (isNarrowableOperand(elementAccess.expression)) {
|
||||
currentFlow = createFlowArrayMutation(currentFlow, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1225,6 +1240,12 @@ namespace ts {
|
||||
else {
|
||||
forEachChild(node, bind);
|
||||
}
|
||||
if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
const propertyAccess = <PropertyAccessExpression>node.expression;
|
||||
if (isNarrowableOperand(propertyAccess.expression) && isPushOrUnshiftIdentifier(propertyAccess.name)) {
|
||||
currentFlow = createFlowArrayMutation(currentFlow, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getContainerFlags(node: Node): ContainerFlags {
|
||||
|
||||
+231
-57
@@ -115,6 +115,7 @@ namespace ts {
|
||||
const intersectionTypes = createMap<IntersectionType>();
|
||||
const stringLiteralTypes = createMap<LiteralType>();
|
||||
const numericLiteralTypes = createMap<LiteralType>();
|
||||
const evolvingArrayTypes: AnonymousType[] = [];
|
||||
|
||||
const unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown");
|
||||
const resolvingSymbol = createSymbol(SymbolFlags.Transient, "__resolving__");
|
||||
@@ -176,6 +177,7 @@ namespace ts {
|
||||
let globalBooleanType: ObjectType;
|
||||
let globalRegExpType: ObjectType;
|
||||
let anyArrayType: Type;
|
||||
let autoArrayType: Type;
|
||||
let anyReadonlyArrayType: Type;
|
||||
|
||||
// The library files are only loaded when the feature is used.
|
||||
@@ -3061,9 +3063,14 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isAutoVariableInitializer(initializer: Expression) {
|
||||
const expr = initializer && skipParentheses(initializer);
|
||||
return !expr || expr.kind === SyntaxKind.NullKeyword || expr.kind === SyntaxKind.Identifier && getResolvedSymbol(<Identifier>expr) === undefinedSymbol;
|
||||
function isNullOrUndefined(node: Expression) {
|
||||
const expr = skipParentheses(node);
|
||||
return expr.kind === SyntaxKind.NullKeyword || expr.kind === SyntaxKind.Identifier && getResolvedSymbol(<Identifier>expr) === undefinedSymbol;
|
||||
}
|
||||
|
||||
function isEmptyArrayLiteral(node: Expression) {
|
||||
const expr = skipParentheses(node);
|
||||
return expr.kind === SyntaxKind.ArrayLiteralExpression && (<ArrayLiteralExpression>expr).elements.length === 0;
|
||||
}
|
||||
|
||||
function addOptionality(type: Type, optional: boolean): Type {
|
||||
@@ -3104,12 +3111,18 @@ namespace ts {
|
||||
return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ declaration.questionToken && includeOptionality);
|
||||
}
|
||||
|
||||
// Use control flow type inference for non-ambient, non-exported var or let variables with no initializer
|
||||
// or a 'null' or 'undefined' initializer.
|
||||
if (declaration.kind === SyntaxKind.VariableDeclaration && !isBindingPattern(declaration.name) &&
|
||||
!(getCombinedNodeFlags(declaration) & NodeFlags.Const) && !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) &&
|
||||
!isInAmbientContext(declaration) && isAutoVariableInitializer(declaration.initializer)) {
|
||||
return autoType;
|
||||
!(getCombinedModifierFlags(declaration) & ModifierFlags.Export) && !isInAmbientContext(declaration)) {
|
||||
// Use control flow tracked 'any' type for non-ambient, non-exported var or let variables with no
|
||||
// initializer or a 'null' or 'undefined' initializer.
|
||||
if (!(getCombinedNodeFlags(declaration) & NodeFlags.Const) && (!declaration.initializer || isNullOrUndefined(declaration.initializer))) {
|
||||
return autoType;
|
||||
}
|
||||
// Use control flow tracked 'any[]' type for non-ambient, non-exported variables with an empty array
|
||||
// literal initializer.
|
||||
if (declaration.initializer && isEmptyArrayLiteral(declaration.initializer)) {
|
||||
return autoArrayType;
|
||||
}
|
||||
}
|
||||
|
||||
if (declaration.kind === SyntaxKind.Parameter) {
|
||||
@@ -7423,7 +7436,7 @@ namespace ts {
|
||||
type.flags & TypeFlags.NumberLiteral ? numberType :
|
||||
type.flags & TypeFlags.BooleanLiteral ? booleanType :
|
||||
type.flags & TypeFlags.EnumLiteral ? (<EnumLiteralType>type).baseType :
|
||||
type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(map((<UnionType>type).types, getBaseTypeOfLiteralType)) :
|
||||
type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(sameMap((<UnionType>type).types, getBaseTypeOfLiteralType)) :
|
||||
type;
|
||||
}
|
||||
|
||||
@@ -7432,7 +7445,7 @@ namespace ts {
|
||||
type.flags & TypeFlags.NumberLiteral && type.flags & TypeFlags.FreshLiteral ? numberType :
|
||||
type.flags & TypeFlags.BooleanLiteral ? booleanType :
|
||||
type.flags & TypeFlags.EnumLiteral ? (<EnumLiteralType>type).baseType :
|
||||
type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(map((<UnionType>type).types, getWidenedLiteralType)) :
|
||||
type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(sameMap((<UnionType>type).types, getWidenedLiteralType)) :
|
||||
type;
|
||||
}
|
||||
|
||||
@@ -7571,10 +7584,10 @@ namespace ts {
|
||||
return getWidenedTypeOfObjectLiteral(type);
|
||||
}
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
return getUnionType(map((<UnionType>type).types, getWidenedConstituentType));
|
||||
return getUnionType(sameMap((<UnionType>type).types, getWidenedConstituentType));
|
||||
}
|
||||
if (isArrayType(type) || isTupleType(type)) {
|
||||
return createTypeReference((<TypeReference>type).target, map((<TypeReference>type).typeArguments, getWidenedType));
|
||||
return createTypeReference((<TypeReference>type).target, sameMap((<TypeReference>type).typeArguments, getWidenedType));
|
||||
}
|
||||
}
|
||||
return type;
|
||||
@@ -7992,7 +8005,7 @@ namespace ts {
|
||||
const widenLiteralTypes = context.inferences[index].topLevel &&
|
||||
!hasPrimitiveConstraint(signature.typeParameters[index]) &&
|
||||
(context.inferences[index].isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), signature.typeParameters[index]));
|
||||
const baseInferences = widenLiteralTypes ? map(inferences, getWidenedLiteralType) : inferences;
|
||||
const baseInferences = widenLiteralTypes ? sameMap(inferences, getWidenedLiteralType) : inferences;
|
||||
// Infer widened union or supertype, or the unknown type for no common supertype
|
||||
const unionOrSuperType = context.inferUnionTypes ? getUnionType(baseInferences, /*subtypeReduction*/ true) : getCommonSupertype(baseInferences);
|
||||
inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType;
|
||||
@@ -8395,6 +8408,13 @@ namespace ts {
|
||||
getAssignedType(<Expression>node);
|
||||
}
|
||||
|
||||
function isEmptyArrayAssignment(node: VariableDeclaration | BindingElement | Expression) {
|
||||
return node.kind === SyntaxKind.VariableDeclaration && (<VariableDeclaration>node).initializer &&
|
||||
isEmptyArrayLiteral((<VariableDeclaration>node).initializer) ||
|
||||
node.kind !== SyntaxKind.BindingElement && node.parent.kind === SyntaxKind.BinaryExpression &&
|
||||
isEmptyArrayLiteral((<BinaryExpression>node.parent).right);
|
||||
}
|
||||
|
||||
function getReferenceCandidate(node: Expression): Expression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
@@ -8410,6 +8430,14 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
function getReferenceRoot(node: Node): Node {
|
||||
const parent = node.parent;
|
||||
return parent.kind === SyntaxKind.ParenthesizedExpression ||
|
||||
parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).operatorToken.kind === SyntaxKind.EqualsToken && (<BinaryExpression>parent).left === node ||
|
||||
parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).operatorToken.kind === SyntaxKind.CommaToken && (<BinaryExpression>parent).right === node ?
|
||||
getReferenceRoot(parent) : node;
|
||||
}
|
||||
|
||||
function getTypeOfSwitchClause(clause: CaseClause | DefaultClause) {
|
||||
if (clause.kind === SyntaxKind.CaseClause) {
|
||||
const caseType = getRegularTypeOfLiteralType(checkExpression((<CaseClause>clause).expression));
|
||||
@@ -8495,21 +8523,113 @@ namespace ts {
|
||||
return incomplete ? { flags: 0, type } : type;
|
||||
}
|
||||
|
||||
// An evolving array type tracks the element types that have so far been seen in an
|
||||
// 'x.push(value)' or 'x[n] = value' operation along the control flow graph. Evolving
|
||||
// array types are ultimately converted into manifest array types (using getFinalArrayType)
|
||||
// and never escape the getFlowTypeOfReference function.
|
||||
function createEvolvingArrayType(elementType: Type): AnonymousType {
|
||||
const result = <AnonymousType>createObjectType(TypeFlags.Anonymous);
|
||||
result.elementType = elementType;
|
||||
return result;
|
||||
}
|
||||
|
||||
function getEvolvingArrayType(elementType: Type): AnonymousType {
|
||||
return evolvingArrayTypes[elementType.id] || (evolvingArrayTypes[elementType.id] = createEvolvingArrayType(elementType));
|
||||
}
|
||||
|
||||
// When adding evolving array element types we do not perform subtype reduction. Instead,
|
||||
// we defer subtype reduction until the evolving array type is finalized into a manifest
|
||||
// array type.
|
||||
function addEvolvingArrayElementType(evolvingArrayType: AnonymousType, node: Expression): AnonymousType {
|
||||
const elementType = getBaseTypeOfLiteralType(checkExpression(node));
|
||||
return isTypeSubsetOf(elementType, evolvingArrayType.elementType) ? evolvingArrayType : getEvolvingArrayType(getUnionType([evolvingArrayType.elementType, elementType]));
|
||||
}
|
||||
|
||||
function isEvolvingArrayType(type: Type) {
|
||||
return !!(type.flags & TypeFlags.Anonymous && (<AnonymousType>type).elementType);
|
||||
}
|
||||
|
||||
function createFinalArrayType(elementType: Type) {
|
||||
return elementType.flags & TypeFlags.Never ?
|
||||
autoArrayType :
|
||||
createArrayType(elementType.flags & TypeFlags.Union ?
|
||||
getUnionType((<UnionType>elementType).types, /*subtypeReduction*/ true) :
|
||||
elementType);
|
||||
}
|
||||
|
||||
// We perform subtype reduction upon obtaining the final array type from an evolving array type.
|
||||
function getFinalArrayType(evolvingArrayType: AnonymousType): Type {
|
||||
return evolvingArrayType.finalArrayType || (evolvingArrayType.finalArrayType = createFinalArrayType(evolvingArrayType.elementType));
|
||||
}
|
||||
|
||||
function finalizeEvolvingArrayType(type: Type): Type {
|
||||
return isEvolvingArrayType(type) ? getFinalArrayType(<AnonymousType>type) : type;
|
||||
}
|
||||
|
||||
function getElementTypeOfEvolvingArrayType(type: Type) {
|
||||
return isEvolvingArrayType(type) ? (<AnonymousType>type).elementType : neverType;
|
||||
}
|
||||
|
||||
function isEvolvingArrayTypeList(types: Type[]) {
|
||||
let hasEvolvingArrayType = false;
|
||||
for (const t of types) {
|
||||
if (!(t.flags & TypeFlags.Never)) {
|
||||
if (!isEvolvingArrayType(t)) {
|
||||
return false;
|
||||
}
|
||||
hasEvolvingArrayType = true;
|
||||
}
|
||||
}
|
||||
return hasEvolvingArrayType;
|
||||
}
|
||||
|
||||
// At flow control branch or loop junctions, if the type along every antecedent code path
|
||||
// is an evolving array type, we construct a combined evolving array type. Otherwise we
|
||||
// finalize all evolving array types.
|
||||
function getUnionOrEvolvingArrayType(types: Type[], subtypeReduction: boolean) {
|
||||
return isEvolvingArrayTypeList(types) ?
|
||||
getEvolvingArrayType(getUnionType(map(types, getElementTypeOfEvolvingArrayType))) :
|
||||
getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction);
|
||||
}
|
||||
|
||||
// Return true if the given node is 'x' in an 'x.length', x.push(value)', 'x.unshift(value)' or
|
||||
// 'x[n] = value' operation, where 'n' is an expression of type any, undefined, or a number-like type.
|
||||
function isEvolvingArrayOperationTarget(node: Node) {
|
||||
const root = getReferenceRoot(node);
|
||||
const parent = root.parent;
|
||||
const isLengthPushOrUnshift = parent.kind === SyntaxKind.PropertyAccessExpression && (
|
||||
(<PropertyAccessExpression>parent).name.text === "length" ||
|
||||
parent.parent.kind === SyntaxKind.CallExpression && isPushOrUnshiftIdentifier((<PropertyAccessExpression>parent).name));
|
||||
const isElementAssignment = parent.kind === SyntaxKind.ElementAccessExpression &&
|
||||
(<ElementAccessExpression>parent).expression === root &&
|
||||
parent.parent.kind === SyntaxKind.BinaryExpression &&
|
||||
(<BinaryExpression>parent.parent).operatorToken.kind === SyntaxKind.EqualsToken &&
|
||||
(<BinaryExpression>parent.parent).left === parent &&
|
||||
!isAssignmentTarget(parent.parent) &&
|
||||
isTypeAnyOrAllConstituentTypesHaveKind(checkExpression((<ElementAccessExpression>parent).argumentExpression), TypeFlags.NumberLike | TypeFlags.Undefined);
|
||||
return isLengthPushOrUnshift || isElementAssignment;
|
||||
}
|
||||
|
||||
function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, flowContainer: Node) {
|
||||
let key: string;
|
||||
if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
|
||||
return declaredType;
|
||||
}
|
||||
const initialType = assumeInitialized ? declaredType :
|
||||
declaredType === autoType ? undefinedType :
|
||||
declaredType === autoType || declaredType === autoArrayType ? undefinedType :
|
||||
includeFalsyTypes(declaredType, TypeFlags.Undefined);
|
||||
const visitedFlowStart = visitedFlowCount;
|
||||
const result = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
|
||||
const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
|
||||
visitedFlowCount = visitedFlowStart;
|
||||
if (reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(result, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
|
||||
// When the reference is 'x' in an 'x.length', 'x.push(value)', 'x.unshift(value)' or x[n] = value' operation,
|
||||
// we give type 'any[]' to 'x' instead of using the type determined by control flow analysis such that operations
|
||||
// on empty arrays are possible without implicit any errors and new element types can be inferred without
|
||||
// type mismatch errors.
|
||||
const resultType = isEvolvingArrayType(evolvedType) && isEvolvingArrayOperationTarget(reference) ? anyArrayType : finalizeEvolvingArrayType(evolvedType);
|
||||
if (reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
|
||||
return declaredType;
|
||||
}
|
||||
return result;
|
||||
return resultType;
|
||||
|
||||
function getTypeAtFlowNode(flow: FlowNode): FlowType {
|
||||
while (true) {
|
||||
@@ -8546,6 +8666,13 @@ namespace ts {
|
||||
getTypeAtFlowBranchLabel(<FlowLabel>flow) :
|
||||
getTypeAtFlowLoopLabel(<FlowLabel>flow);
|
||||
}
|
||||
else if (flow.flags & FlowFlags.ArrayMutation) {
|
||||
type = getTypeAtFlowArrayMutation(<FlowArrayMutation>flow);
|
||||
if (!type) {
|
||||
flow = (<FlowArrayMutation>flow).antecedent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (flow.flags & FlowFlags.Start) {
|
||||
// Check if we should continue with the control flow of the containing function.
|
||||
const container = (<FlowStart>flow).container;
|
||||
@@ -8558,8 +8685,8 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
// Unreachable code errors are reported in the binding phase. Here we
|
||||
// simply return the declared type to reduce follow-on errors.
|
||||
type = declaredType;
|
||||
// simply return the non-auto declared type to reduce follow-on errors.
|
||||
type = convertAutoToAny(declaredType);
|
||||
}
|
||||
if (flow.flags & FlowFlags.Shared) {
|
||||
// Record visited node and the associated type in the cache.
|
||||
@@ -8580,9 +8707,17 @@ namespace ts {
|
||||
const flowType = getTypeAtFlowNode(flow.antecedent);
|
||||
return createFlowType(getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), isIncomplete(flowType));
|
||||
}
|
||||
return declaredType === autoType ? getBaseTypeOfLiteralType(getInitialOrAssignedType(node)) :
|
||||
declaredType.flags & TypeFlags.Union ? getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(node)) :
|
||||
declaredType;
|
||||
if (declaredType === autoType || declaredType === autoArrayType) {
|
||||
if (isEmptyArrayAssignment(node)) {
|
||||
return getEvolvingArrayType(neverType);
|
||||
}
|
||||
const assignedType = getBaseTypeOfLiteralType(getInitialOrAssignedType(node));
|
||||
return isTypeAssignableTo(assignedType, declaredType) ? assignedType : anyArrayType;
|
||||
}
|
||||
if (declaredType.flags & TypeFlags.Union) {
|
||||
return getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(node));
|
||||
}
|
||||
return declaredType;
|
||||
}
|
||||
// We didn't have a direct match. However, if the reference is a dotted name, this
|
||||
// may be an assignment to a left hand part of the reference. For example, for a
|
||||
@@ -8595,24 +8730,56 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getTypeAtFlowArrayMutation(flow: FlowArrayMutation): FlowType {
|
||||
const node = flow.node;
|
||||
const expr = node.kind === SyntaxKind.CallExpression ?
|
||||
(<PropertyAccessExpression>(<CallExpression>node).expression).expression :
|
||||
(<ElementAccessExpression>(<BinaryExpression>node).left).expression;
|
||||
if (isMatchingReference(reference, getReferenceCandidate(expr))) {
|
||||
const flowType = getTypeAtFlowNode(flow.antecedent);
|
||||
const type = getTypeFromFlowType(flowType);
|
||||
if (isEvolvingArrayType(type)) {
|
||||
let evolvedType = <AnonymousType>type;
|
||||
if (node.kind === SyntaxKind.CallExpression) {
|
||||
for (const arg of (<CallExpression>node).arguments) {
|
||||
evolvedType = addEvolvingArrayElementType(evolvedType, arg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const indexType = checkExpression((<ElementAccessExpression>(<BinaryExpression>node).left).argumentExpression);
|
||||
if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike | TypeFlags.Undefined)) {
|
||||
evolvedType = addEvolvingArrayElementType(evolvedType, (<BinaryExpression>node).right);
|
||||
}
|
||||
}
|
||||
return evolvedType === type ? flowType : createFlowType(evolvedType, isIncomplete(flowType));
|
||||
}
|
||||
return flowType;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getTypeAtFlowCondition(flow: FlowCondition): FlowType {
|
||||
const flowType = getTypeAtFlowNode(flow.antecedent);
|
||||
let type = getTypeFromFlowType(flowType);
|
||||
if (!(type.flags & TypeFlags.Never)) {
|
||||
// If we have an antecedent type (meaning we're reachable in some way), we first
|
||||
// attempt to narrow the antecedent type. If that produces the never type, and if
|
||||
// the antecedent type is incomplete (i.e. a transient type in a loop), then we
|
||||
// take the type guard as an indication that control *could* reach here once we
|
||||
// have the complete type. We proceed by switching to the silent never type which
|
||||
// doesn't report errors when operators are applied to it. Note that this is the
|
||||
// *only* place a silent never type is ever generated.
|
||||
const assumeTrue = (flow.flags & FlowFlags.TrueCondition) !== 0;
|
||||
type = narrowType(type, flow.expression, assumeTrue);
|
||||
if (type.flags & TypeFlags.Never && isIncomplete(flowType)) {
|
||||
type = silentNeverType;
|
||||
}
|
||||
const type = getTypeFromFlowType(flowType);
|
||||
if (type.flags & TypeFlags.Never) {
|
||||
return flowType;
|
||||
}
|
||||
return createFlowType(type, isIncomplete(flowType));
|
||||
// If we have an antecedent type (meaning we're reachable in some way), we first
|
||||
// attempt to narrow the antecedent type. If that produces the never type, and if
|
||||
// the antecedent type is incomplete (i.e. a transient type in a loop), then we
|
||||
// take the type guard as an indication that control *could* reach here once we
|
||||
// have the complete type. We proceed by switching to the silent never type which
|
||||
// doesn't report errors when operators are applied to it. Note that this is the
|
||||
// *only* place a silent never type is ever generated.
|
||||
const assumeTrue = (flow.flags & FlowFlags.TrueCondition) !== 0;
|
||||
const nonEvolvingType = finalizeEvolvingArrayType(type);
|
||||
const narrowedType = narrowType(nonEvolvingType, flow.expression, assumeTrue);
|
||||
if (narrowedType === nonEvolvingType) {
|
||||
return flowType;
|
||||
}
|
||||
const incomplete = isIncomplete(flowType);
|
||||
const resultType = incomplete && narrowedType.flags & TypeFlags.Never ? silentNeverType : narrowedType;
|
||||
return createFlowType(resultType, incomplete);
|
||||
}
|
||||
|
||||
function getTypeAtSwitchClause(flow: FlowSwitchClause): FlowType {
|
||||
@@ -8655,7 +8822,7 @@ namespace ts {
|
||||
seenIncomplete = true;
|
||||
}
|
||||
}
|
||||
return createFlowType(getUnionType(antecedentTypes, subtypeReduction), seenIncomplete);
|
||||
return createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction), seenIncomplete);
|
||||
}
|
||||
|
||||
function getTypeAtFlowLoopLabel(flow: FlowLabel): FlowType {
|
||||
@@ -8671,11 +8838,15 @@ namespace ts {
|
||||
}
|
||||
// If this flow loop junction and reference are already being processed, return
|
||||
// the union of the types computed for each branch so far, marked as incomplete.
|
||||
// We should never see an empty array here because the first antecedent of a loop
|
||||
// junction is always the non-looping control flow path that leads to the top.
|
||||
// It is possible to see an empty array in cases where loops are nested and the
|
||||
// back edge of the outer loop reaches an inner loop that is already being analyzed.
|
||||
// In such cases we restart the analysis of the inner loop, which will then see
|
||||
// a non-empty in-process array for the outer loop and eventually terminate because
|
||||
// the first antecedent of a loop junction is always the non-looping control flow
|
||||
// path that leads to the top.
|
||||
for (let i = flowLoopStart; i < flowLoopCount; i++) {
|
||||
if (flowLoopNodes[i] === flow && flowLoopKeys[i] === key) {
|
||||
return createFlowType(getUnionType(flowLoopTypes[i]), /*incomplete*/ true);
|
||||
if (flowLoopNodes[i] === flow && flowLoopKeys[i] === key && flowLoopTypes[i].length) {
|
||||
return createFlowType(getUnionOrEvolvingArrayType(flowLoopTypes[i], /*subtypeReduction*/ false), /*incomplete*/ true);
|
||||
}
|
||||
}
|
||||
// Add the flow loop junction and reference to the in-process stack and analyze
|
||||
@@ -8718,7 +8889,7 @@ namespace ts {
|
||||
}
|
||||
// The result is incomplete if the first antecedent (the non-looping control flow path)
|
||||
// is incomplete.
|
||||
const result = getUnionType(antecedentTypes, subtypeReduction);
|
||||
const result = getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction);
|
||||
if (isIncomplete(firstAntecedentType)) {
|
||||
return createFlowType(result, /*incomplete*/ true);
|
||||
}
|
||||
@@ -9100,6 +9271,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function isConstVariable(symbol: Symbol) {
|
||||
return symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0 && getTypeOfSymbol(symbol) !== autoArrayType;
|
||||
}
|
||||
|
||||
function checkIdentifier(node: Identifier): Type {
|
||||
const symbol = getResolvedSymbol(node);
|
||||
|
||||
@@ -9190,30 +9365,28 @@ namespace ts {
|
||||
// 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.
|
||||
while (flowContainer !== declarationContainer &&
|
||||
(flowContainer.kind === SyntaxKind.FunctionExpression ||
|
||||
flowContainer.kind === SyntaxKind.ArrowFunction ||
|
||||
isObjectLiteralOrClassExpressionMethod(flowContainer)) &&
|
||||
(isReadonlySymbol(localOrExportSymbol) || isParameter && !isParameterAssigned(localOrExportSymbol))) {
|
||||
while (flowContainer !== declarationContainer && (flowContainer.kind === SyntaxKind.FunctionExpression ||
|
||||
flowContainer.kind === SyntaxKind.ArrowFunction || isObjectLiteralOrClassExpressionMethod(flowContainer)) &&
|
||||
(isConstVariable(localOrExportSymbol) || isParameter && !isParameterAssigned(localOrExportSymbol))) {
|
||||
flowContainer = getControlFlowContainer(flowContainer);
|
||||
}
|
||||
// We only look for uninitialized variables in strict null checking mode, and only when we can analyze
|
||||
// the entire control flow graph from the variable's declaration (i.e. when the flow container and
|
||||
// declaration container are the same).
|
||||
const assumeInitialized = isParameter || isOuterVariable ||
|
||||
type !== autoType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0) ||
|
||||
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0) ||
|
||||
isInAmbientContext(declaration);
|
||||
const flowType = getFlowTypeOfReference(node, type, assumeInitialized, 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.
|
||||
if (type === autoType) {
|
||||
if (flowType === autoType) {
|
||||
if (type === autoType || type === autoArrayType) {
|
||||
if (flowType === autoType || flowType === autoArrayType) {
|
||||
if (compilerOptions.noImplicitAny) {
|
||||
error(declaration.name, Diagnostics.Variable_0_implicitly_has_type_any_in_some_locations_where_its_type_cannot_be_determined, symbolToString(symbol));
|
||||
error(node, Diagnostics.Variable_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(anyType));
|
||||
error(declaration.name, Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined, symbolToString(symbol), typeToString(flowType));
|
||||
error(node, Diagnostics.Variable_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType));
|
||||
}
|
||||
return anyType;
|
||||
return convertAutoToAny(flowType);
|
||||
}
|
||||
}
|
||||
else if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
|
||||
@@ -10657,7 +10830,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
return getUnionType(signatures.map(getReturnTypeOfSignature), /*subtypeReduction*/ true);
|
||||
return getUnionType(map(signatures, getReturnTypeOfSignature), /*subtypeReduction*/ true);
|
||||
}
|
||||
|
||||
/// e.g. "props" for React.d.ts,
|
||||
@@ -10707,7 +10880,7 @@ namespace ts {
|
||||
}
|
||||
if (elemType.flags & TypeFlags.Union) {
|
||||
const types = (<UnionOrIntersectionType>elemType).types;
|
||||
return getUnionType(types.map(type => {
|
||||
return getUnionType(map(types, type => {
|
||||
return getResolvedJsxType(node, type, elemClassType);
|
||||
}), /*subtypeReduction*/ true);
|
||||
}
|
||||
@@ -15966,7 +16139,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function convertAutoToAny(type: Type) {
|
||||
return type === autoType ? anyType : type;
|
||||
return type === autoType ? anyType : type === autoArrayType ? anyArrayType : type;
|
||||
}
|
||||
|
||||
// Check variable, parameter, or property declaration
|
||||
@@ -19384,6 +19557,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
anyArrayType = createArrayType(anyType);
|
||||
autoArrayType = createArrayType(autoType);
|
||||
|
||||
const symbol = getGlobalSymbol("ReadonlyArray", SymbolFlags.Type, /*diagnostic*/ undefined);
|
||||
globalReadonlyArrayType = symbol && <GenericType>getTypeOfGlobalSymbol(symbol, /*arity*/ 1);
|
||||
|
||||
+22
-2
@@ -268,13 +268,33 @@ namespace ts {
|
||||
if (array) {
|
||||
result = [];
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const v = array[i];
|
||||
result.push(f(v, i));
|
||||
result.push(f(array[i], i));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Maps from T to T and avoids allocation if all elements map to themselves
|
||||
export function sameMap<T>(array: T[], f: (x: T, i: number) => T): T[] {
|
||||
let result: T[];
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (result) {
|
||||
result.push(f(array[i], i));
|
||||
}
|
||||
else {
|
||||
const item = array[i];
|
||||
const mapped = f(item, i);
|
||||
if (item !== mapped) {
|
||||
result = array.slice(0, i);
|
||||
result.push(mapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result || array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens an array containing a mix of array or non-array elements.
|
||||
*
|
||||
|
||||
@@ -2961,7 +2961,7 @@
|
||||
"category": "Error",
|
||||
"code": 7033
|
||||
},
|
||||
"Variable '{0}' implicitly has type 'any' in some locations where its type cannot be determined.": {
|
||||
"Variable '{0}' implicitly has type '{1}' in some locations where its type cannot be determined.": {
|
||||
"category": "Error",
|
||||
"code": 7034
|
||||
},
|
||||
|
||||
+12
-2
@@ -1907,8 +1907,9 @@ namespace ts {
|
||||
TrueCondition = 1 << 5, // Condition known to be true
|
||||
FalseCondition = 1 << 6, // Condition known to be false
|
||||
SwitchClause = 1 << 7, // Switch statement clause
|
||||
Referenced = 1 << 8, // Referenced as antecedent once
|
||||
Shared = 1 << 9, // Referenced as antecedent more than once
|
||||
ArrayMutation = 1 << 8, // Potential array mutation
|
||||
Referenced = 1 << 9, // Referenced as antecedent once
|
||||
Shared = 1 << 10, // Referenced as antecedent more than once
|
||||
Label = BranchLabel | LoopLabel,
|
||||
Condition = TrueCondition | FalseCondition
|
||||
}
|
||||
@@ -1951,6 +1952,13 @@ namespace ts {
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
// FlowArrayMutation represents a node potentially mutates an array, i.e. an
|
||||
// operation of the form 'x.push(value)', 'x.unshift(value)' or 'x[n] = value'.
|
||||
export interface FlowArrayMutation extends FlowNode {
|
||||
node: CallExpression | BinaryExpression;
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export type FlowType = Type | IncompleteType;
|
||||
|
||||
// Incomplete types occur during control flow analysis of loops. An IncompleteType
|
||||
@@ -2748,6 +2756,8 @@ namespace ts {
|
||||
export interface AnonymousType extends ObjectType {
|
||||
target?: AnonymousType; // Instantiation target
|
||||
mapper?: TypeMapper; // Instantiation mapper
|
||||
elementType?: Type; // Element expressions of evolving array type
|
||||
finalArrayType?: Type; // Final array type of evolving array type
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
@@ -1901,6 +1901,10 @@ namespace ts {
|
||||
return node.kind === SyntaxKind.Identifier && (<Identifier>node).text === "Symbol";
|
||||
}
|
||||
|
||||
export function isPushOrUnshiftIdentifier(node: Identifier) {
|
||||
return node.text === "push" || node.text === "unshift";
|
||||
}
|
||||
|
||||
export function isModifierKind(token: SyntaxKind): boolean {
|
||||
switch (token) {
|
||||
case SyntaxKind.AbstractKeyword:
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(5,9): error TS7034: Variable 'x' implicitly has type 'any[]' in some locations where its type cannot be determined.
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(6,13): error TS7005: Variable 'x' implicitly has an 'any[]' type.
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(12,9): error TS7034: Variable 'x' implicitly has type 'any[]' in some locations where its type cannot be determined.
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(14,13): error TS7005: Variable 'x' implicitly has an 'any[]' type.
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(20,9): error TS7034: Variable 'x' implicitly has type 'any[]' in some locations where its type cannot be determined.
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(23,9): error TS7005: Variable 'x' implicitly has an 'any[]' type.
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(30,12): error TS2345: Argument of type 'true' is not assignable to parameter of type 'string | number'.
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(35,12): error TS2345: Argument of type 'true' is not assignable to parameter of type 'string | number'.
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(49,5): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '((...items: (string | number)[]) => number) | ((...items: boolean[]) => number)' has no compatible call signatures.
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(57,12): error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(61,11): error TS7034: Variable 'x' implicitly has type 'any[]' in some locations where its type cannot be determined.
|
||||
tests/cases/compiler/controlFlowArrayErrors.ts(64,9): error TS7005: Variable 'x' implicitly has an 'any[]' type.
|
||||
|
||||
|
||||
==== tests/cases/compiler/controlFlowArrayErrors.ts (12 errors) ====
|
||||
|
||||
declare function cond(): boolean;
|
||||
|
||||
function f1() {
|
||||
let x = []; // Implicit any[] error in some locations
|
||||
~
|
||||
!!! error TS7034: Variable 'x' implicitly has type 'any[]' in some locations where its type cannot be determined.
|
||||
let y = x; // Implicit any[] error
|
||||
~
|
||||
!!! error TS7005: Variable 'x' implicitly has an 'any[]' type.
|
||||
x.push(5);
|
||||
let z = x;
|
||||
}
|
||||
|
||||
function f2() {
|
||||
let x; // Implicit any[] error in some locations
|
||||
~
|
||||
!!! error TS7034: Variable 'x' implicitly has type 'any[]' in some locations where its type cannot be determined.
|
||||
x = [];
|
||||
let y = x; // Implicit any[] error
|
||||
~
|
||||
!!! error TS7005: Variable 'x' implicitly has an 'any[]' type.
|
||||
x.push(5);
|
||||
let z = x;
|
||||
}
|
||||
|
||||
function f3() {
|
||||
let x = []; // Implicit any[] error in some locations
|
||||
~
|
||||
!!! error TS7034: Variable 'x' implicitly has type 'any[]' in some locations where its type cannot be determined.
|
||||
x.push(5);
|
||||
function g() {
|
||||
x; // Implicit any[] error
|
||||
~
|
||||
!!! error TS7005: Variable 'x' implicitly has an 'any[]' type.
|
||||
}
|
||||
}
|
||||
|
||||
function f4() {
|
||||
let x;
|
||||
x = [5, "hello"]; // Non-evolving array
|
||||
x.push(true); // Error
|
||||
~~~~
|
||||
!!! error TS2345: Argument of type 'true' is not assignable to parameter of type 'string | number'.
|
||||
}
|
||||
|
||||
function f5() {
|
||||
let x = [5, "hello"]; // Non-evolving array
|
||||
x.push(true); // Error
|
||||
~~~~
|
||||
!!! error TS2345: Argument of type 'true' is not assignable to parameter of type 'string | number'.
|
||||
}
|
||||
|
||||
function f6() {
|
||||
let x;
|
||||
if (cond()) {
|
||||
x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
}
|
||||
else {
|
||||
x = [true]; // Non-evolving array
|
||||
}
|
||||
x; // boolean[] | (string | number)[]
|
||||
x.push(99); // Error
|
||||
~~~~~~~~~~
|
||||
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '((...items: (string | number)[]) => number) | ((...items: boolean[]) => number)' has no compatible call signatures.
|
||||
}
|
||||
|
||||
function f7() {
|
||||
let x = []; // x has evolving array value
|
||||
x.push(5);
|
||||
let y = x; // y has non-evolving array value
|
||||
x.push("hello"); // Ok
|
||||
y.push("hello"); // Error
|
||||
~~~~~~~
|
||||
!!! error TS2345: Argument of type '"hello"' is not assignable to parameter of type 'number'.
|
||||
}
|
||||
|
||||
function f8() {
|
||||
const x = []; // Implicit any[] error in some locations
|
||||
~
|
||||
!!! error TS7034: Variable 'x' implicitly has type 'any[]' in some locations where its type cannot be determined.
|
||||
x.push(5);
|
||||
function g() {
|
||||
x; // Implicit any[] error
|
||||
~
|
||||
!!! error TS7005: Variable 'x' implicitly has an 'any[]' type.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
//// [controlFlowArrayErrors.ts]
|
||||
|
||||
declare function cond(): boolean;
|
||||
|
||||
function f1() {
|
||||
let x = []; // Implicit any[] error in some locations
|
||||
let y = x; // Implicit any[] error
|
||||
x.push(5);
|
||||
let z = x;
|
||||
}
|
||||
|
||||
function f2() {
|
||||
let x; // Implicit any[] error in some locations
|
||||
x = [];
|
||||
let y = x; // Implicit any[] error
|
||||
x.push(5);
|
||||
let z = x;
|
||||
}
|
||||
|
||||
function f3() {
|
||||
let x = []; // Implicit any[] error in some locations
|
||||
x.push(5);
|
||||
function g() {
|
||||
x; // Implicit any[] error
|
||||
}
|
||||
}
|
||||
|
||||
function f4() {
|
||||
let x;
|
||||
x = [5, "hello"]; // Non-evolving array
|
||||
x.push(true); // Error
|
||||
}
|
||||
|
||||
function f5() {
|
||||
let x = [5, "hello"]; // Non-evolving array
|
||||
x.push(true); // Error
|
||||
}
|
||||
|
||||
function f6() {
|
||||
let x;
|
||||
if (cond()) {
|
||||
x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
}
|
||||
else {
|
||||
x = [true]; // Non-evolving array
|
||||
}
|
||||
x; // boolean[] | (string | number)[]
|
||||
x.push(99); // Error
|
||||
}
|
||||
|
||||
function f7() {
|
||||
let x = []; // x has evolving array value
|
||||
x.push(5);
|
||||
let y = x; // y has non-evolving array value
|
||||
x.push("hello"); // Ok
|
||||
y.push("hello"); // Error
|
||||
}
|
||||
|
||||
function f8() {
|
||||
const x = []; // Implicit any[] error in some locations
|
||||
x.push(5);
|
||||
function g() {
|
||||
x; // Implicit any[] error
|
||||
}
|
||||
}
|
||||
|
||||
//// [controlFlowArrayErrors.js]
|
||||
function f1() {
|
||||
var x = []; // Implicit any[] error in some locations
|
||||
var y = x; // Implicit any[] error
|
||||
x.push(5);
|
||||
var z = x;
|
||||
}
|
||||
function f2() {
|
||||
var x; // Implicit any[] error in some locations
|
||||
x = [];
|
||||
var y = x; // Implicit any[] error
|
||||
x.push(5);
|
||||
var z = x;
|
||||
}
|
||||
function f3() {
|
||||
var x = []; // Implicit any[] error in some locations
|
||||
x.push(5);
|
||||
function g() {
|
||||
x; // Implicit any[] error
|
||||
}
|
||||
}
|
||||
function f4() {
|
||||
var x;
|
||||
x = [5, "hello"]; // Non-evolving array
|
||||
x.push(true); // Error
|
||||
}
|
||||
function f5() {
|
||||
var x = [5, "hello"]; // Non-evolving array
|
||||
x.push(true); // Error
|
||||
}
|
||||
function f6() {
|
||||
var x;
|
||||
if (cond()) {
|
||||
x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
}
|
||||
else {
|
||||
x = [true]; // Non-evolving array
|
||||
}
|
||||
x; // boolean[] | (string | number)[]
|
||||
x.push(99); // Error
|
||||
}
|
||||
function f7() {
|
||||
var x = []; // x has evolving array value
|
||||
x.push(5);
|
||||
var y = x; // y has non-evolving array value
|
||||
x.push("hello"); // Ok
|
||||
y.push("hello"); // Error
|
||||
}
|
||||
function f8() {
|
||||
var x = []; // Implicit any[] error in some locations
|
||||
x.push(5);
|
||||
function g() {
|
||||
x; // Implicit any[] error
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
//// [controlFlowArrays.ts]
|
||||
|
||||
declare function cond(): boolean;
|
||||
|
||||
function f1() {
|
||||
let x = [];
|
||||
x[0] = 5;
|
||||
x[1] = "hello";
|
||||
x[2] = true;
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f2() {
|
||||
let x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f3() {
|
||||
let x;
|
||||
x = [];
|
||||
x.push(5, "hello");
|
||||
return x; // (string | number)[]
|
||||
}
|
||||
|
||||
function f4() {
|
||||
let x = [];
|
||||
if (cond()) {
|
||||
x.push(5);
|
||||
}
|
||||
else {
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // (string | number)[]
|
||||
}
|
||||
|
||||
function f5() {
|
||||
let x;
|
||||
if (cond()) {
|
||||
x = [];
|
||||
x.push(5);
|
||||
}
|
||||
else {
|
||||
x = [];
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // (string | number)[]
|
||||
}
|
||||
|
||||
function f6() {
|
||||
let x;
|
||||
if (cond()) {
|
||||
x = 5;
|
||||
}
|
||||
else {
|
||||
x = [];
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // number | string[]
|
||||
}
|
||||
|
||||
function f7() {
|
||||
let x = null;
|
||||
if (cond()) {
|
||||
x = [];
|
||||
while (cond()) {
|
||||
x.push("hello");
|
||||
}
|
||||
}
|
||||
return x; // string[] | null
|
||||
}
|
||||
|
||||
function f8() {
|
||||
let x = [];
|
||||
x.push(5);
|
||||
if (cond()) return x; // number[]
|
||||
x.push("hello");
|
||||
if (cond()) return x; // (string | number)[]
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f9() {
|
||||
let x = [];
|
||||
if (cond()) {
|
||||
x.push(5);
|
||||
return x; // number[]
|
||||
}
|
||||
else {
|
||||
x.push("hello");
|
||||
return x; // string[]
|
||||
}
|
||||
}
|
||||
|
||||
function f10() {
|
||||
let x = [];
|
||||
if (cond()) {
|
||||
x.push(true);
|
||||
x; // boolean[]
|
||||
}
|
||||
else {
|
||||
x.push(5);
|
||||
x; // number[]
|
||||
while (cond()) {
|
||||
x.push("hello");
|
||||
}
|
||||
x; // (string | number)[]
|
||||
}
|
||||
x.push(99);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f11() {
|
||||
let x = [];
|
||||
if (x.length === 0) { // x.length ok on implicit any[]
|
||||
x.push("hello");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
function f12() {
|
||||
let x;
|
||||
x = [];
|
||||
if (x.length === 0) { // x.length ok on implicit any[]
|
||||
x.push("hello");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
function f13() {
|
||||
var x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f14() {
|
||||
const x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f15() {
|
||||
let x = [];
|
||||
while (cond()) {
|
||||
while (cond()) {}
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // string[]
|
||||
}
|
||||
|
||||
function f16() {
|
||||
let x;
|
||||
let y;
|
||||
(x = [], x).push(5);
|
||||
(x.push("hello"), x).push(true);
|
||||
((x))[3] = { a: 1 };
|
||||
return x; // (string | number | boolean | { a: number })[]
|
||||
}
|
||||
|
||||
function f17() {
|
||||
let x = [];
|
||||
x.unshift(5);
|
||||
x.unshift("hello");
|
||||
x.unshift(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f18() {
|
||||
let x = [];
|
||||
x.push(5);
|
||||
x.unshift("hello");
|
||||
x[2] = true;
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
//// [controlFlowArrays.js]
|
||||
function f1() {
|
||||
var x = [];
|
||||
x[0] = 5;
|
||||
x[1] = "hello";
|
||||
x[2] = true;
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
function f2() {
|
||||
var x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
function f3() {
|
||||
var x;
|
||||
x = [];
|
||||
x.push(5, "hello");
|
||||
return x; // (string | number)[]
|
||||
}
|
||||
function f4() {
|
||||
var x = [];
|
||||
if (cond()) {
|
||||
x.push(5);
|
||||
}
|
||||
else {
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // (string | number)[]
|
||||
}
|
||||
function f5() {
|
||||
var x;
|
||||
if (cond()) {
|
||||
x = [];
|
||||
x.push(5);
|
||||
}
|
||||
else {
|
||||
x = [];
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // (string | number)[]
|
||||
}
|
||||
function f6() {
|
||||
var x;
|
||||
if (cond()) {
|
||||
x = 5;
|
||||
}
|
||||
else {
|
||||
x = [];
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // number | string[]
|
||||
}
|
||||
function f7() {
|
||||
var x = null;
|
||||
if (cond()) {
|
||||
x = [];
|
||||
while (cond()) {
|
||||
x.push("hello");
|
||||
}
|
||||
}
|
||||
return x; // string[] | null
|
||||
}
|
||||
function f8() {
|
||||
var x = [];
|
||||
x.push(5);
|
||||
if (cond())
|
||||
return x; // number[]
|
||||
x.push("hello");
|
||||
if (cond())
|
||||
return x; // (string | number)[]
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
function f9() {
|
||||
var x = [];
|
||||
if (cond()) {
|
||||
x.push(5);
|
||||
return x; // number[]
|
||||
}
|
||||
else {
|
||||
x.push("hello");
|
||||
return x; // string[]
|
||||
}
|
||||
}
|
||||
function f10() {
|
||||
var x = [];
|
||||
if (cond()) {
|
||||
x.push(true);
|
||||
x; // boolean[]
|
||||
}
|
||||
else {
|
||||
x.push(5);
|
||||
x; // number[]
|
||||
while (cond()) {
|
||||
x.push("hello");
|
||||
}
|
||||
x; // (string | number)[]
|
||||
}
|
||||
x.push(99);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
function f11() {
|
||||
var x = [];
|
||||
if (x.length === 0) {
|
||||
x.push("hello");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
function f12() {
|
||||
var x;
|
||||
x = [];
|
||||
if (x.length === 0) {
|
||||
x.push("hello");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
function f13() {
|
||||
var x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
function f14() {
|
||||
var x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
function f15() {
|
||||
var x = [];
|
||||
while (cond()) {
|
||||
while (cond()) { }
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // string[]
|
||||
}
|
||||
function f16() {
|
||||
var x;
|
||||
var y;
|
||||
(x = [], x).push(5);
|
||||
(x.push("hello"), x).push(true);
|
||||
((x))[3] = { a: 1 };
|
||||
return x; // (string | number | boolean | { a: number })[]
|
||||
}
|
||||
function f17() {
|
||||
var x = [];
|
||||
x.unshift(5);
|
||||
x.unshift("hello");
|
||||
x.unshift(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
function f18() {
|
||||
var x = [];
|
||||
x.push(5);
|
||||
x.unshift("hello");
|
||||
x[2] = true;
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
@@ -0,0 +1,470 @@
|
||||
=== tests/cases/compiler/controlFlowArrays.ts ===
|
||||
|
||||
declare function cond(): boolean;
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
|
||||
function f1() {
|
||||
>f1 : Symbol(f1, Decl(controlFlowArrays.ts, 1, 33))
|
||||
|
||||
let x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 4, 7))
|
||||
|
||||
x[0] = 5;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 4, 7))
|
||||
|
||||
x[1] = "hello";
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 4, 7))
|
||||
|
||||
x[2] = true;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 4, 7))
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 4, 7))
|
||||
}
|
||||
|
||||
function f2() {
|
||||
>f2 : Symbol(f2, Decl(controlFlowArrays.ts, 9, 1))
|
||||
|
||||
let x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 12, 7))
|
||||
|
||||
x.push(5);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 12, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 12, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
x.push(true);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 12, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 12, 7))
|
||||
}
|
||||
|
||||
function f3() {
|
||||
>f3 : Symbol(f3, Decl(controlFlowArrays.ts, 17, 1))
|
||||
|
||||
let x;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 20, 7))
|
||||
|
||||
x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 20, 7))
|
||||
|
||||
x.push(5, "hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 20, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
return x; // (string | number)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 20, 7))
|
||||
}
|
||||
|
||||
function f4() {
|
||||
>f4 : Symbol(f4, Decl(controlFlowArrays.ts, 24, 1))
|
||||
|
||||
let x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 27, 7))
|
||||
|
||||
if (cond()) {
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
|
||||
x.push(5);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 27, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
else {
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 27, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
return x; // (string | number)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 27, 7))
|
||||
}
|
||||
|
||||
function f5() {
|
||||
>f5 : Symbol(f5, Decl(controlFlowArrays.ts, 35, 1))
|
||||
|
||||
let x;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 38, 7))
|
||||
|
||||
if (cond()) {
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
|
||||
x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 38, 7))
|
||||
|
||||
x.push(5);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 38, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
else {
|
||||
x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 38, 7))
|
||||
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 38, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
return x; // (string | number)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 38, 7))
|
||||
}
|
||||
|
||||
function f6() {
|
||||
>f6 : Symbol(f6, Decl(controlFlowArrays.ts, 48, 1))
|
||||
|
||||
let x;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 51, 7))
|
||||
|
||||
if (cond()) {
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
|
||||
x = 5;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 51, 7))
|
||||
}
|
||||
else {
|
||||
x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 51, 7))
|
||||
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 51, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
return x; // number | string[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 51, 7))
|
||||
}
|
||||
|
||||
function f7() {
|
||||
>f7 : Symbol(f7, Decl(controlFlowArrays.ts, 60, 1))
|
||||
|
||||
let x = null;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 63, 7))
|
||||
|
||||
if (cond()) {
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
|
||||
x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 63, 7))
|
||||
|
||||
while (cond()) {
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 63, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
}
|
||||
return x; // string[] | null
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 63, 7))
|
||||
}
|
||||
|
||||
function f8() {
|
||||
>f8 : Symbol(f8, Decl(controlFlowArrays.ts, 71, 1))
|
||||
|
||||
let x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 74, 7))
|
||||
|
||||
x.push(5);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 74, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
if (cond()) return x; // number[]
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 74, 7))
|
||||
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 74, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
if (cond()) return x; // (string | number)[]
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 74, 7))
|
||||
|
||||
x.push(true);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 74, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 74, 7))
|
||||
}
|
||||
|
||||
function f9() {
|
||||
>f9 : Symbol(f9, Decl(controlFlowArrays.ts, 81, 1))
|
||||
|
||||
let x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 84, 7))
|
||||
|
||||
if (cond()) {
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
|
||||
x.push(5);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 84, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
return x; // number[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 84, 7))
|
||||
}
|
||||
else {
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 84, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
return x; // string[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 84, 7))
|
||||
}
|
||||
}
|
||||
|
||||
function f10() {
|
||||
>f10 : Symbol(f10, Decl(controlFlowArrays.ts, 93, 1))
|
||||
|
||||
let x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 96, 7))
|
||||
|
||||
if (cond()) {
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
|
||||
x.push(true);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 96, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
x; // boolean[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 96, 7))
|
||||
}
|
||||
else {
|
||||
x.push(5);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 96, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
x; // number[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 96, 7))
|
||||
|
||||
while (cond()) {
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 96, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
x; // (string | number)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 96, 7))
|
||||
}
|
||||
x.push(99);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 96, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 96, 7))
|
||||
}
|
||||
|
||||
function f11() {
|
||||
>f11 : Symbol(f11, Decl(controlFlowArrays.ts, 111, 1))
|
||||
|
||||
let x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 114, 7))
|
||||
|
||||
if (x.length === 0) { // x.length ok on implicit any[]
|
||||
>x.length : Symbol(Array.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 114, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.d.ts, --, --))
|
||||
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 114, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
return x;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 114, 7))
|
||||
}
|
||||
|
||||
function f12() {
|
||||
>f12 : Symbol(f12, Decl(controlFlowArrays.ts, 119, 1))
|
||||
|
||||
let x;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 122, 7))
|
||||
|
||||
x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 122, 7))
|
||||
|
||||
if (x.length === 0) { // x.length ok on implicit any[]
|
||||
>x.length : Symbol(Array.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 122, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.d.ts, --, --))
|
||||
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 122, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
return x;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 122, 7))
|
||||
}
|
||||
|
||||
function f13() {
|
||||
>f13 : Symbol(f13, Decl(controlFlowArrays.ts, 128, 1))
|
||||
|
||||
var x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 131, 7))
|
||||
|
||||
x.push(5);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 131, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 131, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
x.push(true);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 131, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 131, 7))
|
||||
}
|
||||
|
||||
function f14() {
|
||||
>f14 : Symbol(f14, Decl(controlFlowArrays.ts, 136, 1))
|
||||
|
||||
const x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 139, 9))
|
||||
|
||||
x.push(5);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 139, 9))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 139, 9))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
x.push(true);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 139, 9))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 139, 9))
|
||||
}
|
||||
|
||||
function f15() {
|
||||
>f15 : Symbol(f15, Decl(controlFlowArrays.ts, 144, 1))
|
||||
|
||||
let x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 147, 7))
|
||||
|
||||
while (cond()) {
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
|
||||
while (cond()) {}
|
||||
>cond : Symbol(cond, Decl(controlFlowArrays.ts, 0, 0))
|
||||
|
||||
x.push("hello");
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 147, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
return x; // string[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 147, 7))
|
||||
}
|
||||
|
||||
function f16() {
|
||||
>f16 : Symbol(f16, Decl(controlFlowArrays.ts, 153, 1))
|
||||
|
||||
let x;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 156, 7))
|
||||
|
||||
let y;
|
||||
>y : Symbol(y, Decl(controlFlowArrays.ts, 157, 7))
|
||||
|
||||
(x = [], x).push(5);
|
||||
>(x = [], x).push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 156, 7))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 156, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
(x.push("hello"), x).push(true);
|
||||
>(x.push("hello"), x).push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 156, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 156, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
((x))[3] = { a: 1 };
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 156, 7))
|
||||
>a : Symbol(a, Decl(controlFlowArrays.ts, 160, 16))
|
||||
|
||||
return x; // (string | number | boolean | { a: number })[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 156, 7))
|
||||
}
|
||||
|
||||
function f17() {
|
||||
>f17 : Symbol(f17, Decl(controlFlowArrays.ts, 162, 1))
|
||||
|
||||
let x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 165, 7))
|
||||
|
||||
x.unshift(5);
|
||||
>x.unshift : Symbol(Array.unshift, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 165, 7))
|
||||
>unshift : Symbol(Array.unshift, Decl(lib.d.ts, --, --))
|
||||
|
||||
x.unshift("hello");
|
||||
>x.unshift : Symbol(Array.unshift, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 165, 7))
|
||||
>unshift : Symbol(Array.unshift, Decl(lib.d.ts, --, --))
|
||||
|
||||
x.unshift(true);
|
||||
>x.unshift : Symbol(Array.unshift, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 165, 7))
|
||||
>unshift : Symbol(Array.unshift, Decl(lib.d.ts, --, --))
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 165, 7))
|
||||
}
|
||||
|
||||
function f18() {
|
||||
>f18 : Symbol(f18, Decl(controlFlowArrays.ts, 170, 1))
|
||||
|
||||
let x = [];
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 173, 7))
|
||||
|
||||
x.push(5);
|
||||
>x.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 173, 7))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
|
||||
x.unshift("hello");
|
||||
>x.unshift : Symbol(Array.unshift, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 173, 7))
|
||||
>unshift : Symbol(Array.unshift, Decl(lib.d.ts, --, --))
|
||||
|
||||
x[2] = true;
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 173, 7))
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : Symbol(x, Decl(controlFlowArrays.ts, 173, 7))
|
||||
}
|
||||
@@ -0,0 +1,615 @@
|
||||
=== tests/cases/compiler/controlFlowArrays.ts ===
|
||||
|
||||
declare function cond(): boolean;
|
||||
>cond : () => boolean
|
||||
|
||||
function f1() {
|
||||
>f1 : () => (string | number | boolean)[]
|
||||
|
||||
let x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
x[0] = 5;
|
||||
>x[0] = 5 : 5
|
||||
>x[0] : any
|
||||
>x : any[]
|
||||
>0 : 0
|
||||
>5 : 5
|
||||
|
||||
x[1] = "hello";
|
||||
>x[1] = "hello" : "hello"
|
||||
>x[1] : any
|
||||
>x : any[]
|
||||
>1 : 1
|
||||
>"hello" : "hello"
|
||||
|
||||
x[2] = true;
|
||||
>x[2] = true : true
|
||||
>x[2] : any
|
||||
>x : any[]
|
||||
>2 : 2
|
||||
>true : true
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f2() {
|
||||
>f2 : () => (string | number | boolean)[]
|
||||
|
||||
let x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
x.push(5);
|
||||
>x.push(5) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>5 : 5
|
||||
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
|
||||
x.push(true);
|
||||
>x.push(true) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>true : true
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f3() {
|
||||
>f3 : () => (string | number)[]
|
||||
|
||||
let x;
|
||||
>x : any
|
||||
|
||||
x = [];
|
||||
>x = [] : never[]
|
||||
>x : any
|
||||
>[] : never[]
|
||||
|
||||
x.push(5, "hello");
|
||||
>x.push(5, "hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>5 : 5
|
||||
>"hello" : "hello"
|
||||
|
||||
return x; // (string | number)[]
|
||||
>x : (string | number)[]
|
||||
}
|
||||
|
||||
function f4() {
|
||||
>f4 : () => (string | number)[]
|
||||
|
||||
let x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
if (cond()) {
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
|
||||
x.push(5);
|
||||
>x.push(5) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>5 : 5
|
||||
}
|
||||
else {
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
}
|
||||
return x; // (string | number)[]
|
||||
>x : (string | number)[]
|
||||
}
|
||||
|
||||
function f5() {
|
||||
>f5 : () => (string | number)[]
|
||||
|
||||
let x;
|
||||
>x : any
|
||||
|
||||
if (cond()) {
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
|
||||
x = [];
|
||||
>x = [] : never[]
|
||||
>x : any
|
||||
>[] : never[]
|
||||
|
||||
x.push(5);
|
||||
>x.push(5) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>5 : 5
|
||||
}
|
||||
else {
|
||||
x = [];
|
||||
>x = [] : never[]
|
||||
>x : any
|
||||
>[] : never[]
|
||||
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
}
|
||||
return x; // (string | number)[]
|
||||
>x : (string | number)[]
|
||||
}
|
||||
|
||||
function f6() {
|
||||
>f6 : () => number | string[]
|
||||
|
||||
let x;
|
||||
>x : any
|
||||
|
||||
if (cond()) {
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
|
||||
x = 5;
|
||||
>x = 5 : 5
|
||||
>x : any
|
||||
>5 : 5
|
||||
}
|
||||
else {
|
||||
x = [];
|
||||
>x = [] : never[]
|
||||
>x : any
|
||||
>[] : never[]
|
||||
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
}
|
||||
return x; // number | string[]
|
||||
>x : number | string[]
|
||||
}
|
||||
|
||||
function f7() {
|
||||
>f7 : () => string[] | null
|
||||
|
||||
let x = null;
|
||||
>x : any
|
||||
>null : null
|
||||
|
||||
if (cond()) {
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
|
||||
x = [];
|
||||
>x = [] : never[]
|
||||
>x : any
|
||||
>[] : never[]
|
||||
|
||||
while (cond()) {
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
}
|
||||
}
|
||||
return x; // string[] | null
|
||||
>x : string[] | null
|
||||
}
|
||||
|
||||
function f8() {
|
||||
>f8 : () => (string | number | boolean)[]
|
||||
|
||||
let x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
x.push(5);
|
||||
>x.push(5) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>5 : 5
|
||||
|
||||
if (cond()) return x; // number[]
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
>x : number[]
|
||||
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
|
||||
if (cond()) return x; // (string | number)[]
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
>x : (string | number)[]
|
||||
|
||||
x.push(true);
|
||||
>x.push(true) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>true : true
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f9() {
|
||||
>f9 : () => string[] | number[]
|
||||
|
||||
let x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
if (cond()) {
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
|
||||
x.push(5);
|
||||
>x.push(5) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>5 : 5
|
||||
|
||||
return x; // number[]
|
||||
>x : number[]
|
||||
}
|
||||
else {
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
|
||||
return x; // string[]
|
||||
>x : string[]
|
||||
}
|
||||
}
|
||||
|
||||
function f10() {
|
||||
>f10 : () => (string | number | boolean)[]
|
||||
|
||||
let x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
if (cond()) {
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
|
||||
x.push(true);
|
||||
>x.push(true) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>true : true
|
||||
|
||||
x; // boolean[]
|
||||
>x : boolean[]
|
||||
}
|
||||
else {
|
||||
x.push(5);
|
||||
>x.push(5) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>5 : 5
|
||||
|
||||
x; // number[]
|
||||
>x : number[]
|
||||
|
||||
while (cond()) {
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
}
|
||||
x; // (string | number)[]
|
||||
>x : (string | number)[]
|
||||
}
|
||||
x.push(99);
|
||||
>x.push(99) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>99 : 99
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f11() {
|
||||
>f11 : () => string[]
|
||||
|
||||
let x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
if (x.length === 0) { // x.length ok on implicit any[]
|
||||
>x.length === 0 : boolean
|
||||
>x.length : number
|
||||
>x : any[]
|
||||
>length : number
|
||||
>0 : 0
|
||||
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
}
|
||||
return x;
|
||||
>x : string[]
|
||||
}
|
||||
|
||||
function f12() {
|
||||
>f12 : () => string[]
|
||||
|
||||
let x;
|
||||
>x : any
|
||||
|
||||
x = [];
|
||||
>x = [] : never[]
|
||||
>x : any
|
||||
>[] : never[]
|
||||
|
||||
if (x.length === 0) { // x.length ok on implicit any[]
|
||||
>x.length === 0 : boolean
|
||||
>x.length : number
|
||||
>x : any[]
|
||||
>length : number
|
||||
>0 : 0
|
||||
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
}
|
||||
return x;
|
||||
>x : string[]
|
||||
}
|
||||
|
||||
function f13() {
|
||||
>f13 : () => (string | number | boolean)[]
|
||||
|
||||
var x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
x.push(5);
|
||||
>x.push(5) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>5 : 5
|
||||
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
|
||||
x.push(true);
|
||||
>x.push(true) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>true : true
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f14() {
|
||||
>f14 : () => (string | number | boolean)[]
|
||||
|
||||
const x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
x.push(5);
|
||||
>x.push(5) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>5 : 5
|
||||
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
|
||||
x.push(true);
|
||||
>x.push(true) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>true : true
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f15() {
|
||||
>f15 : () => string[]
|
||||
|
||||
let x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
while (cond()) {
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
|
||||
while (cond()) {}
|
||||
>cond() : boolean
|
||||
>cond : () => boolean
|
||||
|
||||
x.push("hello");
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
}
|
||||
return x; // string[]
|
||||
>x : string[]
|
||||
}
|
||||
|
||||
function f16() {
|
||||
>f16 : () => (string | number | boolean | { a: number; })[]
|
||||
|
||||
let x;
|
||||
>x : any
|
||||
|
||||
let y;
|
||||
>y : any
|
||||
|
||||
(x = [], x).push(5);
|
||||
>(x = [], x).push(5) : number
|
||||
>(x = [], x).push : (...items: any[]) => number
|
||||
>(x = [], x) : any[]
|
||||
>x = [], x : any[]
|
||||
>x = [] : never[]
|
||||
>x : any
|
||||
>[] : never[]
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>5 : 5
|
||||
|
||||
(x.push("hello"), x).push(true);
|
||||
>(x.push("hello"), x).push(true) : number
|
||||
>(x.push("hello"), x).push : (...items: any[]) => number
|
||||
>(x.push("hello"), x) : any[]
|
||||
>x.push("hello"), x : any[]
|
||||
>x.push("hello") : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>true : true
|
||||
|
||||
((x))[3] = { a: 1 };
|
||||
>((x))[3] = { a: 1 } : { a: number; }
|
||||
>((x))[3] : any
|
||||
>((x)) : any[]
|
||||
>(x) : any[]
|
||||
>x : any[]
|
||||
>3 : 3
|
||||
>{ a: 1 } : { a: number; }
|
||||
>a : number
|
||||
>1 : 1
|
||||
|
||||
return x; // (string | number | boolean | { a: number })[]
|
||||
>x : (string | number | boolean | { a: number; })[]
|
||||
}
|
||||
|
||||
function f17() {
|
||||
>f17 : () => (string | number | boolean)[]
|
||||
|
||||
let x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
x.unshift(5);
|
||||
>x.unshift(5) : number
|
||||
>x.unshift : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>unshift : (...items: any[]) => number
|
||||
>5 : 5
|
||||
|
||||
x.unshift("hello");
|
||||
>x.unshift("hello") : number
|
||||
>x.unshift : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>unshift : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
|
||||
x.unshift(true);
|
||||
>x.unshift(true) : number
|
||||
>x.unshift : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>unshift : (...items: any[]) => number
|
||||
>true : true
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f18() {
|
||||
>f18 : () => (string | number | boolean)[]
|
||||
|
||||
let x = [];
|
||||
>x : any[]
|
||||
>[] : never[]
|
||||
|
||||
x.push(5);
|
||||
>x.push(5) : number
|
||||
>x.push : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>5 : 5
|
||||
|
||||
x.unshift("hello");
|
||||
>x.unshift("hello") : number
|
||||
>x.unshift : (...items: any[]) => number
|
||||
>x : any[]
|
||||
>unshift : (...items: any[]) => number
|
||||
>"hello" : "hello"
|
||||
|
||||
x[2] = true;
|
||||
>x[2] = true : true
|
||||
>x[2] : any
|
||||
>x : any[]
|
||||
>2 : 2
|
||||
>true : true
|
||||
|
||||
return x; // (string | number | boolean)[]
|
||||
>x : (string | number | boolean)[]
|
||||
}
|
||||
@@ -1,17 +1,14 @@
|
||||
tests/cases/compiler/implicitAnyWidenToAny.ts(4,5): error TS7005: Variable 'widenArray' implicitly has an 'any[]' type.
|
||||
tests/cases/compiler/implicitAnyWidenToAny.ts(5,5): error TS7005: Variable 'emptyArray' implicitly has an 'any[]' type.
|
||||
|
||||
|
||||
==== tests/cases/compiler/implicitAnyWidenToAny.ts (2 errors) ====
|
||||
==== tests/cases/compiler/implicitAnyWidenToAny.ts (1 errors) ====
|
||||
// these should be errors
|
||||
var x = null; // error at "x"
|
||||
var x1 = undefined; // error at "x1"
|
||||
var widenArray = [null, undefined]; // error at "widenArray"
|
||||
~~~~~~~~~~
|
||||
!!! error TS7005: Variable 'widenArray' implicitly has an 'any[]' type.
|
||||
var emptyArray = []; // error at "emptyArray"
|
||||
~~~~~~~~~~
|
||||
!!! error TS7005: Variable 'emptyArray' implicitly has an 'any[]' type.
|
||||
var emptyArray = [];
|
||||
|
||||
// these should not be error
|
||||
class AnimalObj {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var x = null; // error at "x"
|
||||
var x1 = undefined; // error at "x1"
|
||||
var widenArray = [null, undefined]; // error at "widenArray"
|
||||
var emptyArray = []; // error at "emptyArray"
|
||||
var emptyArray = [];
|
||||
|
||||
// these should not be error
|
||||
class AnimalObj {
|
||||
@@ -32,7 +32,7 @@ var obj1 = anyReturnFunc();
|
||||
var x = null; // error at "x"
|
||||
var x1 = undefined; // error at "x1"
|
||||
var widenArray = [null, undefined]; // error at "widenArray"
|
||||
var emptyArray = []; // error at "emptyArray"
|
||||
var emptyArray = [];
|
||||
// these should not be error
|
||||
var AnimalObj = (function () {
|
||||
function AnimalObj() {
|
||||
|
||||
@@ -35,12 +35,12 @@ use(data[0]() === data[1]());
|
||||
>use(data[0]() === data[1]()) : any
|
||||
>use : (a: any) => any
|
||||
>data[0]() === data[1]() : boolean
|
||||
>data[0]() : any
|
||||
>data[0] : any
|
||||
>data : any[]
|
||||
>data[0]() : typeof C
|
||||
>data[0] : () => typeof C
|
||||
>data : (() => typeof C)[]
|
||||
>0 : 0
|
||||
>data[1]() : any
|
||||
>data[1] : any
|
||||
>data : any[]
|
||||
>data[1]() : typeof C
|
||||
>data[1] : () => typeof C
|
||||
>data : (() => typeof C)[]
|
||||
>1 : 1
|
||||
|
||||
|
||||
@@ -36,12 +36,12 @@ use(data[0]() === data[1]());
|
||||
>use(data[0]() === data[1]()) : any
|
||||
>use : (a: any) => any
|
||||
>data[0]() === data[1]() : boolean
|
||||
>data[0]() : any
|
||||
>data[0] : any
|
||||
>data : any[]
|
||||
>data[0]() : typeof C
|
||||
>data[0] : () => typeof C
|
||||
>data : (() => typeof C)[]
|
||||
>0 : 0
|
||||
>data[1]() : any
|
||||
>data[1] : any
|
||||
>data : any[]
|
||||
>data[1]() : typeof C
|
||||
>data[1] : () => typeof C
|
||||
>data : (() => typeof C)[]
|
||||
>1 : 1
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ var a3 = void 0;
|
||||
>0 : 0
|
||||
|
||||
var b1 = [];
|
||||
>b1 : never[]
|
||||
>b1 : any[]
|
||||
>[] : never[]
|
||||
|
||||
var b2 = [,];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
=== tests/cases/compiler/typedArrays.ts ===
|
||||
|
||||
function CreateTypedArrayTypes() {
|
||||
>CreateTypedArrayTypes : () => any[]
|
||||
>CreateTypedArrayTypes : () => (Int8ArrayConstructor | Uint8ArrayConstructor | Int16ArrayConstructor | Uint16ArrayConstructor | Int32ArrayConstructor | Uint32ArrayConstructor | Float32ArrayConstructor | Float64ArrayConstructor | Uint8ClampedArrayConstructor)[]
|
||||
|
||||
var typedArrays = [];
|
||||
>typedArrays : any[]
|
||||
@@ -71,11 +71,11 @@ function CreateTypedArrayTypes() {
|
||||
>Uint8ClampedArray : Uint8ClampedArrayConstructor
|
||||
|
||||
return typedArrays;
|
||||
>typedArrays : any[]
|
||||
>typedArrays : (Int8ArrayConstructor | Uint8ArrayConstructor | Int16ArrayConstructor | Uint16ArrayConstructor | Int32ArrayConstructor | Uint32ArrayConstructor | Float32ArrayConstructor | Float64ArrayConstructor | Uint8ClampedArrayConstructor)[]
|
||||
}
|
||||
|
||||
function CreateTypedArrayInstancesFromLength(obj: number) {
|
||||
>CreateTypedArrayInstancesFromLength : (obj: number) => any[]
|
||||
>CreateTypedArrayInstancesFromLength : (obj: number) => (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
>obj : number
|
||||
|
||||
var typedArrays = [];
|
||||
@@ -164,11 +164,11 @@ function CreateTypedArrayInstancesFromLength(obj: number) {
|
||||
>obj : number
|
||||
|
||||
return typedArrays;
|
||||
>typedArrays : any[]
|
||||
>typedArrays : (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
}
|
||||
|
||||
function CreateTypedArrayInstancesFromArray(obj: number[]) {
|
||||
>CreateTypedArrayInstancesFromArray : (obj: number[]) => any[]
|
||||
>CreateTypedArrayInstancesFromArray : (obj: number[]) => (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
>obj : number[]
|
||||
|
||||
var typedArrays = [];
|
||||
@@ -257,11 +257,11 @@ function CreateTypedArrayInstancesFromArray(obj: number[]) {
|
||||
>obj : number[]
|
||||
|
||||
return typedArrays;
|
||||
>typedArrays : any[]
|
||||
>typedArrays : (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
}
|
||||
|
||||
function CreateIntegerTypedArraysFromArray2(obj:number[]) {
|
||||
>CreateIntegerTypedArraysFromArray2 : (obj: number[]) => any[]
|
||||
>CreateIntegerTypedArraysFromArray2 : (obj: number[]) => (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
>obj : number[]
|
||||
|
||||
var typedArrays = [];
|
||||
@@ -368,11 +368,11 @@ function CreateIntegerTypedArraysFromArray2(obj:number[]) {
|
||||
>obj : number[]
|
||||
|
||||
return typedArrays;
|
||||
>typedArrays : any[]
|
||||
>typedArrays : (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
}
|
||||
|
||||
function CreateIntegerTypedArraysFromArrayLike(obj:ArrayLike<number>) {
|
||||
>CreateIntegerTypedArraysFromArrayLike : (obj: ArrayLike<number>) => any[]
|
||||
>CreateIntegerTypedArraysFromArrayLike : (obj: ArrayLike<number>) => (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
>obj : ArrayLike<number>
|
||||
>ArrayLike : ArrayLike<T>
|
||||
|
||||
@@ -480,11 +480,11 @@ function CreateIntegerTypedArraysFromArrayLike(obj:ArrayLike<number>) {
|
||||
>obj : ArrayLike<number>
|
||||
|
||||
return typedArrays;
|
||||
>typedArrays : any[]
|
||||
>typedArrays : (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
}
|
||||
|
||||
function CreateTypedArraysOf(obj) {
|
||||
>CreateTypedArraysOf : (obj: any) => any[]
|
||||
>CreateTypedArraysOf : (obj: any) => (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
>obj : any
|
||||
|
||||
var typedArrays = [];
|
||||
@@ -600,11 +600,11 @@ function CreateTypedArraysOf(obj) {
|
||||
>obj : any
|
||||
|
||||
return typedArrays;
|
||||
>typedArrays : any[]
|
||||
>typedArrays : (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
}
|
||||
|
||||
function CreateTypedArraysOf2() {
|
||||
>CreateTypedArraysOf2 : () => any[]
|
||||
>CreateTypedArraysOf2 : () => (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
|
||||
var typedArrays = [];
|
||||
>typedArrays : any[]
|
||||
@@ -737,11 +737,11 @@ function CreateTypedArraysOf2() {
|
||||
>4 : 4
|
||||
|
||||
return typedArrays;
|
||||
>typedArrays : any[]
|
||||
>typedArrays : (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
}
|
||||
|
||||
function CreateTypedArraysFromMapFn(obj:ArrayLike<number>, mapFn: (n:number, v:number)=> number) {
|
||||
>CreateTypedArraysFromMapFn : (obj: ArrayLike<number>, mapFn: (n: number, v: number) => number) => any[]
|
||||
>CreateTypedArraysFromMapFn : (obj: ArrayLike<number>, mapFn: (n: number, v: number) => number) => (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
>obj : ArrayLike<number>
|
||||
>ArrayLike : ArrayLike<T>
|
||||
>mapFn : (n: number, v: number) => number
|
||||
@@ -861,11 +861,11 @@ function CreateTypedArraysFromMapFn(obj:ArrayLike<number>, mapFn: (n:number, v:n
|
||||
>mapFn : (n: number, v: number) => number
|
||||
|
||||
return typedArrays;
|
||||
>typedArrays : any[]
|
||||
>typedArrays : (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
}
|
||||
|
||||
function CreateTypedArraysFromThisObj(obj:ArrayLike<number>, mapFn: (n:number, v:number)=> number, thisArg: {}) {
|
||||
>CreateTypedArraysFromThisObj : (obj: ArrayLike<number>, mapFn: (n: number, v: number) => number, thisArg: {}) => any[]
|
||||
>CreateTypedArraysFromThisObj : (obj: ArrayLike<number>, mapFn: (n: number, v: number) => number, thisArg: {}) => (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
>obj : ArrayLike<number>
|
||||
>ArrayLike : ArrayLike<T>
|
||||
>mapFn : (n: number, v: number) => number
|
||||
@@ -995,5 +995,5 @@ function CreateTypedArraysFromThisObj(obj:ArrayLike<number>, mapFn: (n:number, v
|
||||
>thisArg : {}
|
||||
|
||||
return typedArrays;
|
||||
>typedArrays : any[]
|
||||
>typedArrays : (Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array)[]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// @noImplicitAny: true
|
||||
|
||||
declare function cond(): boolean;
|
||||
|
||||
function f1() {
|
||||
let x = []; // Implicit any[] error in some locations
|
||||
let y = x; // Implicit any[] error
|
||||
x.push(5);
|
||||
let z = x;
|
||||
}
|
||||
|
||||
function f2() {
|
||||
let x; // Implicit any[] error in some locations
|
||||
x = [];
|
||||
let y = x; // Implicit any[] error
|
||||
x.push(5);
|
||||
let z = x;
|
||||
}
|
||||
|
||||
function f3() {
|
||||
let x = []; // Implicit any[] error in some locations
|
||||
x.push(5);
|
||||
function g() {
|
||||
x; // Implicit any[] error
|
||||
}
|
||||
}
|
||||
|
||||
function f4() {
|
||||
let x;
|
||||
x = [5, "hello"]; // Non-evolving array
|
||||
x.push(true); // Error
|
||||
}
|
||||
|
||||
function f5() {
|
||||
let x = [5, "hello"]; // Non-evolving array
|
||||
x.push(true); // Error
|
||||
}
|
||||
|
||||
function f6() {
|
||||
let x;
|
||||
if (cond()) {
|
||||
x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
}
|
||||
else {
|
||||
x = [true]; // Non-evolving array
|
||||
}
|
||||
x; // boolean[] | (string | number)[]
|
||||
x.push(99); // Error
|
||||
}
|
||||
|
||||
function f7() {
|
||||
let x = []; // x has evolving array value
|
||||
x.push(5);
|
||||
let y = x; // y has non-evolving array value
|
||||
x.push("hello"); // Ok
|
||||
y.push("hello"); // Error
|
||||
}
|
||||
|
||||
function f8() {
|
||||
const x = []; // Implicit any[] error in some locations
|
||||
x.push(5);
|
||||
function g() {
|
||||
x; // Implicit any[] error
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
// @strictNullChecks: true
|
||||
// @noImplicitAny: true
|
||||
|
||||
declare function cond(): boolean;
|
||||
|
||||
function f1() {
|
||||
let x = [];
|
||||
x[0] = 5;
|
||||
x[1] = "hello";
|
||||
x[2] = true;
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f2() {
|
||||
let x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f3() {
|
||||
let x;
|
||||
x = [];
|
||||
x.push(5, "hello");
|
||||
return x; // (string | number)[]
|
||||
}
|
||||
|
||||
function f4() {
|
||||
let x = [];
|
||||
if (cond()) {
|
||||
x.push(5);
|
||||
}
|
||||
else {
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // (string | number)[]
|
||||
}
|
||||
|
||||
function f5() {
|
||||
let x;
|
||||
if (cond()) {
|
||||
x = [];
|
||||
x.push(5);
|
||||
}
|
||||
else {
|
||||
x = [];
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // (string | number)[]
|
||||
}
|
||||
|
||||
function f6() {
|
||||
let x;
|
||||
if (cond()) {
|
||||
x = 5;
|
||||
}
|
||||
else {
|
||||
x = [];
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // number | string[]
|
||||
}
|
||||
|
||||
function f7() {
|
||||
let x = null;
|
||||
if (cond()) {
|
||||
x = [];
|
||||
while (cond()) {
|
||||
x.push("hello");
|
||||
}
|
||||
}
|
||||
return x; // string[] | null
|
||||
}
|
||||
|
||||
function f8() {
|
||||
let x = [];
|
||||
x.push(5);
|
||||
if (cond()) return x; // number[]
|
||||
x.push("hello");
|
||||
if (cond()) return x; // (string | number)[]
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f9() {
|
||||
let x = [];
|
||||
if (cond()) {
|
||||
x.push(5);
|
||||
return x; // number[]
|
||||
}
|
||||
else {
|
||||
x.push("hello");
|
||||
return x; // string[]
|
||||
}
|
||||
}
|
||||
|
||||
function f10() {
|
||||
let x = [];
|
||||
if (cond()) {
|
||||
x.push(true);
|
||||
x; // boolean[]
|
||||
}
|
||||
else {
|
||||
x.push(5);
|
||||
x; // number[]
|
||||
while (cond()) {
|
||||
x.push("hello");
|
||||
}
|
||||
x; // (string | number)[]
|
||||
}
|
||||
x.push(99);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f11() {
|
||||
let x = [];
|
||||
if (x.length === 0) { // x.length ok on implicit any[]
|
||||
x.push("hello");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
function f12() {
|
||||
let x;
|
||||
x = [];
|
||||
if (x.length === 0) { // x.length ok on implicit any[]
|
||||
x.push("hello");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
function f13() {
|
||||
var x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f14() {
|
||||
const x = [];
|
||||
x.push(5);
|
||||
x.push("hello");
|
||||
x.push(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f15() {
|
||||
let x = [];
|
||||
while (cond()) {
|
||||
while (cond()) {}
|
||||
x.push("hello");
|
||||
}
|
||||
return x; // string[]
|
||||
}
|
||||
|
||||
function f16() {
|
||||
let x;
|
||||
let y;
|
||||
(x = [], x).push(5);
|
||||
(x.push("hello"), x).push(true);
|
||||
((x))[3] = { a: 1 };
|
||||
return x; // (string | number | boolean | { a: number })[]
|
||||
}
|
||||
|
||||
function f17() {
|
||||
let x = [];
|
||||
x.unshift(5);
|
||||
x.unshift("hello");
|
||||
x.unshift(true);
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
|
||||
function f18() {
|
||||
let x = [];
|
||||
x.push(5);
|
||||
x.unshift("hello");
|
||||
x[2] = true;
|
||||
return x; // (string | number | boolean)[]
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
var x = null; // error at "x"
|
||||
var x1 = undefined; // error at "x1"
|
||||
var widenArray = [null, undefined]; // error at "widenArray"
|
||||
var emptyArray = []; // error at "emptyArray"
|
||||
var emptyArray = [];
|
||||
|
||||
// these should not be error
|
||||
class AnimalObj {
|
||||
|
||||
Reference in New Issue
Block a user