Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions compiler/rustc_resolve/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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}`
Expand Down
80 changes: 55 additions & 25 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;`
Expand Down Expand Up @@ -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 {
Expand Down
23 changes: 0 additions & 23 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
}
Expand Down
42 changes: 8 additions & 34 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<SelfImportsOnlyAllowedWithinSuggestion>,
#[subdiagnostic]
pub(crate) mpart_suggestion: Option<SelfImportsOnlyAllowedWithinMultipartSuggestion>,
}

#[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> {
Expand Down Expand Up @@ -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 {
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}
}

Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,6 @@ enum ResolutionError<'ra> {
IdentifierBoundMoreThanOnceInSamePattern(Ident),
/// Error E0426: use of undeclared label.
UndeclaredLabel { name: Symbol, suggestion: Option<LabelSuggestion> },
/// 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.
Expand Down
9 changes: 9 additions & 0 deletions tests/ui/dollar-crate/use-dollar-crate-self.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
macro_rules! foo {
() => {
use $crate::{self}; //~ ERROR `$crate` may not be imported
};
}

foo!();

fn main() {}
13 changes: 13 additions & 0 deletions tests/ui/dollar-crate/use-dollar-crate-self.stderr
Original file line number Diff line number Diff line change
@@ -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

88 changes: 88 additions & 0 deletions tests/ui/use/use-path-segment-kw.rs
Original file line number Diff line number Diff line change
@@ -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();
}
Loading
Loading