Skip to content

Don't issue a use-before-declared error for a property that exists in a superclass#17910

Merged
3 commits merged into
masterfrom
useBeforeDeclaration_superClass
Aug 29, 2017
Merged

Don't issue a use-before-declared error for a property that exists in a superclass#17910
3 commits merged into
masterfrom
useBeforeDeclaration_superClass

Conversation

@ghost
Copy link
Copy Markdown

@ghost ghost commented Aug 18, 2017

Fixes #14822

@sandersn What's the proper way to get a superclass symbol from a class symbol?

@ghost ghost requested a review from sandersn August 18, 2017 21:21
Comment thread src/compiler/checker.ts
if (isInPropertyInitializer(node) &&
!isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right)
&& !isPropertyDeclaredInAncestorClass(prop)) {
error(right, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, unescapeLeadingUnderscores(right.escapedText));
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Should we change this to say "property" instead of "block-scoped variable"?

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.

Looks pretty good, although I want to see what it looks like after changing to use getBaseTypes.

Comment thread src/compiler/checker.ts Outdated

// TODO: there must be a better way of doing this
function getSuperClass(classSymbol: Symbol): Symbol | undefined {
const classDecl = classSymbol.valueDeclaration;
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.

return getBaseTypes(getTypeOfSymbol(classSymbol)).map(t => t.symbol); but this makes the return type Symbol[] not Symbol | 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.

Oh, maybe this only applies to base types that are classes, in which case you can filter for that and assert that there's only one.

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.

Or maybe assume that there's only one; I believe that the code for getBaseTypes is pretty clear that there's only one.

Comment thread src/compiler/checker.ts Outdated
}

function isPropertyDeclaredInAncestorClass(prop: Symbol): boolean {
// It's possible that "prop.valueDeclaration" is a local declaration, but the property was also declared in a superclass.
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.

use jsdoc syntax for this comment

Comment thread src/compiler/checker.ts Outdated
// In that case we won't consider it used before its declaration, because it gets its value from the superclass' declaration.
let classSymbol = prop.parent;
while (true) {
classSymbol = getSuperClass(classSymbol);
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 change getSuperClass to return Type, rename classSymbol to classType, and then change to const superProperty = getPropertyOfType(classType)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Is it not safe to access members directly? We should document that if so.

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.

No, the main point is to switch to retrieving the super Type instead of the Symbol. After that, the correct/easiest way to retrieve the property symbol is getPropertyOfType not type.symbol.members.get

@ghost
Copy link
Copy Markdown
Author

ghost commented Aug 29, 2017

@sandersn Any more comments?

Comment thread src/compiler/checker.ts
*/
function isPropertyDeclaredInAncestorClass(prop: Symbol): boolean {
let classType = getTypeOfSymbol(prop.parent) as InterfaceType;
while (true) {
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.

It sure would be convenient to say while (classType = getSuperClass(classType)) here, but we only use this idiom one other place in checker, so perhaps not good to start now.

@ghost ghost merged commit 7306b13 into master Aug 29, 2017
@ghost ghost deleted the useBeforeDeclaration_superClass branch August 29, 2017 16:18
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
This pull request was closed.
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