From 30a19adb73e1876511bb6c3bf7cc3900b5127d72 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Thu, 25 Sep 2025 09:53:57 +0800 Subject: [PATCH] WIP: rewrite build_reduced_graph_for_use_tree --- compiler/rustc_resolve/messages.ftl | 12 +- .../rustc_resolve/src/build_reduced_graph.rs | 80 +++++--- compiler/rustc_resolve/src/diagnostics.rs | 23 --- compiler/rustc_resolve/src/errors.rs | 42 +---- compiler/rustc_resolve/src/ident.rs | 8 + compiler/rustc_resolve/src/lib.rs | 2 - .../ui/dollar-crate/use-dollar-crate-self.rs | 9 + .../dollar-crate/use-dollar-crate-self.stderr | 13 ++ tests/ui/use/use-path-segment-kw.rs | 88 +++++++++ tests/ui/use/use-path-segment-kw.stderr | 171 ++++++++++++++++++ 10 files changed, 355 insertions(+), 93 deletions(-) create mode 100644 tests/ui/dollar-crate/use-dollar-crate-self.rs create mode 100644 tests/ui/dollar-crate/use-dollar-crate-self.stderr create mode 100644 tests/ui/use/use-path-segment-kw.rs create mode 100644 tests/ui/use/use-path-segment-kw.stderr diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 5bf90d2637df5..acdd6fd0915db 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -381,15 +381,6 @@ resolve_self_import_only_in_import_list_with_non_empty_prefix = `self` import can only appear in an import list with a non-empty prefix .label = can only appear in an import list with a non-empty prefix -resolve_self_imports_only_allowed_within = - `self` imports are only allowed within a {"{"} {"}"} list - -resolve_self_imports_only_allowed_within_multipart_suggestion = - alternatively, use the multi-path `use` syntax to import `self` - -resolve_self_imports_only_allowed_within_suggestion = - consider importing the module directly - resolve_self_in_const_generic_ty = cannot use `Self` in const parameter type @@ -463,6 +454,9 @@ resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg = resolve_unnamed_crate_root_import = crate root imports need to be explicitly named: `use crate as name;` +resolve_unnamed_imports = + imports need to be explicitly named: `use {$ident} as name;` + resolve_unreachable_label = use of unreachable label `{$name}` .label = unreachable label `{$name}` diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 88fbc6dcb6650..2ad75f8b1545a 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -596,35 +596,59 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } } } else { - // Disallow `self` - if source.ident.name == kw::SelfLower { - let parent = module_path.last(); + match source.ident.name { + kw::Crate => { + if !module_path.is_empty() { + self.r.dcx().span_err( + ident.span, + "`crate` in paths can only be used in start position", + ); + return; + } - let span = match parent { - // only `::self` from `use foo::self as bar` - Some(seg) => seg.ident.span.shrink_to_hi().to(source.ident.span), - None => source.ident.span, - }; - let span_with_rename = match rename { - // only `self as bar` from `use foo::self as bar` - Some(rename) => source.ident.span.to(rename.span), - None => source.ident.span, - }; - self.r.report_error( - span, - ResolutionError::SelfImportsOnlyAllowedWithin { - root: parent.is_none(), - span_with_rename, - }, - ); - - // Error recovery: replace `use foo::self;` with `use foo;` - if let Some(parent) = module_path.pop() { - source = parent; if rename.is_none() { - ident = source.ident; + self.r + .dcx() + .emit_err(errors::UnnamedCrateRootImport { span: ident.span }); + return; } } + kw::Super => { + if rename.is_none() { + self.r + .dcx() + .emit_err(errors::UnnamedImports { span: ident.span, ident }); + return; + } + + type_ns_only = true; + } + kw::SelfLower => { + if let Some(parent) = module_path.pop() { + if parent.ident.name.is_path_segment_keyword() && rename.is_none() { + self.r.dcx().emit_err(errors::UnnamedImports { + span: ident.span, + ident, + }); + return; + } + + let self_span = source.ident.span; + source = parent; + if rename.is_none() { + ident = Ident::new(source.ident.name, self_span); + } + } else if rename.is_none() { + self.r + .dcx() + .emit_err(errors::UnnamedImports { span: ident.span, ident }); + return; + } + + type_ns_only = true; + } + kw::DollarCrate => {} + _ => {} } // Disallow `use $crate;` @@ -708,6 +732,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } e.emit(); + } else if let &[self_span] = &self_spans[..] + && prefix.len() == 1 + && prefix[0].ident.name == kw::DollarCrate + { + // Disallow `use $crate::{self};` + self.r.dcx().emit_err(errors::CrateImported { span: self_span }); } for &(ref tree, id) in items { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 236ab1f09d35f..9cc5be3a15f75 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -867,29 +867,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { sub_unreachable, }) } - ResolutionError::SelfImportsOnlyAllowedWithin { root, span_with_rename } => { - // None of the suggestions below would help with a case like `use self`. - let (suggestion, mpart_suggestion) = if root { - (None, None) - } else { - // use foo::bar::self -> foo::bar - // use foo::bar::self as abc -> foo::bar as abc - let suggestion = errs::SelfImportsOnlyAllowedWithinSuggestion { span }; - - // use foo::bar::self -> foo::bar::{self} - // use foo::bar::self as abc -> foo::bar::{self as abc} - let mpart_suggestion = errs::SelfImportsOnlyAllowedWithinMultipartSuggestion { - multipart_start: span_with_rename.shrink_to_lo(), - multipart_end: span_with_rename.shrink_to_hi(), - }; - (Some(suggestion), Some(mpart_suggestion)) - }; - self.dcx().create_err(errs::SelfImportsOnlyAllowedWithin { - span, - suggestion, - mpart_suggestion, - }) - } ResolutionError::SelfImportCanOnlyAppearOnceInTheList => { self.dcx().create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span }) } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index f0ea97ba8a0c0..c9d56080073c1 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -272,40 +272,6 @@ pub(crate) struct AttemptToUseNonConstantValueInConstantWithoutSuggestion<'a> { pub(crate) suggestion: &'a str, } -#[derive(Diagnostic)] -#[diag(resolve_self_imports_only_allowed_within, code = E0429)] -pub(crate) struct SelfImportsOnlyAllowedWithin { - #[primary_span] - pub(crate) span: Span, - #[subdiagnostic] - pub(crate) suggestion: Option, - #[subdiagnostic] - pub(crate) mpart_suggestion: Option, -} - -#[derive(Subdiagnostic)] -#[suggestion( - resolve_self_imports_only_allowed_within_suggestion, - code = "", - applicability = "machine-applicable" -)] -pub(crate) struct SelfImportsOnlyAllowedWithinSuggestion { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion( - resolve_self_imports_only_allowed_within_multipart_suggestion, - applicability = "machine-applicable" -)] -pub(crate) struct SelfImportsOnlyAllowedWithinMultipartSuggestion { - #[suggestion_part(code = "{{")] - pub(crate) multipart_start: Span, - #[suggestion_part(code = "}}")] - pub(crate) multipart_end: Span, -} - #[derive(Diagnostic)] #[diag(resolve_binding_shadows_something_unacceptable, code = E0530)] pub(crate) struct BindingShadowsSomethingUnacceptable<'a> { @@ -898,6 +864,14 @@ pub(crate) struct UnnamedCrateRootImport { pub(crate) span: Span, } +#[derive(Diagnostic)] +#[diag(resolve_unnamed_imports)] +pub(crate) struct UnnamedImports { + #[primary_span] + pub(crate) span: Span, + pub(crate) ident: Ident, +} + #[derive(Diagnostic)] #[diag(resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments)] pub(crate) struct MacroExpandedExternCrateCannotShadowExternArguments { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 2a195c8068dac..bbe31e04e8149 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -869,6 +869,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // FIXME: Implement these with renaming requirements so that e.g. // `use super;` doesn't work, but `use super as name;` does. // Fall through here to get an error from `early_resolve_...`. + + if ident.name == kw::Super { + if let Some(parent) = parent_scope.module.parent { + return Ok(parent.self_binding.unwrap()); + } + } else { + return Ok(parent_scope.module.self_binding.unwrap()); + } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1636605b234f4..43374b7f9ab39 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -261,8 +261,6 @@ enum ResolutionError<'ra> { IdentifierBoundMoreThanOnceInSamePattern(Ident), /// Error E0426: use of undeclared label. UndeclaredLabel { name: Symbol, suggestion: Option }, - /// Error E0429: `self` imports are only allowed within a `{ }` list. - SelfImportsOnlyAllowedWithin { root: bool, span_with_rename: Span }, /// Error E0430: `self` import can only appear once in the list. SelfImportCanOnlyAppearOnceInTheList, /// Error E0431: `self` import can only appear in an import list with a non-empty prefix. diff --git a/tests/ui/dollar-crate/use-dollar-crate-self.rs b/tests/ui/dollar-crate/use-dollar-crate-self.rs new file mode 100644 index 0000000000000..fc9898ef151ac --- /dev/null +++ b/tests/ui/dollar-crate/use-dollar-crate-self.rs @@ -0,0 +1,9 @@ +macro_rules! foo { + () => { + use $crate::{self}; //~ ERROR `$crate` may not be imported + }; +} + +foo!(); + +fn main() {} diff --git a/tests/ui/dollar-crate/use-dollar-crate-self.stderr b/tests/ui/dollar-crate/use-dollar-crate-self.stderr new file mode 100644 index 0000000000000..262bb56dc50b7 --- /dev/null +++ b/tests/ui/dollar-crate/use-dollar-crate-self.stderr @@ -0,0 +1,13 @@ +error: `$crate` may not be imported + --> $DIR/use-dollar-crate-self.rs:3:22 + | +LL | use $crate::{self}; + | ^^^^ +... +LL | foo!(); + | ------ in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/use/use-path-segment-kw.rs b/tests/ui/use/use-path-segment-kw.rs new file mode 100644 index 0000000000000..d06ea900a0d83 --- /dev/null +++ b/tests/ui/use/use-path-segment-kw.rs @@ -0,0 +1,88 @@ +//@ edition: 2021 + +// mod x { +// use super; // bad +// use super as name; // good +// use self; // bad +// use self as name; // good +// use crate; // bad +// use crate as name; // good +// use $crate; // bad +// use $crate as name; // good + +// mod foo; +// use foo::crate; // bad +// use crate::crate; // bad +// use foo::super; // bad +// use super::super; // bad +// use foo::self; // good +// use self::self; // bad +// use self::self as name; // good +// } + +fn outer() {} + +mod foo { + pub mod bar { + pub mod foobar { + pub mod qux { + pub use super::inner; + } + + pub fn inner() {} + } + + pub use crate as _crate; // Good + use crate; //~ ERROR crate root imports need to be explicitly named: `use crate as name;` + use ::crate; //~ ERROR `crate` in paths can only be used in start position + use foobar::crate; //~ ERROR `crate` in paths can only be used in start position + use crate::crate; //~ ERROR `crate` in paths can only be used in start position + use super::crate; //~ ERROR `crate` in paths can only be used in start position + use self::crate; //~ ERROR `crate` in paths can only be used in start position + use ::crate as _crate2; //~ ERROR `crate` in paths can only be used in start position + use foobar::crate as _crate3; //~ ERROR `crate` in paths can only be used in start position + use crate::crate as _crate4; //~ ERROR `crate` in paths can only be used in start position + use super::crate as _crate5; //~ ERROR `crate` in paths can only be used in start position + use self::crate as _crate6; //~ ERROR `crate` in paths can only be used in start position + + pub use super as _super; // Good + use super; //~ ERROR imports need to be explicitly named: `use super as name;` + use ::super; //~ ERROR imports need to be explicitly named: `use super as name;` + use foobar::super; //~ ERROR imports need to be explicitly named: `use super as name;` + use crate::super; //~ ERROR imports need to be explicitly named: `use super as name;` + use super::super; //~ ERROR imports need to be explicitly named: `use super as name;` + use self::super; //~ ERROR imports need to be explicitly named: `use super as name;` + use ::super as _super2; //~ ERROR unresolved import `super` + use foobar::super as _super3; //~ ERROR unresolved import `foobar::super` + use crate::super as _super4; //~ ERROR unresolved import `crate::super` + use super::super as _super5; //~ ERROR unresolved import `super::super` + use foobar::super as _super6; //~ ERROR unresolved import `foobar::super` + + pub use self as _self; // Good + pub use foobar::qux::self; // Good + pub use foobar::self as _self3; // Good + pub use crate::self as _self4; // Good + pub use super::self as _self5; // Good + pub use self::self as _self6; // Good + use self; //~ ERROR imports need to be explicitly named: `use self as name;` + use ::self; //~ ERROR imports need to be explicitly named: `use self as name;` + use crate::self; //~ ERROR imports need to be explicitly named: `use self as name;` + use super::self; //~ ERROR imports need to be explicitly named: `use self as name;` + use self::self; //~ ERROR imports need to be explicitly named: `use self as name;` + use ::self as _self2; //~ ERROR unresolved import `{{root}}` + } +} + +fn main() { + foo::bar::_crate::outer(); + foo::bar::_crate::foo::bar::foobar::inner(); + + foo::bar::_super::bar::foobar::inner(); + + foo::bar::_self::foobar::inner(); + foo::bar::qux::inner(); + foo::bar::_self3::inner(); + foo::bar::_self4::outer(); + foo::bar::_self5::bar::foobar::inner(); + foo::bar::_self6::foobar::inner(); +} diff --git a/tests/ui/use/use-path-segment-kw.stderr b/tests/ui/use/use-path-segment-kw.stderr new file mode 100644 index 0000000000000..37bd76ff24437 --- /dev/null +++ b/tests/ui/use/use-path-segment-kw.stderr @@ -0,0 +1,171 @@ +error: crate root imports need to be explicitly named: `use crate as name;` + --> $DIR/use-path-segment-kw.rs:36:13 + | +LL | use crate; + | ^^^^^ + +error: `crate` in paths can only be used in start position + --> $DIR/use-path-segment-kw.rs:37:15 + | +LL | use ::crate; + | ^^^^^ + +error: `crate` in paths can only be used in start position + --> $DIR/use-path-segment-kw.rs:38:21 + | +LL | use foobar::crate; + | ^^^^^ + +error: `crate` in paths can only be used in start position + --> $DIR/use-path-segment-kw.rs:39:20 + | +LL | use crate::crate; + | ^^^^^ + +error: `crate` in paths can only be used in start position + --> $DIR/use-path-segment-kw.rs:40:20 + | +LL | use super::crate; + | ^^^^^ + +error: `crate` in paths can only be used in start position + --> $DIR/use-path-segment-kw.rs:41:19 + | +LL | use self::crate; + | ^^^^^ + +error: `crate` in paths can only be used in start position + --> $DIR/use-path-segment-kw.rs:42:24 + | +LL | use ::crate as _crate2; + | ^^^^^^^ + +error: `crate` in paths can only be used in start position + --> $DIR/use-path-segment-kw.rs:43:30 + | +LL | use foobar::crate as _crate3; + | ^^^^^^^ + +error: `crate` in paths can only be used in start position + --> $DIR/use-path-segment-kw.rs:44:29 + | +LL | use crate::crate as _crate4; + | ^^^^^^^ + +error: `crate` in paths can only be used in start position + --> $DIR/use-path-segment-kw.rs:45:29 + | +LL | use super::crate as _crate5; + | ^^^^^^^ + +error: `crate` in paths can only be used in start position + --> $DIR/use-path-segment-kw.rs:46:28 + | +LL | use self::crate as _crate6; + | ^^^^^^^ + +error: imports need to be explicitly named: `use super as name;` + --> $DIR/use-path-segment-kw.rs:49:13 + | +LL | use super; + | ^^^^^ + +error: imports need to be explicitly named: `use super as name;` + --> $DIR/use-path-segment-kw.rs:50:15 + | +LL | use ::super; + | ^^^^^ + +error: imports need to be explicitly named: `use super as name;` + --> $DIR/use-path-segment-kw.rs:51:21 + | +LL | use foobar::super; + | ^^^^^ + +error: imports need to be explicitly named: `use super as name;` + --> $DIR/use-path-segment-kw.rs:52:20 + | +LL | use crate::super; + | ^^^^^ + +error: imports need to be explicitly named: `use super as name;` + --> $DIR/use-path-segment-kw.rs:53:20 + | +LL | use super::super; + | ^^^^^ + +error: imports need to be explicitly named: `use super as name;` + --> $DIR/use-path-segment-kw.rs:54:19 + | +LL | use self::super; + | ^^^^^ + +error: imports need to be explicitly named: `use self as name;` + --> $DIR/use-path-segment-kw.rs:67:13 + | +LL | use self; + | ^^^^ + +error: imports need to be explicitly named: `use self as name;` + --> $DIR/use-path-segment-kw.rs:68:15 + | +LL | use ::self; + | ^^^^ + +error: imports need to be explicitly named: `use self as name;` + --> $DIR/use-path-segment-kw.rs:69:20 + | +LL | use crate::self; + | ^^^^ + +error: imports need to be explicitly named: `use self as name;` + --> $DIR/use-path-segment-kw.rs:70:20 + | +LL | use super::self; + | ^^^^ + +error: imports need to be explicitly named: `use self as name;` + --> $DIR/use-path-segment-kw.rs:71:19 + | +LL | use self::self; + | ^^^^ + +error[E0432]: unresolved import `super` + --> $DIR/use-path-segment-kw.rs:55:13 + | +LL | use ::super as _super2; + | ^^^^^^^^^^^^^^^^^^ no `super` in the root + +error[E0432]: unresolved import `foobar::super` + --> $DIR/use-path-segment-kw.rs:56:13 + | +LL | use foobar::super as _super3; + | ^^^^^^^^^^^^^^^^^^^^^^^^ no `super` in `foo::bar::foobar` + +error[E0432]: unresolved import `crate::super` + --> $DIR/use-path-segment-kw.rs:57:13 + | +LL | use crate::super as _super4; + | ^^^^^^^^^^^^^^^^^^^^^^^ no `super` in the root + +error[E0432]: unresolved import `super::super` + --> $DIR/use-path-segment-kw.rs:58:13 + | +LL | use super::super as _super5; + | ^^^^^^^^^^^^^^^^^^^^^^^ no `super` in `foo` + +error[E0432]: unresolved import `foobar::super` + --> $DIR/use-path-segment-kw.rs:59:13 + | +LL | use foobar::super as _super6; + | ^^^^^^^^^^^^^^^^^^^^^^^^ no `super` in `foo::bar::foobar` + +error[E0432]: unresolved import `{{root}}` + --> $DIR/use-path-segment-kw.rs:72:13 + | +LL | use ::self as _self2; + | ^^^^^^^^^^^^^^^^ no `{{root}}` in the root + +error: aborting due to 28 previous errors + +For more information about this error, try `rustc --explain E0432`.