Skip to content

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

Merged
weswigham merged 8 commits into
microsoft:masterfrom
weswigham:get-symbol-at-location-fix
Dec 15, 2017
Merged

Fix get symbol at location to behave correctly for parameter assignments and jsx attributes#20706
weswigham merged 8 commits into
microsoft:masterfrom
weswigham:get-symbol-at-location-fix

Conversation

@weswigham
Copy link
Copy Markdown
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
Copy Markdown
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.

Comment thread src/compiler/checker.ts Outdated
// 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
Copy Markdown
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
Copy Markdown
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.

Comment thread src/compiler/parser.ts
case SyntaxKind.Parameter:
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<ParameterDeclaration>node).dotDotDotToken) ||
Copy link
Copy Markdown
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
Copy Markdown
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.

Comment thread src/compiler/types.ts
type?: TypeNode;
initializer?: Expression;
}
export type VariableLikeDeclaration =
Copy link
Copy Markdown
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
Copy Markdown
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.).

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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.


/** @type {string|undefined} */
foo: undefined,
>foo : string | undefined
Copy link
Copy Markdown
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
Copy Markdown
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


for ({name: nameA } of robots) {
>{name: nameA } : { name: string; }
>name : Robot
Copy link
Copy Markdown
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
Copy Markdown
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.

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
Copy Markdown
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
Copy Markdown
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.

Comment thread src/compiler/utilities.ts Outdated
case SyntaxKind.Parameter:
case SyntaxKind.VariableDeclaration:
return node === (<VariableLikeDeclaration>parent).type;
return node === (parent as Node & { type: Node }).type;
Copy link
Copy Markdown
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
Copy Markdown
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.

Comment thread src/compiler/utilities.ts Outdated
/** True if has type node attached to it. */
/* @internal */
export function hasType(node: Node): node is HasType {
return !!(node as TypeContainer).type;
Copy link
Copy Markdown
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
Copy Markdown
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