-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Improve the remaining rough corners of the module system #1289
Comments
As discussed in #1285, a revision of these features would greatly ease the pain of writing wrapper libraries that wish to glob-import the items being wrapped, but also publicly re-export a subset of them. The ability to do: use foo::*;
pub use foo::Bar; would be very much appreciated. 👍 |
👍 |
Several of these suggestions are addressed by #1560 |
Indeed, a lot has been done in the last year :) |
Just curious, what is the current status of these efforts? |
"Expose private imports as regular importable items to submodules" is done, as is much of "Address recursive mutual import issues". Not sure about the others off the top of my head. |
[beta] resolve: Implement uniform paths 2.0 With this PR paths in imports on 2018 edition are resolved as relative in the scope in which they are written, similarly to any other paths. The previous implementation worked differently - it tried to resolve the import in the current module (`self::import`) and in the "crate universe" (`::import`), and then merge these two resolutions if possible. The difference is that the new scheme can refer to strictly larger set of names in scope - names from unnamed blocks, names from all kinds of preludes, including macros imported with `#[macro_use] extern crate`, built-in types/macros, macros introduced with `macro_rules`. This means strictly more potential ambiguities and therefore ambiguity errors, since we keep the rule that any two different candidate names in scope conflict with each other during import resolution. So this is a breaking change for 2018 edition, but it should be relatively minor. All paths that don't start with an extern crate are also gated with the `uniform_paths` feature, paths that refer to extern crates are not gated (so we effectively get something like "future-proofed anchored paths" on stable). Another difference is treatment of paths in visibilities (`pub(in path)`). Few people remember about paths in visibilities, so before this PR they still used the old 2015 rules even on 2018 edition. Namely, paths in visibilities were crate-relative, analogous to 2015 edition imports. This PR resolves paths in visibilities as uniform as well, or rather future proofs them in this direction. Paths in visibilities are restricted to parent modules, so relative paths almost never make sense there, and `pub(in a)` needs to be rewritten as `pub(in crate::a)` in the uniform scheme, de-facto cementing the discouraged status of non-`pub(crate)` and non-`pub(super)` fine-grained visibilities. This is clearly a breaking change for 2018 edition as well, but also a minor one. The in-scope resolution strategy for import paths mirrors what is currently done for macro paths on stable (on both editions), so it will continue working even if the "ambiguity always means error" restriction is relaxed in the future. This PR also significantly improves diagnostics for all kinds of resolution ambiguities, from the newly introduced import ones to pretty old "glob vs glob" conflicts. (That's probably what I've spent most of the time on.) Why beta: - This is a breaking change on 2018 edition. - This is a large PR, it's less risky to forward-port it to nightly, than back-port to beta. cc #55618 cc #53130 cc rust-lang/rfcs#1289 Closes #18084 Closes #54525 Fixes #54390 Fixes #55668 r? @ghost
[beta] resolve: Implement uniform paths 2.0 With this PR paths in imports on 2018 edition are resolved as relative in the scope in which they are written, similarly to any other paths. The previous implementation worked differently - it tried to resolve the import in the current module (`self::import`) and in the "crate universe" (`::import`), and then merge these two resolutions if possible. The difference is that the new scheme can refer to strictly larger set of names in scope - names from unnamed blocks, names from all kinds of preludes, including macros imported with `#[macro_use] extern crate`, built-in types/macros, macros introduced with `macro_rules`. This means strictly more potential ambiguities and therefore ambiguity errors, since we keep the rule that any two different candidate names in scope conflict with each other during import resolution. So this is a breaking change for 2018 edition, but it should be relatively minor. All paths that don't start with an extern crate are also gated with the `uniform_paths` feature, paths that refer to extern crates are not gated (so we effectively get something like "future-proofed anchored paths" on stable). Another difference is treatment of paths in visibilities (`pub(in path)`). Few people remember about paths in visibilities, so before this PR they still used the old 2015 rules even on 2018 edition. Namely, paths in visibilities were crate-relative, analogous to 2015 edition imports. This PR resolves paths in visibilities as uniform as well, or rather future proofs them in this direction. Paths in visibilities are restricted to parent modules, so relative paths almost never make sense there, and `pub(in a)` needs to be rewritten as `pub(in crate::a)` in the uniform scheme, de-facto cementing the discouraged status of non-`pub(crate)` and non-`pub(super)` fine-grained visibilities. This is clearly a breaking change for 2018 edition as well, but also a minor one. The in-scope resolution strategy for import paths mirrors what is currently done for macro paths on stable (on both editions), so it will continue working even if the "ambiguity always means error" restriction is relaxed in the future. This PR also significantly improves diagnostics for all kinds of resolution ambiguities, from the newly introduced import ones to pretty old "glob vs glob" conflicts. (That's probably what I've spent most of the time on.) Why beta: - This is a breaking change on 2018 edition. - This is a large PR, it's less risky to forward-port it to nightly, than back-port to beta. cc #55618 cc #53130 cc rust-lang/rfcs#1289 Closes #18084 Closes #54525 Fixes #54390 Fixes #55668 r? @ghost
Motivation
The module system (specifically name resolution) still has a few rough edges, footguns and corner cases that can be removed in a way that doesn't change its core semantics. Similarly, error messages and doc generation need to be smarter about the module system in some areas.
This issue proposes all changes that the author regards as improvements, and they would build on prior work like #116 and #385.
This is not a RFC due to its size, and lack of details. Rather, the idea is to paint the big picture, and have a central place to discuss wether this is a direction the module system should be taken or not.
Proposals
Change wildcard import semantics to be shadow-able by other items and non-wildcard imports.
use
items.publicly visible through more more than one of them
if the names refer to different logical items.
Recommend to use an explicit import to choose between them in the error message.
downstream users using wildcard imports can always clarify or guard in advance
with an explicit import.
Allow
pub use
re-imports/exports of already privately imported symbols #1285which zero names are resolved.
Expose private imports as regular importable items to submodules
breaking no other code on the inside of a module.
use super::*;
in a test submodule to import everythingneeded to test the parent.
use self::submodule::*;
to flatten a module hierarchy.mod my_prelude { pub use other_prelude::*; pub use my_items::*; }
to easily merge modules together.
since any names becoming visible with this change would not conflict with existing imports:
existing modules will not fail to compile since imports are currently strictly
forbidden from shadowing other items.
Make imports in non-module scopes see items defined in non-module scopes
This is about making this print
"inner a"
twice:This would address issues like Ability to refer to a path relative to the current scope in use declarations #959 and extern crate foo with use self::foo doesn't work inside a function rust#27626.
This would remove the corner case of imports not composing well
with items in a nested scope.
This is a breaking change.
However, the breakage scenario is obscure and unidiomatic
enough that a crater run
and community outreach might likely discover no regressions.
Address recursive mutual import issues.
language semantics in the past.
this is algorithmically feasible to implement in rustc, but
as far as I abstractly know about the problem, it should be doable.
(Say with a fixpoint algorithm gathering the set of possible imports from wildcards, kept finite by normalizing the paths to the canonical path of a item)
should become a non-error with the new wildcard import semantics.
This should work, and doesn't today:
nice error message. This should fail to compile
(and already does today, though not with a nice message):
Error messages and rustdoc output should treat imports and paths of imported
items smarter.
in a non-import item:
extern crate
statements count as a reexport here.item private from the location of the start of the chain.
In this case, the last visible reexport in the chain is defined
as "visibly-terminating":
it is
<name_of_the_crate>::<canonical_path_in_the_crate>
. Example:<resolved-name-in-current-contex> defined at <visibly-terminating-path>
.For example:
extern crate <name_of_the_crate>::<visibly-terminating-path-in-that-crate>
similarly to before. Maybe also add a hash or version number to clear up
issues like in Two different versions of a crate interacting leads to unhelpful error messages rust#22750.
current crate in any way, and that he would have to add a
extern crate
item or resolve a version mismatch to change that.
use
statements that are visibly-terminating in thereexport chain of any other
use
item in that crate as its terminating item.docs.
currently generates documentation for that one as well (to make cross-crate links),
also append a "defined at "
note that links there.
use
statements uniformly, for example by showing them simplyas a "reexport" linking to the visibly-terminating item.
referring to them in the current crate like today.
defined in another crate that is not also reexported,
like the return type of a
pub fn foo() -> Rc<u32>
in a cratenot reexporting
std
oralloc
.Precedence
comment to look at what Scala did in this whole space, and the semantics
described at http://www.scala-lang.org/files/archive/spec/2.11/02-identifiers-names-and-scopes.html,
where applicable, seem to mostly match the semantics of Rusts name resolution if the
tweaks described above get applied.
The text was updated successfully, but these errors were encountered: