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

(Modules) Tracking issue for Picking a Module Path System variant #53130

Closed
5 of 8 tasks
Centril opened this issue Aug 6, 2018 · 104 comments · Fixed by #56759
Closed
5 of 8 tasks

(Modules) Tracking issue for Picking a Module Path System variant #53130

Centril opened this issue Aug 6, 2018 · 104 comments · Fixed by #56759
Labels
B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Milestone

Comments

@Centril
Copy link
Contributor

Centril commented Aug 6, 2018

This is a sub-tracking issue for the RFC "Clarify and streamline paths and visibility" (rust-lang/rfcs#2126)
as well as the internals post Relative Paths in Rust 2018.

The issue deals with revamping paths and making a decision about whether we should pick:

Unresolved questions:

  • Which variant do we pick?
@Centril Centril added B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. T-lang Relevant to the language team, which will review and decide on the PR/issue. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC labels Aug 6, 2018
@Centril Centril added this to the Rust 2018 RC milestone Aug 6, 2018
@Centril Centril changed the title (Modules) Tracking issue for Picking one of the two proposed Module Path Systems (Modules) Tracking issue for Picking one of the two Module Path Systems Aug 6, 2018
@Centril Centril changed the title (Modules) Tracking issue for Picking one of the two Module Path Systems (Modules) Tracking issue for Picking a Module Path System variant Aug 6, 2018
@sanmai-NL
Copy link

Could you give more details about what has been implemented concretely, and what renaming operations are needed exactly? It comes down to: how can I start testing anything right now?

A priori, I vote for anchored_use_paths, for being the most explicit/teachable. One suggestion: I find the crate keyword a bit odd since it does not seem related to visibility at all. I suppose this has been debated before but it would be better if it becomes pubcrate or whatever.

@Centril
Copy link
Contributor Author

Centril commented Aug 8, 2018

cc @eddyb re. @sanmai-NL's question.

bors added a commit that referenced this issue Aug 14, 2018
#[feature(uniform_paths)]: allow `use x::y;` to resolve through `self::x`, not just `::x`.

_Branch originally by @cramertj, based on @petrochenkov's [description on the internals forum](https://internals.rust-lang.org/t/relative-paths-in-rust-2018/7883/30?u=petrochenkov)._
_(note, however, that the approach has significantly changed since)_

Implements `#[feature(uniform_paths)]` from #53130, by treating unqualified `use` paths as maybe-relative. That is, `use x::y;`, where `x` is a plain identifier (not a keyword), is no longer the same as `use ::x::y;`, and before picking an external crate named `x`, it first looks for an item named `x` in the same module (i.e. `self::x`) and prefers that local item instead.

Such a "maybe-relative" `x` can only resolve to an external crate if it's listed in "`extern_prelude`" (i.e. `core` / `std` and all the crates passed to `--extern`; the latter includes Cargo dependencies) - this is the same condition as being able to refer to the external crate from an unqualified, non-`use` path.
All other crates must be explicitly imported with an absolute path, e.g. `use ::x::y;`

To detect an ambiguity between the external crate and the local item with the same name, a "canary" import (e.g. `use self::x as _;`), tagged with the `is_uniform_paths_canary` flag, is injected. As the initial implementation is not sophisticated enough to handle all possible ways in which `self::x` could appear (e.g. from macro expansion), this also guards against accidentally picking the external crate, when it might actually get "shadowed" later.
Also, more canaries are injected for each block scope around the `use`, as `self::x` cannot resolve to any items named `x` in those scopes, but non-`use` paths can, and that could be confusing or even backwards-incompatible.

Errors are emitted only if the main "canary" import succeeds while an external crate exists (or if any of the block-scoped ones succeed at all), and ambiguities have custom error reporting, e.g.:
```rust
#![feature(uniform_paths)]
pub mod foo {
    use std::io;
    pub mod std { pub mod io {} }
}
```
```rust
error: import from `std` is ambiguous
 --> test.rs:3:9
  |
3 |     use std::io;
  |         ^^^ could refer to external crate `::std`
4 |     pub mod std { pub mod io {} }
  |     ----------------------------- could also refer to `self::std`
  |
  = help: write `::std` or `self::std` explicitly instead
  = note: relative `use` paths enabled by `#![feature(uniform_paths)]`
```
Another example, this time with a block-scoped item shadowing a module-scoped one:
```rust
#![feature(uniform_paths)]
enum Foo { A, B }
fn main() {
    enum Foo {}
    use Foo::*;
}
```
```rust
error: import from `Foo` is ambiguous
 --> test.rs:5:9
  |
4 |     enum Foo {}
  |     ----------- shadowed by block-scoped `Foo`
5 |     use Foo::*;
  |         ^^^
  |
  = help: write `::Foo` or `self::Foo` explicitly instead
  = note: relative `use` paths enabled by `#![feature(uniform_paths)]`
```

Additionally, this PR, because replacing "the `finalize_import` hack" was a blocker:
* fixes #52140
* fixes #52141
* fixes #52705

cc @aturon @joshtriplett
@eddyb
Copy link
Member

eddyb commented Aug 14, 2018

@sanmai-NL Now that #52923 has landed, the next nightly should have both options available:

  • anchored_use_paths has been the Rust 2018 default for some(?) time now
  • uniform_paths you get by being on Rust 2018 and adding #![feature(uniform_paths)]

I'd suggesting trying the latter after upgrading to the edition, and report back if the ambiguity errors end up being too excessive.

AFAIK, the upgrade involves taking a Rust 2015 crate, adding #![feature(rust_2018_preview)] without changing the edition, running rustfix to apply the suggestions it gives for making same-crate paths explicit (i.e. prepending all paths that don't start with a crate name, with crate::), and only then do you switch the edition (usually in Cargo.toml) to Rust 2018.
You can remove #![feature(rust_2018_preview)] afterwards, since it's redundant.

@joshtriplett
Copy link
Member

@archer884
Copy link

archer884 commented Aug 16, 2018

I absolutely despise the "anchored paths variant," and I am very excited to see that we're considering an alternative. Any alternative, honestly. >.>

...That said, uniform paths look great. :) I'd much prefer to let people use absolute paths (the anchored version) if they like, but not force people to do it.

(No idea where the appropriate place to provide feedback for this would be, so I just left it here. Sorry.)

@kohensu
Copy link

kohensu commented Aug 16, 2018

Using uniform_paths, there is an error I find confusing.
Considering:

#![feature(rust_2018_preview)]
#![feature(uniform_paths)]
use hex;
fn main() {
    println!("hex {}", hex::encode("01"));
}

I get this error:

error: import from `hex` is ambiguous
 --> src/main.rs:3:5
  |
3 | use hex;
  |     ^^^
  |     |
  |     could refer to external crate `::hex`
  |     could also refer to `self::hex`
  |
  = help: write `::hex` or `self::hex` explicitly instead
  = note: relative `use` paths enabled by `#![feature(uniform_paths)]`

whereas self::hex doesn't exist in the module.

Because the code is working without use hex maybe suggesting to remove it will be more clear.

@Nemo157
Copy link
Member

Nemo157 commented Aug 16, 2018

@kohensu see #53408, I think the plan is to either special case allow that or improve the error message to just suggest removing it.

@kohensu
Copy link

kohensu commented Aug 16, 2018

@Nemo157
Sorry, I did not see that.
Thanks for the reference to the issue.

@sanmai-NL
Copy link

@archer884: What’s more interesting is your motivation to feel that way?

@Xymist
Copy link

Xymist commented Aug 16, 2018

As a user (who perhaps hasn't been paying as much attention as I should) I think the uniform_paths option feels strictly better. Special case sugar for when there's no possible ambiguity would be nice, but by no means necessary; optimising for clarity is definitely a greater win.

@eddyb
Copy link
Member

eddyb commented Aug 16, 2018

Special case sugar for when there's no possible ambiguity would be nice

Not sure what you mean. Does #53427 (by treating each namespace independently) solve that for you?

@archer884
Copy link

archer884 commented Aug 16, 2018 via email

@sanmai-NL
Copy link

sanmai-NL commented Aug 17, 2018

That’s an argument from authority, and a very aspecific one. Conciseness is a criterion independent from explicitness and also from simplicity.

@archer884

This comment has been minimized.

@sanmai-NL

This comment has been minimized.

@archer884

This comment has been minimized.

@liigo

This comment has been minimized.

@sanmai-NL

This comment has been minimized.

@rfcbot
Copy link

rfcbot commented Sep 16, 2018

The final comment period, with a disposition to merge, as per the review above, is now complete.

@aturon
Copy link
Member

aturon commented Nov 2, 2018

See also: #53130 proposing to stabilize on uniform paths.

@Centril
Copy link
Contributor Author

Centril commented Nov 2, 2018

@aturon haha; came here to link to that issue as well =P

You linked to the current issue tho ;)
Here's the right issue: #55618.

bors added a commit that referenced this issue Nov 14, 2018
[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
bors added a commit that referenced this issue Nov 18, 2018
[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
@petrochenkov
Copy link
Contributor

Some follow-up issues:

bors added a commit that referenced this issue Jan 12, 2019
Stabilize `uniform_paths`

Address all the things described in #56417.

Assign visibilities to `macro_rules` items - `pub` to `macro_export`-ed macros and `pub(crate)` to non-exported macros, these visibilities determine how far these macros can be reexported with `use`.

Prohibit use of reexported inert attributes and "tool modules", after renaming (e.g. `use inline as imported_inline`) their respective tools and even compiler passes won't be able to recognize and properly check them.

Also turn use of uniform paths in 2015 macros into an error, I'd prefer to neither remove nor stabilize them right away because I still want to make some experiments in this area (uniform path fallback was added to 2015 macros used on 2018 edition in #56053 (comment)).

UPDATE: The last commit also stabilizes the feature `uniform_paths`.

Closes #53130
Closes #55618
Closes #56326
Closes #56398
Closes #56417
Closes #56821
Closes #57252
Closes #57422
bors added a commit that referenced this issue Jan 12, 2019
Stabilize `uniform_paths`

Address all the things described in #56417.

Assign visibilities to `macro_rules` items - `pub` to `macro_export`-ed macros and `pub(crate)` to non-exported macros, these visibilities determine how far these macros can be reexported with `use`.

Prohibit use of reexported inert attributes and "tool modules", after renaming (e.g. `use inline as imported_inline`) their respective tools and even compiler passes won't be able to recognize and properly check them.

Also turn use of uniform paths in 2015 macros into an error, I'd prefer to neither remove nor stabilize them right away because I still want to make some experiments in this area (uniform path fallback was added to 2015 macros used on 2018 edition in #56053 (comment)).

UPDATE: The last commit also stabilizes the feature `uniform_paths`.

Closes #53130
Closes #55618
Closes #56326
Closes #56398
Closes #56417
Closes #56821
Closes #57252
Closes #57422
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.