Skip to content

Fix get symbol at location to behave correctly for parameter assignments and jsx attributes #20706

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 15, 2017

Conversation

weswigham
Copy link
Member

@weswigham weswigham commented Dec 14, 2017

Fixes #19041

The corrected type baselines have exposed another bug - note all the literal types in TSX files (opened #20705 to track it).

@weswigham weswigham force-pushed the get-symbol-at-location-fix branch from cafb3c5 to 7405a9c Compare December 15, 2017 18:17
Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor questions left, although it turns out you either answered or fixed a lot of them.

@@ -4216,7 +4216,7 @@ namespace ts {

// Return the type of a binding element parent. We check SymbolLinks first to see if a type has been
// assigned by contextual typing.
function getTypeForBindingElementParent(node: VariableLikeDeclaration) {
function getTypeForBindingElementParent(node: BindingElement["parent"]["parent"]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too cute + too obscure for me. Since it appears to be equivalent to VariableDeclaration | ParameterDeclaration | BindingElement, why not use that or create an alias for it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to use BindingElement["parent"]["parent"] so it stays in sync with changes to both binding elements' types and their parents' types - so an alias it is.

@@ -88,20 +88,48 @@ namespace ts {
case SyntaxKind.SpreadAssignment:
return visitNode(cbNode, (<SpreadAssignment>node).expression);
case SyntaxKind.Parameter:
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<ParameterDeclaration>node).dotDotDotToken) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why can't these be shared any more? Are there order conflicts in the current, shared version?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The union won't allow access to properties that don't exist on every node. Also, this is less polymorphic, so should have slightly better performance.

type?: TypeNode;
initializer?: Expression;
}
export type VariableLikeDeclaration =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

performance? I remember doing this (or similar) and found it added quite a bit of time to our build.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no noticeable difference in self-compilation (maybe slightly better? The difference is in the noise.).

@@ -453,6 +453,9 @@ declare namespace ts {
interface JSDocContainer {
}
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | EndOfFileToken;
type HasType = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertySignature | PropertyDeclaration | TypePredicateNode | ParenthesizedTypeNode | TypeOperatorNode | MappedTypeNode | AssertionExpression | TypeAliasDeclaration | JSDocTypeExpression | JSDocNonNullableType | JSDocNullableType | JSDocOptionalType | JSDocVariadicType;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these aliases meant to be public? I guess maybe they are required for export to services/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to make them public (like HasJSDoc), because knowing what nodes have a .type or a .initializer is a useful set of nodes, IMO. It can be internal, since I don't think any public functions use them?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't care much either way, just checking.

@@ -10,12 +10,12 @@ const obj = {

/** @type {string|undefined} */
foo: undefined,
>foo : string | undefined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this change seems incorrect

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix'd since this comment was first submitted

@@ -103,7 +103,7 @@ let name: string, primary: string, secondary: string, skill: string;

for ({name: nameA } of robots) {
>{name: nameA } : { name: string; }
>name : Robot
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this change is confusing. Either the baseline was wrong before or it's wrong now. I think it was wrong before.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was wrong before.

@@ -25,5 +25,5 @@ verify.referenceGroups(r2, [
]);
verify.referenceGroups(r4, [
{ definition: "(property) I.property1: number", ranges: [r0, r1, r2, r3] },
{ definition: "(property) property1: I", ranges: [r4] }
{ definition: "(property) property1: any", ranges: [r4] }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing. What is correct here? any shouldn't be it, but I don't think I is correct either.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was very wrong. any is at least the type of p2, which is bound to the same symbol as that property because the object literal at this location isn't being correctly interpreted as a binding pattern in all locations. This PR is like a partial fix for that (now the type isn't completely incorrect, at least), but the symbols still need to be bound up correctly. IMO, the root cause is object literal/binding pattern confusion causing us to not handle binding patterns correctly in all the places we need to. I'd like to do a more directed fix at making binding patterns actually appear in expression positions instead of object literals when they're actually binding patterns, and use that to fix this.

For now, this is much better, though.

@@ -784,7 +784,7 @@ namespace ts {
case SyntaxKind.PropertySignature:
case SyntaxKind.Parameter:
case SyntaxKind.VariableDeclaration:
return node === (<VariableLikeDeclaration>parent).type;
return node === (parent as Node & { type: Node }).type;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:( parsing for humans (looks like (parent as Node) & { type: Node } at first glance)

So wouldn't parent as HasType work too? It would be easier to read.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or just parent as TypeContainer.

/** True if has type node attached to it. */
/* @internal */
export function hasType(node: Node): node is HasType {
return !!(node as TypeContainer).type;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would drop TypeContainer and just use any.

@weswigham
Copy link
Member Author

@sandersn Have I addressed all of your comments?

@weswigham weswigham merged commit dd933f4 into microsoft:master Dec 15, 2017
@weswigham weswigham deleted the get-symbol-at-location-fix branch December 15, 2017 23:50
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants