Skip to content

fix: shadow type by module #19461

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 5 commits into from
Apr 10, 2025
Merged

Conversation

Hmikihiro
Copy link
Contributor

fix: #19107

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 27, 2025
db: &'a dyn DefDatabase,
path: &'a Path,
) -> impl Iterator<Item = (ModuleOrTypeNs, Option<usize>, Option<ImportOrExternCrate>)> + 'a
{
Copy link
Contributor

Choose a reason for hiding this comment

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

Given edition 2024 new capture rules there shouldn't be a need to define the lifetime 'a.

&'a self,
db: &'a dyn DefDatabase,
path: &'a Path,
) -> Box<
Copy link
Contributor

Choose a reason for hiding this comment

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

Box<dyn Iterator> optimizes very bad and also incurs an allocation, and resolver is very hot.

In general I don't think an iterator is the correct thing to return here. Resolution doesn't have "multiple options". It has a single option. If it resolves the a module, it resolves to it and to nothing else. So this should return a single value.

if let Some(res) = m.resolve_path_in_module_or_type_ns(db, path) {
let res = match res.0 {
ModuleOrTypeNs::TypeNs(_) => res,
ModuleOrTypeNs::ModuleNs(_) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the feedback. I agree that it should return a single value.

As an alternative, I tried checking for a conflict between a module and a builtin type in the scope directly, instead of using Box<dyn Iterator> and evaluating lazily.

@@ -107,6 +107,12 @@ pub enum TypeNs {
// ModuleId(ModuleId)
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ModuleOrTypeNs {
Copy link
Member

Choose a reason for hiding this comment

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

Modules are part of the type namespace, they're not their own namespace. They've been commented out in the TypeNs enum only because "the resolver is used when all module paths are fully resolved.". It may make more sense to just add the Module case back to TypeNs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you. I agree that there's no real need to split modules out from TypeNs.
This enum is only used to check BuiltinType with module. I've included modules in TypeNs instead.

Comment on lines +1652 to 1654
| TypeNs::ModuleId(_) => {
// FIXME diagnostic
(self.err_ty(), None)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

mod Foo {}
fn main() {
    Foo {}
 // ^^^ not a struct, variant or union type
}

Modules do not have variants, so this results in an error.

@@ -285,7 +285,9 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args),
TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args),
// FIXME: report error
TypeNs::EnumVariantId(_) => return (TyKind::Error.intern(Interner), None),
TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => {
return (TyKind::Error.intern(Interner), None);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

pub mod M {
    pub mod Module {}
}

fn sample_function<Module>(x: Module) {
    let x: Module = x;
    {
        use M::Module;
        let x: Module = x;
            // ^^^^^^ not a type
    }
}

fn main() {}

This kind of pattern is similar to the above code.
Here, Module refers to a module, not a type, so using it as a type results in an error.
That's why we return TyKind::Error for TypeNs::ModuleId.

Hmikihiro and others added 5 commits April 10, 2025 16:29
Signed-off-by: Hayashi Mikihiro <[email protected]>
Signed-off-by: Hayashi Mikihiro <[email protected]>
Signed-off-by: Hayashi Mikihiro <[email protected]>
Copy link
Member

@Veykril Veykril left a comment

Choose a reason for hiding this comment

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

Thanks!

@Veykril Veykril enabled auto-merge April 10, 2025 11:59
@Veykril Veykril added this pull request to the merge queue Apr 10, 2025
Merged via the queue into rust-lang:master with commit f880acd Apr 10, 2025
14 checks passed
@Hmikihiro Hmikihiro deleted the shadow_by_module branch April 10, 2025 12:58
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.

Module should be resolved correctly when conflicting with struct in use imports
5 participants