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: if item exsits on module, resolve as module instead of type #19088

Merged

Conversation

Hmikihiro
Copy link
Contributor

@Hmikihiro Hmikihiro commented Feb 4, 2025

fix : #18941, #19107

This PR resolves modules if items exist in the module and treats them as modules.

duplicate-str-module.mov

If a type import overwrites a module, this PR ensures it is resolved as a type

duplicate_with_module_struct.mov

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. has-merge-commits S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Feb 4, 2025
@rustbot

This comment has been minimized.

@Hmikihiro Hmikihiro force-pushed the all_remove_duplicate_module_adt branch from cf71962 to 9568a66 Compare February 4, 2025 02:19
@rustbot rustbot removed has-merge-commits S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Feb 4, 2025
Some(it)
if matches!(
it,
PathResolution::Def(ModuleDef::Adt(_) | ModuleDef::BuiltinType(_))
Copy link
Contributor

Choose a reason for hiding this comment

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

It cannot be an ADT (there will be an error - https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=66662b72d42109fcca7af9a68de608d7), only a primitive type can be shadowed with the same name and different resolutions

Copy link
Contributor

Choose a reason for hiding this comment

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

Now I see that we don't resolve them correctly even in the case of a module shadowing a struct (I haven't checked why), but this is a different issue - we should always resolve to the module in this case (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=960405ae19d2bdd97128fb38e364ba08).

Copy link
Contributor Author

@Hmikihiro Hmikihiro Feb 6, 2025

Choose a reason for hiding this comment

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

Thank you for comment.
Since defining an Adt and a module in the same scope causes an error, I fixed it by removing the check for whether an item exists in the module when there is a duplicate.

remove_only_std.str.mov

Copy link
Contributor

@ChayimFriedman2 ChayimFriedman2 left a comment

Choose a reason for hiding this comment

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

So I looked into this, and I think this isn't the correct approach. Instead, we need to do the following: resolve_hir_path_qualifier() currently tries the module path last (

.resolve_module_path_in_items(db.upcast(), path.mod_path()?)
). I think we need to try it first. This should solve both issues (but please test that both str the type and str the module are resolved correctly).

As an unrelated note, can you please move the test to the goto definition feature? remove_unused_imports will eventually switch to a proper approach that requests the unused imports from analysis, and it'll be a shame to lose these tests in the way (also I believe most resolve_path() tests are there).

@ChayimFriedman2
Copy link
Contributor

No. Wait. Even what I suggested won't solve the problem, because it will prefer the module even when the struct should be preferred, like the following:

mod foo {
    pub fn bar() {}
}

fn main() {
    struct foo;
    impl foo {
        pub fn bar() {}
    }
    foo::bar();
}

Something else is needed. I'll think about it more (it'd be perfect if we could solve the full path, and during the process record which way we went - but this will be too costly. Also, I've discovered that even our resolution is not perfect, in https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ae501f2aa9e9b987a35d5cfb50146641 we should fail to resolve but we instead fall back to the associate fn foo()).

@rustbot rustbot added has-merge-commits S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Feb 10, 2025
@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@Hmikihiro Hmikihiro force-pushed the all_remove_duplicate_module_adt branch from aed7d07 to f9eebaf Compare February 10, 2025 05:34
@rustbot rustbot removed has-merge-commits S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Feb 10, 2025
@Hmikihiro
Copy link
Contributor Author

I think this function can resolve if those item is only ModuleDef.

.resolve_module_path_in_items(db.upcast(), path.mod_path()?)

When I try it first, this foo can resolved.

mod foo {
    pub fn bar() {}
}

fn main() {
    struct foo;
    impl foo {
        pub fn bar() {}
    }
    foo::bar();
}

but I think resolve_module_path_in_items can't find TypeParam

trait Foo {
    fn fn_foo();
}

mod bar {
    pub mod Bar {
         // ^^^
        pub fn fn_bar() {}
    }
}

fn qux<Bar: Foo>() {
    // ^^^ should find mod bar::Bar
    use bar::Bar;
    Bar::fn_bar();
}

@ChayimFriedman2
Copy link
Contributor

Sorry, but your comment is unclear. Are you claiming that swapping the order is enough?

@Hmikihiro
Copy link
Contributor Author

Sorry for the confusion.
I think swapping the order is not enough but if the path doesn't conflict with type parameter, it is useful.

@ChayimFriedman2
Copy link
Contributor

But you can't know if the path conflicts with a parameter, or a struct, or whatever.

I think what we need to do is this: the problem is that ModuleItemMap filters the resolutions it accepts:

fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportOrGlob>)> {
let (def, import) = per_ns.take_values_import()?;
let res = match def {
ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
ModuleDefId::AdtId(AdtId::EnumId(_) | AdtId::UnionId(_))
| ModuleDefId::TraitId(_)
| ModuleDefId::TraitAliasId(_)
| ModuleDefId::TypeAliasId(_)
| ModuleDefId::BuiltinType(_)
| ModuleDefId::MacroId(_)
| ModuleDefId::ModuleId(_) => return None,
};
Some((res, import))
}
fn to_type_ns(per_ns: PerNs) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
let def = per_ns.take_types_full()?;
let res = match def.def {
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it),
ModuleDefId::FunctionId(_)
| ModuleDefId::ConstId(_)
| ModuleDefId::MacroId(_)
| ModuleDefId::StaticId(_)
| ModuleDefId::ModuleId(_) => return None,
};
Some((res, def.import))
}

This is incorrect. If we resolve to such item, that means we have no resolution, but we instead continue to search in outer scopes. This is also what leads to IDE resolution to fail here, because when resolving only part of the path these resolutions can be correct.

I think we need to remove this filtering, and instead let downstream (analysis, not IDE) err when the resolution is unexpected. IDE should just resolve to them.

Anyway I think we need to separate that from this PR. Make this one focus on builtin shadowing, and if you want make a new PR to solve shadowing of other types.

@Hmikihiro
Copy link
Contributor Author

Thank you for your advice.
I'll focus only on builtin shadowing and remove the other changes from this PR.

At another time, I'll take a look at those functions and try to solve the shadowing of other types.

@Hmikihiro Hmikihiro force-pushed the all_remove_duplicate_module_adt branch from f9eebaf to 1d87b5a Compare February 10, 2025 08:42
Signed-off-by: Hayashi Mikihiro <[email protected]>
@Hmikihiro Hmikihiro force-pushed the all_remove_duplicate_module_adt branch from 1d87b5a to c84cec1 Compare February 10, 2025 08:48
@ChayimFriedman2
Copy link
Contributor

Thanks!

@ChayimFriedman2 ChayimFriedman2 added this pull request to the merge queue Feb 10, 2025
Merged via the queue into rust-lang:master with commit f01f900 Feb 10, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Removing all unused imports removes used import
3 participants