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

group_imports does not differentiate between a local import and an external crate #4709

Open
jhpratt opened this issue Feb 20, 2021 · 9 comments

Comments

@jhpratt
Copy link
Member

jhpratt commented Feb 20, 2021

Describe the bug

rustfmt does not differentiate between local imports not prefixed by self:: and external crates. The behavior is as expected when prefixed by self::.

To Reproduce

Using group_imports = "StdExternalCrate" in rustfmt.toml, the following code is considered formatted.

mod foo {
    struct Foo;
}

use foo::Foo;
use rand::random;

Expected behavior

rustfmt recognizes that foo is a local module, not an external crate.

mod foo {
    struct Foo;
}

use rand::random;

use foo::Foo;

Meta

  • rustfmt version: rustfmt 1.4.30-stable (8c6769d 2021-01-18)
  • From where did you install rustfmt?: rustup
  • How do you run rustfmt: cargo fmt
@jhpratt jhpratt added the bug Panic, non-idempotency, invalid code, etc. label Feb 20, 2021
@jhpratt
Copy link
Member Author

jhpratt commented Feb 20, 2021

@rustbot modify labels to +a-imports +only-with-option

@rustbot
Copy link
Collaborator

rustbot commented Feb 20, 2021

Error: This repository is not enabled to use triagebot.
Add a triagebot.toml in the root of the master branch to enable it.

Please let @rust-lang/release know if you're having trouble with this bot.

@jhpratt
Copy link
Member Author

jhpratt commented Feb 20, 2021

Also, proc_macro should probably be grouped with std, alloc, and core.

@MattX
Copy link
Contributor

MattX commented Feb 20, 2021

rustfmt does not differentiate between local imports not prefixed by self:: and external crates. The behavior is as expected when prefixed by self::.

Hm, when we added this feature I thought there was no good way to differentiate between external and local imports if the latter were not explicitly prefixed, but taking a look at the code again, we might be able to use the (recently added?) file_mod_map field in the context. I'll experiment with this today.

Also, proc_macro should probably be grouped with std, alloc, and core.

Good point. Is there a list of standard crates somewhere? It would be nice to make sure we're not missing any others.

@calebcartwright calebcartwright removed the bug Panic, non-idempotency, invalid code, etc. label Feb 24, 2021
@calebcartwright
Copy link
Member

calebcartwright commented Feb 24, 2021

Removing the bug label, as there's definitely not one here though perhaps some minor updates to the documentation for the variant could be helpful to explain the limitations.

As discussed in various other issues/pulls, including the recent #4693, I'm still highly skeptical that it will be possible to do more. Would be thrilled to be proven wrong as I know folks would appreciate these types of enhancements from rustfmt, but to reiterate a few points:

  • rustfmt runs have to be idempotent, including when running rustfmt directly against a single file (e.g. format-on-save in editor scenarios) as well as when formatting larger/entire portions of a project (e.g. cargo fmt)
  • different folks have different interpretations of what "local" imports mean. even zooming in on the in-same-file modules, are all modules in the file considered local? what about nested in-file modules?
  • anything that's reliant on the presence of entries in the file_mod_map (which has been around for ages and is a crucial part of the formatting flow) will almost certainly fail to meet that idempotence requirement, so think about the impact of that on out-of-file/project "local" modules and the potential for confusion even if in-file mods can be grouped separately from std/crate and everything else (including other things users consider "local") in the external group

@jhpratt
Copy link
Member Author

jhpratt commented Feb 24, 2021

Of course the definition of "local" is up for debate, but under the definition currently used, wouldn't it be possible to just see if there is a mod foo in the file, treating foo::bar as local? It wouldn't catch all cases (you could do use crate::foo; and use foo::bar;, for example), but it would cover a large portion of what I consider good style.

@jplatte
Copy link

jplatte commented Feb 25, 2021

Also found that we had some files in tests/ in https://github.com/ruma/ruma where the imports from the crate being tested were grouped like crate-local imports in the StdExternCrate grouping. I wonder how others feel about that.

self-hosted-bors bot pushed a commit to xaynetwork/xayn_discovery_engine that referenced this issue Nov 15, 2022
This enables the `group_imports` option. With this rustfmt automatically groups the imports in `std`, `external`, and `crate.
This is almost what we already wanted but we lose control of some things:
* it is not able to differentiate between workspace and external so all our crates will go in that section,
* it does not understand local import: 
```rust
mod foo {
    struct Foo;
}

use foo::Foo;
use rand::random;
```
instead of having a separate group for `foo`. 
* It does not respect groups that we create manually
```rust
use tokio;

use itertools;
```
the imports will be merged.

Looking at the changeset we are not too bad at maintaining this style. Most of the changes are the position of `crate` wr.t. to `self` or `super`, fusing groups, and moving our workspace crates to the external one.
But this will be our only option to enforce this style with a tool.

https://rust-lang.github.io/rustfmt/?version=v1.5.1&search=#group_imports
rust-lang/rustfmt#4709
rust-lang/rustfmt#4693
@RalfJung
Copy link
Member

RalfJung commented May 7, 2024

Removing the bug label, as there's definitely not one here

In that case the docs should be updated. The docs say "external crates" go into the middle group, and in the example in the OP, foo is definitely not an external crate. So rustfmt does not behave as documented, which means there must be a bug somewhere.

It seems like the middle group are "external crates as well as local modules that are not prefixed with self".

@RalfJung
Copy link
Member

I have drafted an implementation of a lint that could be used to enforce all local imports to be recognizable by rustfmt: rust-lang/rust#125645.

bors added a commit to rust-lang-ci/rust that referenced this issue Sep 23, 2024
…ethercote

add unqualified_local_imports lint

This lint helps deal with rust-lang/rustfmt#4709 by having the compiler detect imports of local items that are not syntactically distinguishable from imports from other cates. Making them  syntactically distinguishable ensures rustfmt can consistently apply the desired import grouping.
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Sep 25, 2024
add unqualified_local_imports lint

This lint helps deal with rust-lang/rustfmt#4709 by having the compiler detect imports of local items that are not syntactically distinguishable from imports from other cates. Making them  syntactically distinguishable ensures rustfmt can consistently apply the desired import grouping.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants