Skip to content

Fix duplicate errors in js special assignments #24508

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 6 commits into from
Jun 26, 2018

Conversation

sandersn
Copy link
Member

Fixes #24252 by not adding a deferred check in getWidenedTypeFromJSSpecialAssignment. This check will be duplicated by the normal checker's walk.

@sandersn sandersn requested a review from mhegazy May 30, 2018 23:30
@@ -4627,7 +4628,7 @@ namespace ts {
// function/class/{} assignments are fresh declarations, not property assignments, so only add prototype assignments
const specialDeclaration = getAssignedJavascriptInitializer(symbol.valueDeclaration);
if (specialDeclaration) {
return getWidenedLiteralType(checkExpressionCached(specialDeclaration));
return getWidenedLiteralType(checkExpressionCached(specialDeclaration, CheckMode.NoDeferredCheck));
Copy link
Member

Choose a reason for hiding this comment

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

So. CheckMode.NoDeferredCheck isn't falsy. Which means this call to checkExpressionCached is really a roundabout call to checkExpression.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, nice catch. Fixed.

Aside: This means that, originally, the second check of the method body must have gone through checkExpression already or it would have gotten the resolved type and avoided it. This leads to an invariant: once you call checkExpressionCached you should only ever call checkExpressionCached afterward, not checkExpression. Or checkExpression should check links.resolvedType before doing any work.

What's more, it's not in general safe to check any node twice because of side effects to deferredNodes. Maybe expensive asserts in checkDeferredNodes would actually be worth it...

Later: I added the resolvedType check in checkExpression and the only change it makes to tests is the order that a couple of unions print in. So it might be a worthwhile change — even better than the current one, in fact.

@sandersn
Copy link
Member Author

Reprinting my comment from above, because github attached it to a now-outdated line:

This means that, originally, the second check of the method body must have gone through checkExpression already or it would have gotten the resolved type and avoided it. This leads to an invariant: once you call checkExpressionCached you should only ever call checkExpressionCached afterward, not checkExpression. Or checkExpression should check links.resolvedType before doing any work.

What's more, it's not in general safe to check any node twice because of side effects to deferredNodes. Maybe expensive asserts in checkDeferredNodes would actually be worth it...

Later: I added the resolvedType check in checkExpression and the only change it makes to tests is the order that a couple of unions print in. So it might be a worthwhile change — even better than the current one, in fact.

@sandersn
Copy link
Member Author

@weswigham @Andy-MS let's talk about this after the standup today since I believe you both have spent more time thinking about deferred nodes than I have.

@sandersn
Copy link
Member Author

sandersn commented May 31, 2018

We decided that nobody trusts our test coverage to tell us if using the resolvedType from checkExpressionCached in checkExpression is safe. I'll leave the PR the way it is.

@sandersn
Copy link
Member Author

@weswigham @mhegazy User tests are still moving duplicate errors around because of this bug. Mind taking another look?

Copy link
Member

@weswigham weswigham left a comment

Choose a reason for hiding this comment

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

This is OK. We've had a lot of bugs w.r.t. the deferred checking though - shouldn't we just use a map/set instead of an array, so we don't have to think about "will another codepath have added this to the deferred list"?

@@ -598,6 +598,7 @@ namespace ts {
SkipContextSensitive = 1, // Skip context sensitive function expressions
Inferential = 2, // Inferential typing
Contextual = 3, // Normal type checking informed by a contextual type, therefore not cacheable
NoDeferredCheck = 4, // Don't add any nodes for deferred checking
}
Copy link
Member

Choose a reason for hiding this comment

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

The comment is a little misleading since it only disables deferred checking for class expressions - should probably mention that so someone doesn't come back later and because "it doesn't do what it says it does", "fix" it.

@sandersn
Copy link
Member Author

Ah, I had forgotten (and didn't write down) your Map suggestion. I will try it and see how it goes.

I'm not sure it will work in this case, though, because I think there's one deferred check and one in-order check. Switching to Map is worthwhile just for the ability to add a cheap no-dupes assert, though.

@sandersn
Copy link
Member Author

Looks like I was wrong -- switching to a map suffices to fix the bug. I'll just do that.

@sandersn sandersn merged commit 9044589 into master Jun 26, 2018
@sandersn sandersn deleted the fix-duplicate-errors-in-js-special-assignments branch June 26, 2018 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants