Skip to content
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

Simplify single-case pattern match using let destructuring #3574

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

vkobinski
Copy link
Contributor

Fixes #3562

@vkobinski
Copy link
Contributor Author

@lpil What should I do with the tests that use a single case pattern match? Change them?

@GearsDatapacks
Copy link
Contributor

Probably, yes. Also, you'll want to add tests for this new warning.
And in the issue I mentioned adding a code action to fix this warning. Do you think you could implement that?

@vkobinski
Copy link
Contributor Author

Probably, yes. Also, you'll want to add tests for this new warning. And in the issue I mentioned adding a code action to fix this warning. Do you think you could implement that?

The code action should be implemented in the lsp area of the repository? I think i could implement it.

@GearsDatapacks
Copy link
Contributor

The code action should be implemented in the lsp area of the repository?

Correct. It should be in the language_server/code_action.rs file. You can look at the code_action_unused_imports function (which still might be in engine.rs), and see how it finds all the matching warnings, and iterates through them. Instead of replacing the text with an empty string, you can just replace it with whatever the hint is for that warning

@@ -3358,6 +3361,39 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
Ok(())
}

fn check_single_case(&mut self, clauses: &[UntypedClause]) {
if clauses.len() > 1 {
Copy link
Member

Choose a reason for hiding this comment

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

Does this emit a warning if the case is inexhaustive? It shouldn't.

We also want to emit a warning for non-constructor single clause case expressions.

@lpil
Copy link
Member

lpil commented Sep 1, 2024

Thank you!

@lpil lpil marked this pull request as draft September 1, 2024 13:06
_ => None,
})
.join(", ");
let hint = EcoString::from(format!("let {name}({args}) = ..."));
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think it's a good idea to reformat the pattern here. Some information, such as whether the constructor is qualified, will be lost. And, as louis pointed out, this only works for constructor patterns at the moment. What I did for the "let assert to case" action is to get the location of the pattern and copy the exact string value from the source. I'm not sure if you have access to the source here though

Also, you can use eco_format! instead of format! and EcoString::from

@vkobinski
Copy link
Contributor Author

I am implementing the changes you both suggested!

@vkobinski
Copy link
Contributor Author

@GearsDatapacks can you suggest any example of a single case simplification where the pattern is not a constructor?

@vkobinski
Copy link
Contributor Author

I was able to implement the code action for the constructor case! I'm going to make the code action work for other cases too.

@GearsDatapacks
Copy link
Contributor

@GearsDatapacks can you suggest any example of a single case simplification where the pattern is not a constructor?

For example,

case my_tuple {
  #(a, b) -> do_stuff(a, b)
}

Can be rewritten as

let #(a, b) = my_tuple
do_stuff(a, b)

@GearsDatapacks
Copy link
Contributor

I've just realised something which might make this code action a little more complex.

What do you expect to happen if you run the code action on:

let v = case a {
  #(_, value, _) -> value
}

We still need to make sure we bind v in this case, and that we don't generate let v = let #(_, value, _) = a, which is invalid.

Maybe for now we should only offer the code action if the case is in statement position, since that's the only place where let is allowed. It's possible to do this rewrite anywhere, but it requires a lot more calculations for the non-trivial case.

@lpil
Copy link
Member

lpil commented Sep 20, 2024

That's a good observation. Is this code action very useful given that limitation?

@GearsDatapacks
Copy link
Contributor

Perhaps not. It could still me useful in some cases, but I imagine the majority will be using let assignment to extract values. Maybe this should just be a warning for now

@giacomocavalieri
Copy link
Member

Maybe this should just be a warning for now

But what if someone is using a case because they know they'll add more variants to the type to make it easier to change the code later?

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.

Add a warning for single pattern case expression
4 participants