-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Cannot refer to item inside function from module inside function #79260
Comments
(If the lang team agrees that this code should compile, I'm willing to attempt a patch to fix.) |
Note that fixing this would break this code: fn main() {
mod foo {
use super::*;
fn foobar() {
bar();
}
}
}
fn bar() {} |
I'm not convinced it would break that code; |
I can find another example of this which is easy to reproduce and seems like a much more likely case to trigger! Write a doctest which declares a module inside it: /// ```rust
/// struct Foo;
///
/// mod foobar {
/// use super::*;
///
/// fn bar() -> Foo { Foo }
/// }
///
/// ```
fn foo() {} This doctest will fail to compile:
I would guess that the doctest framework wraps the doctest code inside a function, so we see exactly the same issue as in my original report. |
Ah, but I think this variation of @jonas-schievink 's example will break: fn main() {
mod foo {
use super::*;
fn foobar() {
bar();
}
}
fn bar() {
println!("inner bar");
}
}
fn bar() {
println!("outer bar");
} At the moment it always prints (We could perhaps make it backwards compatble by letting items outside the function take precedence, and then switch the order to prefer items inside the function on an edition change.) |
I am against changing the meaning of I also wouldn't call this a bug. Everything is working as it originally is intended to. IMO, if you need a module, just like if you need an impl, it should not be defined in a function. |
We probably need some way to refer to block-that-are-parent-of-modules, but Besides being a breaking change, path resolving to an unnamed block is some new possibility that will cause a number of subsequent issues. use super as foo; // referes to a block
let bar = foo; |
My preferred solution to this issue is probably UPD: Example. struct S;
#[transparent]
mod m {
fn f() {
let s = S; // OK
}
} |
I wrote a PR to experiment with what I proposed above (#79309) - I've added an alternatives section with |
I would like to see this result: 1. For Rust before 2024 edition fn main() {
mod foo {
use super::*;
fn foobar() {
bar(); // <- error[E0425]: cannot find function `bar` in this scope
}
}
fn bar() {
println!("inner bar");
}
}
2. For Rust before 2024 edition fn main() {
mod foo {
use super::*;
fn foobar() {
bar();
}
}
fn bar() {
println!("inner bar");
}
}
fn bar() {
println!("outer bar");
}
3. For Rust before 2024 edition fn main() {
#[enable_fn_scope_from_inner_module] // <- !!!
mod foo {
use super::*;
fn foobar() {
bar();
}
}
fn bar() {
println!("inner bar");
}
}
fn bar() {
println!("outer bar");
}
4. For Rust before 2024 edition #![enable_fn_scope_from_inner_module] // <- !!!
fn main() {
mod foo {
use super::*;
fn foobar() {
bar();
}
}
fn bar() {
println!("inner bar");
}
}
fn bar() {
println!("outer bar");
}
5. For Rust 2024 edition fn main() {
mod foo {
use super::*;
fn foobar() {
bar();
}
}
fn bar() { // <- obscures the outer bar
println!("inner bar");
}
}
fn bar() {
println!("outer bar");
}
|
Alternatively, for this non-working example: we can use this: However, there were difficulties with rust-analyzer: rust-lang/rust-analyzer#15805 |
Here is a real use case for this. I'd like to generate a child module in a proc macro where I'd place the definition of the builder stuct (for privacy of its fields). The builder's fields should reference types from the surrounding scope. fn example() {
struct Password(String);
// Suppose a `#[builder]` proc macro was placed on this struct
struct User {
password: Password,
}
// This module is generated by the proc-macro
mod user_builder {
use super::*;
pub(super) struct UserBuilder {
password: Option<Password>,
}
}
} I made an article about this problem here: https://elastio.github.io/bon/blog/the-weird-of-function-local-types-in-rust |
Another, similar use case for this is with a new feature in our HTTP server Dropshot called API traits. Applying this proc macro on the trait causes a bunch of support functions (and soon at least one macro) to be generated. The options are:
The proposal to have a way to mark a module as transparent in this comment above would solve this issue, and I think it would be worth pursuing. |
@sunshowers I've since discovered another option to workaround this problem, if your goal is to make the generated symbols private. You can just randomize the names of your generated symbols using some simple randomness source like std's This way the users won't be able to use the generated names, and even if they do, they won't be able to compile/re-compile the code if they do that. I also recommend marking these symbols with |
Ah, in my case I'd like the generated symbols to be public. |
I tried this code (https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8c1861ee7e07799c5897f37f0aa2f849):
This fails to compile:
rustc --version --verbose
:Also reproduces on current nightly (as of 2020-11-21).
I suspect that what's going on is that
use super::*
doesn't actually resolve to the scope insidefn main
, but instead the surrounding scopefn main
is itself in.I tried to search around other issues to find whether this is expected.
This is a super weird special case. It seems plausible (at least to me) that
use super::*
from a module inside a function should bring other items local to that function into scope.The text was updated successfully, but these errors were encountered: