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

fix: make bool_to_enum assist create enum at top-level #15667

Merged
merged 3 commits into from Sep 29, 2023

Conversation

rmehri01
Copy link
Contributor

@rmehri01 rmehri01 commented Sep 26, 2023

This pr makes the bool_to_enum assist create the enum at the next closest module block or at top-level, which fixes a few tricky cases such as with an associated const in a trait or module:

trait Foo {
    const $0BOOL: bool;
}

impl Foo for usize {
    const BOOL: bool = true;
}

fn main() {
    if <usize as Foo>::BOOL {
        println!("foo");
    }
}

Which now properly produces:

#[derive(PartialEq, Eq)]
enum Bool { True, False }

trait Foo {
    const BOOL: Bool;
}

impl Foo for usize {
    const BOOL: Bool = Bool::True;
}

fn main() {
    if <usize as Foo>::BOOL == Bool::True {
        println!("foo");
    }
}

I also think it's a bit nicer, especially for local variables, but didn't really know to do it in the first PR :)

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 26, 2023
Comment on lines 475 to 503
/// Finds where to put the new enum definition, at the nearest module or at top-level.
fn node_to_insert_before(mut target_node: SyntaxNode) -> SyntaxNode {
let mut ancestors = target_node.ancestors();

while let Some(ancestor) = ancestors.next() {
match_ast! {
match ancestor {
ast::Item(item) => {
if item
.syntax()
.parent()
.and_then(|item_list| item_list.parent())
.and_then(ast::Module::cast)
.is_some()
{
return ancestor;
}
},
ast::SourceFile(_) => break,
_ => (),
}
}

target_node = ancestor;
}

target_node
}

Copy link
Member

Choose a reason for hiding this comment

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

This can be simplified to

Suggested change
/// Finds where to put the new enum definition, at the nearest module or at top-level.
fn node_to_insert_before(mut target_node: SyntaxNode) -> SyntaxNode {
let mut ancestors = target_node.ancestors();
while let Some(ancestor) = ancestors.next() {
match_ast! {
match ancestor {
ast::Item(item) => {
if item
.syntax()
.parent()
.and_then(|item_list| item_list.parent())
.and_then(ast::Module::cast)
.is_some()
{
return ancestor;
}
},
ast::SourceFile(_) => break,
_ => (),
}
}
target_node = ancestor;
}
target_node
}
/// Finds where to put the new enum definition, at the nearest module or at top-level.
fn node_to_insert_before(target_node: SyntaxNode) -> SyntaxNode {
target_node.ancestors().find(|it| matches!(it.kind(), SyntaxKind::Module | SyntaxKind::SourceFile).unwrap_or(target_node)
}

Copy link
Contributor Author

@rmehri01 rmehri01 Sep 26, 2023

Choose a reason for hiding this comment

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

Sorry, maybe the doc comment isn't too clear but I think the simplified version finds the module or source file itself, while I was aiming to find the furthest ancestor Item that is contained within a module or just at top-level so that I can insert before it. I think something more along the lines of this:

/// Finds where to put the new enum definition.
/// Tries to find the [ast::Item] node at the nearest module or at top-level, otherwise just
/// returns the input node.
fn node_to_insert_before(mut target_node: SyntaxNode) -> SyntaxNode {
    let mut ancestors = target_node.ancestors();

    while let Some(ancestor) = ancestors.next() {
        match_ast! {
            match ancestor {
                ast::Module(_) => break,
                ast::SourceFile(_) => break,
                ast::Item(_) => target_node = ancestor,
                _ => (),
            }
        }
    }

    target_node
}

Copy link
Member

Choose a reason for hiding this comment

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

Oh sorry that wes me spacing out, in that case we can do

target_node.ancestors().take_while(|it| !matches!(it.kind(), SyntaxKind::Module | SyntaxKind::SourceFile).last().unwrap_or(target_node)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No problem! I think this works for the source file case but in the module case we want the second to last node since the last is an ItemList and inserting it before the ItemList would be between the module name and the left brace.

Copy link
Member

Choose a reason for hiding this comment

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

Right, then my snippet only needs a slight adjustment by adding a filter

target_node.ancestors().take_while(|it| !matches!(it.kind(), SyntaxKind::Module | SyntaxKind::SourceFile).filter(|it| ast::Item::can_cast(it.kind())).last().unwrap_or(target_node)

Though I feel like there has to be some assist that does something similar here, I'd be surprised if not but I can't think of any of the top oh my head right now.

Copy link
Contributor Author

@rmehri01 rmehri01 Sep 26, 2023

Choose a reason for hiding this comment

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

Ah I see okay, that works and is much cleaner, thank you!

I thought that would be the case as well, a few that I looked at were extract_function, which has node_to_insert_after and is what I based this one on but seems to be a bit more complex and generate_function which has next_space_for_fn_in_module and similar functions but is based on text ranges and also seem more complex. Do you think it would be better to try to reuse these?

Copy link
Member

Choose a reason for hiding this comment

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

nah this is simple enough so it should be fine

@Veykril Veykril added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 26, 2023
@Veykril
Copy link
Member

Veykril commented Sep 29, 2023

@bors r+

@bors
Copy link
Collaborator

bors commented Sep 29, 2023

📌 Commit 1b3e5b2 has been approved by Veykril

It is now in the queue for this repository.

@bors
Copy link
Collaborator

bors commented Sep 29, 2023

⌛ Testing commit 1b3e5b2 with merge 87e2c31...

@bors
Copy link
Collaborator

bors commented Sep 29, 2023

☀️ Test successful - checks-actions
Approved by: Veykril
Pushing 87e2c31 to master...

@bors bors merged commit 87e2c31 into rust-lang:master Sep 29, 2023
10 checks passed
@rmehri01 rmehri01 deleted the bool_to_enum_top_level branch October 2, 2023 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants