Skip to content

Don't include already-covered cases in switch completions #51790

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
Dec 13, 2022

Conversation

gabritto
Copy link
Member

@gabritto gabritto commented Dec 6, 2022

Fixes #13711.

@typescript-bot typescript-bot added Author: Team For Milestone Bug PRs that fix a bug with a specific milestone labels Dec 6, 2022
if (caseClause && (isCaseKeyword(contextToken!) || isNodeDescendantOf(contextToken!, caseClause.expression))) {
const tracker = newCaseClauseTracker(checker, caseClause.parent.clauses);
literals = literals.filter(literal => !tracker.hasValue(literal));
symbols.forEach((symbol, i) => {
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 can't filter the symbols array because the index of a symbol in this array is tied to the information in symbolToOriginInfoMap. I didn't want to create an abstraction on top of these two arrays and refactor everything, so I added an "ignore" flag to the origin info, but I'm open to suggestions on other ways to achieve this.

Copy link
Member

Choose a reason for hiding this comment

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

We are overdue to make a nice abstraction over a similar data structure to what we have so it’s easier to work with without sacrificing (and probably improving on) the reasonably efficient allocations we have going. This seems fine for now.

const tracker = newCaseClauseTracker(checker, caseClause.parent.clauses);
literals = literals.filter(literal => !tracker.hasValue(literal));
symbols.forEach((symbol, i) => {
if (symbol.valueDeclaration && isEnumMember(symbol.valueDeclaration)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Note that the filtering won't work if someone is using e.g. an object literal as an enum, because checker.constantValue only works for enum members. But I'm hoping that filtering out literals and enum members already covers a lot of the cases.

Copy link
Member

Choose a reason for hiding this comment

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

Seems like something that can be expanded to readonly members with literal types if there’s demand for it 👍

@Andarist
Copy link
Contributor

Andarist commented Dec 7, 2022

Oh yes! Thank you ❤️

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.

Your comment on the reason for marking symbols as ignored might be worth putting in the code as well.

if (caseClause && (isCaseKeyword(contextToken!) || isNodeDescendantOf(contextToken!, caseClause.expression))) {
const tracker = newCaseClauseTracker(checker, caseClause.parent.clauses);
literals = literals.filter(literal => !tracker.hasValue(literal));
symbols.forEach((symbol, i) => {
Copy link
Member

Choose a reason for hiding this comment

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

We are overdue to make a nice abstraction over a similar data structure to what we have so it’s easier to work with without sacrificing (and probably improving on) the reasonably efficient allocations we have going. This seems fine for now.

// filter literals & enum symbols whose values are already present in existing case clauses.
const caseClause = findAncestor(contextToken, isCaseClause);
if (caseClause && (isCaseKeyword(contextToken!) || isNodeDescendantOf(contextToken!, caseClause.expression))) {
const tracker = newCaseClauseTracker(checker, caseClause.parent.clauses);
Copy link
Member

Choose a reason for hiding this comment

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

Very cool that this abstraction came in handy in an additional place 🎉

const tracker = newCaseClauseTracker(checker, caseClause.parent.clauses);
literals = literals.filter(literal => !tracker.hasValue(literal));
symbols.forEach((symbol, i) => {
if (symbol.valueDeclaration && isEnumMember(symbol.valueDeclaration)) {
Copy link
Member

Choose a reason for hiding this comment

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

Seems like something that can be expanded to readonly members with literal types if there’s demand for it 👍

@gabritto gabritto merged commit ad354c2 into main Dec 13, 2022
@gabritto gabritto deleted the gabritto/issue13711 branch December 13, 2022 21:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Milestone Bug PRs that fix a bug with a specific milestone
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Completions in switch: don't include already-covered cases
5 participants