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
93 changes: 68 additions & 25 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,35 +595,72 @@ 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 {
// Allow `use crate as 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;
}
}
// Allow `use super as name;`
kw::Super => {
if !module_path.is_empty() {
self.r.dcx().span_err(
ident.span,
"`super` in paths can only be used in start position",
);
return;
}

if rename.is_none() {
self.r
.dcx()
.emit_err(errors::UnnamedImports { span: ident.span, ident });
return;
}

type_ns_only = true;
}
// Allow `use self as name;`, `use foo::self;` and `use foo::self as name;`
kw::SelfLower => {
if let Some(parent) = module_path.pop() {
if parent.ident.name.is_path_segment_keyword() {
self.r.report_error(
source.ident.span,
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix,
);
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 @@ -707,6 +744,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() {}
12 changes: 12 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,12 @@
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
78 changes: 78 additions & 0 deletions tests/ui/use/use-path-segment-kw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//@ 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 bar() {}

mod foo {
pub mod bar {
pub mod foobar {
pub fn bar() {}
}
}

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 bar::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 bar::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 `super` in paths can only be used in start position
use bar::super; //~ ERROR `super` in paths can only be used in start position
use crate::super; //~ ERROR `super` in paths can only be used in start position
use super::super; //~ ERROR `super` in paths can only be used in start position
use self::super; //~ ERROR `super` in paths can only be used in start position
use ::super as _super2; //~ ERROR `super` in paths can only be used in start position
use bar::super as _super3; //~ ERROR `super` in paths can only be used in start position
use crate::super as _super4; //~ ERROR `super` in paths can only be used in start position
use super::super as _super5; //~ ERROR `super` in paths can only be used in start position
use bar::super as _super6; //~ ERROR `super` in paths can only be used in start position

pub use self as _self; // Good
use self; //~ ERROR imports need to be explicitly named: `use self as name;`
use ::self; //~ ERROR `self` import can only appear in an import list with a non-empty prefix
pub use bar::foobar::self; // Good
use crate::self; //~ ERROR `self` import can only appear in an import list with a non-empty prefix
use super::self; //~ ERROR `self` import can only appear in an import list with a non-empty prefix
use self::self; //~ ERROR `self` import can only appear in an import list with a non-empty prefix
use ::self as _self2; //~ ERROR `self` import can only appear in an import list with a non-empty prefix
pub use bar::self as _self3; // Good
use crate::self as _self4; //~ ERROR `self` import can only appear in an import list with a non-empty prefix
use super::self as _self5; //~ ERROR `self` import can only appear in an import list with a non-empty prefix
use self::self as _self6; //~ ERROR `self` import can only appear in an import list with a non-empty prefix
}

fn main() {
foo::_crate::bar();
foo::_super::bar();
foo::_self::bar::foobar::bar();
foo::foobar::bar();
foo::_self3::foobar::bar();
}
Loading
Loading