GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Control flow analysis for array construction by ahejlsberg · Pull Request #11432 · microsoft/TypeScript Conversation
|
|
Will this affect a problem (#11082) I submitted earlier? This sounds like its different enough from my problem but wanted to check if there is any overlap, thanks! |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| return result; | ||
| } | ||
|
|
||
| // Maps from T to T and avoids allocation of all elements map to themselves |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
typo: of → if
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
zenmumbler No, this PR doesn't affect the issue in #11082. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Mohamed Hegazy (@mhegazy) Want to take a look before I merge this? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Besides a few small changes, I also want to make sure we're OK with less localised errors in a series of functions with no return type annotations. In the example below, the error moves from the line with 'oops' on it to the last line.
function f() { let x = []; x.push(12); x.push('oops'); return x; } function g() { let a = g(); a.push('oops 2'); // shouldn't be allowed return a; // g now has type (string | number)[] } let sum = 0; for (const n of g()) { sum += n; // error, can't add (string | number) to number }
Right now, I think I'm on the side of fewer annotations, but I think we should know about the pitfalls of the new behaviour.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| var widenArray = [null, undefined]; // error at "widenArray" | ||
| ~~~~~~~~~~ | ||
| !!! error TS7005: Variable 'widenArray' implicitly has an 'any[]' type. | ||
| var emptyArray = []; // error at "emptyArray" |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Delete comment and consider deleting the entire line.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Yes, will fix.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
|
||
| declare function cond(): boolean; | ||
|
|
||
| function f1() { |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have meaningful names for these test cases
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I think we're fine with the short names.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| x[1] = "hello"; | ||
| x[2] = true; | ||
| return x; // (string | number | boolean)[] | ||
| } |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
what about a test case that case that does x[0] = 5; x[0] = "hello"; x[0] = true? It would still return (string | number | boolean)[], right?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Yes, you'd get the same type. We don't look at the value of the index expression, so nothing gained by an additional test.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| } | ||
| if (node.expression.kind === SyntaxKind.PropertyAccessExpression) { | ||
| const propertyAccess = <PropertyAccessExpression>node.expression; | ||
| if (isNarrowableOperand(propertyAccess.expression) && propertyAccess.name.text === "push") { |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
what about unshift? I used unshift briefly when writing spread types. :)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Yup, we should support unshift, uncommon as it may be.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| } | ||
|
|
||
| function isEmptyArrayAssignment(node: VariableDeclaration | BindingElement | Expression) { | ||
| return node.kind === SyntaxKind.VariableDeclaration && (<VariableDeclaration>node).initializer && isEmptyArrayLiteral((<VariableDeclaration>node).initializer) || |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
can you break these lines up a bit more? They are really hard to read on github.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Sure.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| return incomplete ? { flags: 0, type } : type; | ||
| } | ||
|
|
||
| // An evolving array type tracks the element types that have so far been seen in an |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
comment should be jsdoc formatted
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| export interface AnonymousType extends ObjectType { | ||
| target?: AnonymousType; // Instantiation target | ||
| mapper?: TypeMapper; // Instantiation mapper | ||
| elementType?: Type; // Element expressions of evolving array type |
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
why isn't AutoArrayType a new subtype of AnonymousType? I think it would make it easier to track the property that auto array types don't escape the dynamic scope of getFlowTypeOfReference.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I don't follow. autoArrayType is the declared type of an auto-inferred any[] and it's already used outside of getFlowTypeOfReference.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
It's separate from autoArrayType, whose type is actually TypeReference.
I'm talking about the comment at the top of the new code that says
Evolving array types are ultimately converted into manifest array types
and never escape the getFlowTypeOfReference function."
I was suggesting something like:
export interface AutoArrayType extends AnonymousType { elementType?: Type; finalArrayType?: Type; }
And then having the new code that returns AnonymousType today return AutoArrayType instead.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see. The issue with doing it that way is that we don't have a TypeFlags.EvolvingArrayType that would indicate an evolving array type (because we're out of flag bits). Instead, we distinguish by looking for the elementType property on AnonymousType, so it has to be part of AnonymousType.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Ok, that makes sense.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction); | ||
| } | ||
|
|
||
| // Return true if the given node is 'x' in an 'x.push(value)' operation. |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
should support unshift here too
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| visitedFlowCount = visitedFlowStart; | ||
| if (reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(result, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) { | ||
| // When the reference is 'x' in an 'x.push(value)' or 'x[n] = value' operation, we give type | ||
| // 'any[]' to 'x' instead of using the type determed by control flow analysis such that new |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
typo:determined
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
With the latest commits, when an evolving array has no function f1() { let a = []; if (cond()) { a.push("hello"); } a; // string[] } function f2() { let a = []; a; // any[], error with --noImplicitAny } Note that references to the function f3() { let a = []; while (a.length < 10) { a.push("test"); } return a; // string[] } |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Mohamed Hegazy (@mhegazy) Latest commits should solve the issue we discussed yesterday. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
# Conflicts: # src/compiler/checker.ts
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.