Skip to content

Commit 8ce11ce

Browse files
authored
Unrolled build for #146972
Rollup merge of #146972 - mu001999-contrib:fix/use-dollar-crate, r=petrochenkov Support importing path-segment keyword with renaming *[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust/pull/146972)* #### Reference PR - rust-lang/reference#2010 - rust-lang/reference#2136 #### Description This PR unifies and extends the behavior of importing path-segment keywords (`crate`/`$crate`/`super`/`self`), resolving several long-standing inconsistencies. Previously, Rust only allowed `use crate as name;` without renaming support for other path keywords. This PR enables importing these keywords with explicit renaming. And it also denies importing these keywords without renaming. ##### What's now allowed For **`crate`** and **`$crate`**: - `use crate as name;` - `use crate::{self as name};` - `use $crate as name;` - `use $crate::{self as name};` For **`super`** (including chained `super::super`): - `use super as name;` - `use super::{self as name};` - `use super::super as name;` - `use super::super::{self as name};` For **`self`**: - `use self as name;` - `use self::{self as name};` ##### Removed error codes Two error codes are no longer emitted: - **E0430**: Previously emitted for duplicate `self` imports like `std::fmt::{self, self}`. The existing E0252 ("name defined multiple times") provides sufficient guidance. - **E0431**: Previously emitted for `use {self [as name]};` and `use ::{self [as name]};`. These patterns are now allowed or denied but with new clearer errors. - For `use {self as name};` and `use ::{self as name};` (in edition 2015), they are allowed now and equivalent to `use crate as name`; - For `use {self};` and `use ::{self};` (in edition 2015) without renaming, they are equivalent to `use crate;`, the new clearer error suggests adding an explicit rename. - For `use ::{self [as name]};` after edition 2015, it is equivalent to `use ${extern-prelude} [as name];`, it is denied with new errors. ##### Future We plan to remove error [E0429](https://doc.rust-lang.org/stable/error_codes/E0429.html#error-code-e0429) and support `self` at the end of paths (#146972 (comment)). This language extension and lint for redundant `::self` instead of hard error `E0429` will be landed separately in the future. --- Fixes #29036 Fixes #35612 Fixes #37156 Fixes #146967 Fixes #149811 r? petrochenkov
2 parents 0376d43 + 6609e4b commit 8ce11ce

33 files changed

Lines changed: 2064 additions & 980 deletions

compiler/rustc_error_codes/src/error_codes/E0430.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
#### Note: this error code is no longer emitted by the compiler.
2+
13
The `self` import appears more than once in the list.
24

35
Erroneous code example:
46

5-
```compile_fail,E0430
7+
```ignore (error is no longer emitted)
68
use something::{self, self}; // error: `self` import can only appear once in
79
// the list
810
```

compiler/rustc_error_codes/src/error_codes/E0431.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
#### Note: this error code is no longer emitted by the compiler.
2+
13
An invalid `self` import was made.
24

35
Erroneous code example:
46

5-
```compile_fail,E0431
7+
```ignore (error is no longer emitted)
68
use {self}; // error: `self` import can only appear in an import list with a
79
// non-empty prefix
810
```

compiler/rustc_resolve/src/build_reduced_graph.rs

Lines changed: 80 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -620,97 +620,103 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
620620
let prefix = crate_root.into_iter().chain(prefix_iter).collect::<Vec<_>>();
621621
debug!("build_reduced_graph_for_use_tree: prefix={:?}", prefix);
622622

623-
let empty_for_self = |prefix: &[Segment]| {
624-
prefix.is_empty() || prefix.len() == 1 && prefix[0].ident.name == kw::PathRoot
625-
};
626623
match use_tree.kind {
627624
ast::UseTreeKind::Simple(rename) => {
628625
let mut ident = use_tree.ident();
629626
let mut module_path = prefix;
630627
let mut source = module_path.pop().unwrap();
631-
let mut type_ns_only = false;
632628

633-
if nested {
634-
// Correctly handle `self`
635-
if source.ident.name == kw::SelfLower {
636-
type_ns_only = true;
629+
// `true` for `...::{self [as target]}` imports, `false` otherwise.
630+
let type_ns_only = nested && source.ident.name == kw::SelfLower;
637631

638-
if empty_for_self(&module_path) {
639-
self.r.report_error(
640-
use_tree.span,
641-
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix,
632+
match source.ident.name {
633+
kw::DollarCrate => {
634+
if !module_path.is_empty() {
635+
self.r.dcx().span_err(
636+
source.ident.span,
637+
"`$crate` in paths can only be used in start position",
642638
);
643639
return;
644640
}
645-
646-
// Replace `use foo::{ self };` with `use foo;`
647-
let self_span = source.ident.span;
648-
source = module_path.pop().unwrap();
649-
if rename.is_none() {
650-
// Keep the span of `self`, but the name of `foo`
651-
ident = Ident::new(source.ident.name, self_span);
641+
}
642+
kw::Crate => {
643+
if !module_path.is_empty() {
644+
self.r.dcx().span_err(
645+
source.ident.span,
646+
"`crate` in paths can only be used in start position",
647+
);
648+
return;
652649
}
653650
}
654-
} else {
655-
// Disallow `self`
656-
if source.ident.name == kw::SelfLower {
657-
let parent = module_path.last();
658-
659-
let span = match parent {
660-
// only `::self` from `use foo::self as bar`
661-
Some(seg) => seg.ident.span.shrink_to_hi().to(source.ident.span),
662-
None => source.ident.span,
663-
};
664-
let span_with_rename = match rename {
665-
// only `self as bar` from `use foo::self as bar`
666-
Some(rename) => source.ident.span.to(rename.span),
667-
None => source.ident.span,
668-
};
669-
self.r.report_error(
670-
span,
671-
ResolutionError::SelfImportsOnlyAllowedWithin {
672-
root: parent.is_none(),
673-
span_with_rename,
674-
},
675-
);
676-
677-
// Error recovery: replace `use foo::self;` with `use foo;`
651+
kw::Super => {
652+
// Allow `self::super` as a valid prefix - `self` at position 0
653+
// followed by any number of `super` segments.
654+
let valid_prefix = module_path.iter().enumerate().all(|(i, seg)| {
655+
let name = seg.ident.name;
656+
name == kw::Super || (name == kw::SelfLower && i == 0)
657+
});
658+
659+
if !valid_prefix {
660+
self.r.dcx().span_err(
661+
source.ident.span,
662+
"`super` in paths can only be used in start position, after `self`, or after another `super`",
663+
);
664+
return;
665+
}
666+
}
667+
kw::SelfLower => {
678668
if let Some(parent) = module_path.pop() {
669+
// Suggest `use prefix::{self};` for `use prefix::self;`
670+
if !type_ns_only
671+
&& (parent.ident.name != kw::PathRoot
672+
|| self.r.path_root_is_crate_root(parent.ident))
673+
{
674+
let span_with_rename = match rename {
675+
Some(rename) => source.ident.span.to(rename.span),
676+
None => source.ident.span,
677+
};
678+
679+
self.r.report_error(
680+
parent.ident.span.shrink_to_hi().to(source.ident.span),
681+
ResolutionError::SelfImportsOnlyAllowedWithin {
682+
root: parent.ident.name == kw::PathRoot,
683+
span_with_rename,
684+
},
685+
);
686+
}
687+
688+
let self_span = source.ident.span;
679689
source = parent;
680690
if rename.is_none() {
681-
ident = source.ident;
691+
ident = Ident::new(source.ident.name, self_span);
682692
}
683693
}
684694
}
695+
_ => {}
696+
}
685697

686-
// Disallow `use $crate;`
687-
if source.ident.name == kw::DollarCrate && module_path.is_empty() {
688-
let crate_root = self.r.resolve_crate_root(source.ident);
689-
let crate_name = match crate_root.kind {
690-
ModuleKind::Def(.., name) => name,
691-
ModuleKind::Block => unreachable!(),
692-
};
693-
// HACK(eddyb) unclear how good this is, but keeping `$crate`
694-
// in `source` breaks `tests/ui/imports/import-crate-var.rs`,
695-
// while the current crate doesn't have a valid `crate_name`.
696-
if let Some(crate_name) = crate_name {
697-
// `crate_name` should not be interpreted as relative.
698-
module_path.push(Segment::from_ident_and_id(
699-
Ident::new(kw::PathRoot, source.ident.span),
700-
self.r.next_node_id(),
701-
));
702-
source.ident.name = crate_name;
703-
}
704-
if rename.is_none() {
705-
ident.name = sym::dummy;
706-
}
707-
708-
self.r.dcx().emit_err(errors::CrateImported { span: item.span });
709-
}
698+
// Deny `use ::{self};` after edition 2015
699+
if source.ident.name == kw::PathRoot
700+
&& !self.r.path_root_is_crate_root(source.ident)
701+
{
702+
self.r.dcx().span_err(use_tree.span, "extern prelude cannot be imported");
703+
return;
710704
}
711705

712-
if ident.name == kw::Crate {
713-
self.r.dcx().emit_err(errors::UnnamedCrateRootImport { span: ident.span });
706+
// Deny importing path-kw without renaming
707+
if rename.is_none() && ident.is_path_segment_keyword() {
708+
let ident = use_tree.ident();
709+
710+
// Don't suggest `use xx::self as name;` for `use xx::self;`
711+
// But it's OK to suggest `use xx::{self as name};` for `use xx::{self};`
712+
let sugg = if !type_ns_only && ident.name == kw::SelfLower {
713+
None
714+
} else {
715+
Some(errors::UnnamedImportSugg { span: ident.span, ident })
716+
};
717+
718+
self.r.dcx().emit_err(errors::UnnamedImport { span: ident.span, sugg });
719+
return;
714720
}
715721

716722
let kind = ImportKind::Single {
@@ -740,32 +746,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
740746
}
741747
}
742748
ast::UseTreeKind::Nested { ref items, .. } => {
743-
// Ensure there is at most one `self` in the list
744-
let self_spans = items
745-
.iter()
746-
.filter_map(|(use_tree, _)| {
747-
if let ast::UseTreeKind::Simple(..) = use_tree.kind
748-
&& use_tree.ident().name == kw::SelfLower
749-
{
750-
return Some(use_tree.span);
751-
}
752-
753-
None
754-
})
755-
.collect::<Vec<_>>();
756-
if self_spans.len() > 1 {
757-
let mut e = self.r.into_struct_error(
758-
self_spans[0],
759-
ResolutionError::SelfImportCanOnlyAppearOnceInTheList,
760-
);
761-
762-
for other_span in self_spans.iter().skip(1) {
763-
e.span_label(*other_span, "another `self` import appears here");
764-
}
765-
766-
e.emit();
767-
}
768-
769749
for &(ref tree, id) in items {
770750
self.build_reduced_graph_for_use_tree(
771751
// This particular use tree
@@ -777,7 +757,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
777757
// Empty groups `a::b::{}` are turned into synthetic `self` imports
778758
// `a::b::c::{self as _}`, so that their prefixes are correctly
779759
// resolved and checked for privacy/stability/etc.
780-
if items.is_empty() && !empty_for_self(&prefix) {
760+
if items.is_empty()
761+
&& !prefix.is_empty()
762+
&& (prefix.len() > 1 || prefix[0].ident.name != kw::PathRoot)
763+
{
781764
let new_span = prefix[prefix.len() - 1].ident.span;
782765
let tree = ast::UseTree {
783766
prefix: ast::Path::from_ident(Ident::new(kw::SelfLower, new_span)),

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -893,12 +893,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
893893
mpart_suggestion,
894894
})
895895
}
896-
ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
897-
self.dcx().create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span })
898-
}
899-
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
900-
self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
901-
}
902896
ResolutionError::FailedToResolve { segment, label, suggestion, module, message } => {
903897
let mut err = struct_span_code_err!(self.dcx(), span, E0433, "{message}");
904898
err.span_label(span, label);

compiler/rustc_resolve/src/errors.rs

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -248,22 +248,6 @@ pub(crate) struct UnreachableLabelWithSimilarNameExists {
248248
pub(crate) ident_span: Span,
249249
}
250250

251-
#[derive(Diagnostic)]
252-
#[diag("`self` import can only appear once in an import list", code = E0430)]
253-
pub(crate) struct SelfImportCanOnlyAppearOnceInTheList {
254-
#[primary_span]
255-
#[label("can only appear once in an import list")]
256-
pub(crate) span: Span,
257-
}
258-
259-
#[derive(Diagnostic)]
260-
#[diag("`self` import can only appear in an import list with a non-empty prefix", code = E0431)]
261-
pub(crate) struct SelfImportOnlyInImportListWithNonEmptyPrefix {
262-
#[primary_span]
263-
#[label("can only appear in an import list with a non-empty prefix")]
264-
pub(crate) span: Span,
265-
}
266-
267251
#[derive(Diagnostic)]
268252
#[diag("can't capture dynamic environment in a fn item", code = E0434)]
269253
#[help("use the `|| {\"{\"} ... {\"}\"}` closure form instead")]
@@ -638,13 +622,6 @@ pub(crate) struct MacroExpandedMacroExportsAccessedByAbsolutePaths {
638622
pub definition: Span,
639623
}
640624

641-
#[derive(Diagnostic)]
642-
#[diag("`$crate` may not be imported")]
643-
pub(crate) struct CrateImported {
644-
#[primary_span]
645-
pub(crate) span: Span,
646-
}
647-
648625
#[derive(Diagnostic)]
649626
#[diag("`#[macro_use]` is not supported on `extern crate self`")]
650627
pub(crate) struct MacroUseExternCrateSelf {
@@ -973,11 +950,25 @@ pub(crate) struct ArgumentsMacroUseNotAllowed {
973950
pub(crate) span: Span,
974951
}
975952

953+
#[derive(Subdiagnostic)]
954+
#[multipart_suggestion(
955+
"try renaming it with a name",
956+
applicability = "maybe-incorrect",
957+
style = "verbose"
958+
)]
959+
pub(crate) struct UnnamedImportSugg {
960+
#[suggestion_part(code = "{ident} as name")]
961+
pub(crate) span: Span,
962+
pub(crate) ident: Ident,
963+
}
964+
976965
#[derive(Diagnostic)]
977-
#[diag("crate root imports need to be explicitly named: `use crate as name;`")]
978-
pub(crate) struct UnnamedCrateRootImport {
966+
#[diag("imports need to be explicitly named")]
967+
pub(crate) struct UnnamedImport {
979968
#[primary_span]
980969
pub(crate) span: Span,
970+
#[subdiagnostic]
971+
pub(crate) sugg: Option<UnnamedImportSugg>,
981972
}
982973

983974
#[derive(Diagnostic)]

0 commit comments

Comments
 (0)