Skip to content
Open
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
4 changes: 3 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0430.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#### Note: this error code is no longer emitted by the compiler.

The `self` import appears more than once in the list.

Erroneous code example:

```compile_fail,E0430
```ignore (error is no longer emitted)
use something::{self, self}; // error: `self` import can only appear once in
// the list
```
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0431.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#### Note: this error code is no longer emitted by the compiler.

An invalid `self` import was made.

Erroneous code example:

```compile_fail,E0431
```ignore (error is no longer emitted)
use {self}; // error: `self` import can only appear in an import list with a
// non-empty prefix
```
Expand Down
14 changes: 2 additions & 12 deletions compiler/rustc_resolve/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,6 @@ resolve_ident_in_scope_but_it_is_desc =

resolve_implicit_elided_lifetimes_not_allowed_here = implicit elided lifetime not allowed here

resolve_imported_crate = `$crate` may not be imported

resolve_imported_macro_not_found = imported macro not found

resolve_imports_cannot_refer_to =
Expand Down Expand Up @@ -397,14 +395,6 @@ resolve_remove_surrounding_derive =

resolve_remove_unnecessary_import = remove unnecessary import

resolve_self_import_can_only_appear_once_in_the_list =
`self` import can only appear once in an import list
.label = can only appear once in an import list

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

Expand Down Expand Up @@ -487,8 +477,8 @@ resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg =
resolve_unknown_diagnostic_attribute = unknown diagnostic attribute
resolve_unknown_diagnostic_attribute_typo_sugg = an attribute with a similar name exists

resolve_unnamed_crate_root_import =
crate root imports need to be explicitly named: `use crate as name;`
resolve_unnamed_import = imports need to be explicitly named
resolve_unnamed_import_sugg = try renaming it with a name

resolve_unreachable_label =
use of unreachable label `{$name}`
Expand Down
174 changes: 76 additions & 98 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,97 +564,98 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
let prefix = crate_root.into_iter().chain(prefix_iter).collect::<Vec<_>>();
debug!("build_reduced_graph_for_use_tree: prefix={:?}", prefix);

let empty_for_self = |prefix: &[Segment]| {
prefix.is_empty() || prefix.len() == 1 && prefix[0].ident.name == kw::PathRoot
};
match use_tree.kind {
ast::UseTreeKind::Simple(rename) => {
let mut ident = use_tree.ident();
let mut module_path = prefix;
let mut source = module_path.pop().unwrap();
let mut type_ns_only = false;

if nested {
// Correctly handle `self`
if source.ident.name == kw::SelfLower {
type_ns_only = true;

if empty_for_self(&module_path) {
self.r.report_error(
use_tree.span,
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix,
// `true` for `...::{self [as target]}` imports, `false` otherwise.
let type_ns_only = nested
&& source.ident.name == kw::SelfLower
&& use_tree.prefix.segments.len() == 1;

match source.ident.name {
kw::DollarCrate => {
if !module_path.is_empty() {
self.r.dcx().span_err(
source.ident.span,
"`$crate` in paths can only be used in start position",
);
return;
}

// Replace `use foo::{ self };` with `use foo;`
let self_span = source.ident.span;
source = module_path.pop().unwrap();
if rename.is_none() {
// Keep the span of `self`, but the name of `foo`
ident = Ident::new(source.ident.name, self_span);
}
kw::Crate => {
if !module_path.is_empty() {
self.r.dcx().span_err(
source.ident.span,
"`crate` in paths can only be used in start position",
);
return;
}
}
} else {
// Disallow `self`
if source.ident.name == kw::SelfLower {
let parent = module_path.last();

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;`
kw::Super => {
if module_path.iter().any(|seg| seg.ident.name != kw::Super) {
self.r.dcx().span_err(
source.ident.span,
"`super` in paths can only be used in start position or after another `super`",
);
return;
}
}
kw::SelfLower => {
if let Some(parent) = module_path.pop() {
// Suggest `use prefix::{self};` for `use prefix::self;`
if !type_ns_only
&& (parent.ident.name != kw::PathRoot
|| self.r.path_root_is_crate_root(parent.ident))
{
let span_with_rename = match rename {
Some(rename) => source.ident.span.to(rename.span),
None => source.ident.span,
};

self.r.report_error(
parent.ident.span.shrink_to_hi().to(source.ident.span),
ResolutionError::SelfImportsOnlyAllowedWithin {
root: parent.ident.name == kw::PathRoot,
span_with_rename,
},
);
}

let self_span = source.ident.span;
source = parent;
if rename.is_none() {
ident = source.ident;
ident = Ident::new(source.ident.name, self_span);
}
}
}
_ => {}
}

// Disallow `use $crate;`
if source.ident.name == kw::DollarCrate && module_path.is_empty() {
let crate_root = self.r.resolve_crate_root(source.ident);
let crate_name = match crate_root.kind {
ModuleKind::Def(.., name) => name,
ModuleKind::Block => unreachable!(),
};
// HACK(eddyb) unclear how good this is, but keeping `$crate`
// in `source` breaks `tests/ui/imports/import-crate-var.rs`,
// while the current crate doesn't have a valid `crate_name`.
if let Some(crate_name) = crate_name {
// `crate_name` should not be interpreted as relative.
module_path.push(Segment::from_ident_and_id(
Ident::new(kw::PathRoot, source.ident.span),
self.r.next_node_id(),
));
source.ident.name = crate_name;
}
if rename.is_none() {
ident.name = sym::dummy;
}

self.r.dcx().emit_err(errors::CrateImported { span: item.span });
}
// Deny `use ::{self};` after edition 2015
if source.ident.name == kw::PathRoot
&& !self.r.path_root_is_crate_root(source.ident)
{
self.r.dcx().span_err(use_tree.span, "extern prelude cannot be imported");
return;
}

if ident.name == kw::Crate {
self.r.dcx().emit_err(errors::UnnamedCrateRootImport { span: ident.span });
// Deny importing path-kw without renaming
if rename.is_none() && ident.is_path_segment_keyword() {
let ident = use_tree.ident();

// Don't suggest `use xx::self as name;` for `use xx::self;`
// But it's OK to suggest `use xx::{self as name};` for `use xx::{self};`
let sugg = if !type_ns_only && ident.name == kw::SelfLower {
None
} else {
Some(errors::UnnamedImportSugg { span: ident.span, ident })
};

self.r.dcx().emit_err(errors::UnnamedImport { span: ident.span, sugg });
return;
}

let kind = ImportKind::Single {
Expand Down Expand Up @@ -684,32 +685,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
}
}
ast::UseTreeKind::Nested { ref items, .. } => {
// Ensure there is at most one `self` in the list
let self_spans = items
.iter()
.filter_map(|(use_tree, _)| {
if let ast::UseTreeKind::Simple(..) = use_tree.kind
&& use_tree.ident().name == kw::SelfLower
{
return Some(use_tree.span);
}

None
})
.collect::<Vec<_>>();
if self_spans.len() > 1 {
let mut e = self.r.into_struct_error(
self_spans[0],
ResolutionError::SelfImportCanOnlyAppearOnceInTheList,
);

for other_span in self_spans.iter().skip(1) {
e.span_label(*other_span, "another `self` import appears here");
}

e.emit();
}

for &(ref tree, id) in items {
self.build_reduced_graph_for_use_tree(
// This particular use tree
Expand All @@ -721,7 +696,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
// Empty groups `a::b::{}` are turned into synthetic `self` imports
// `a::b::c::{self as _}`, so that their prefixes are correctly
// resolved and checked for privacy/stability/etc.
if items.is_empty() && !empty_for_self(&prefix) {
if items.is_empty()
&& !prefix.is_empty()
&& (prefix.len() > 1 || prefix[0].ident.name != kw::PathRoot)
{
let new_span = prefix[prefix.len() - 1].ident.span;
let tree = ast::UseTree {
prefix: ast::Path::from_ident(Ident::new(kw::SelfLower, new_span)),
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -902,12 +902,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
mpart_suggestion,
})
}
ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
self.dcx().create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span })
}
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
}
ResolutionError::FailedToResolve { segment, label, suggestion, module } => {
let mut err =
struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {label}");
Expand Down
41 changes: 16 additions & 25 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,22 +233,6 @@ pub(crate) struct UnreachableLabelWithSimilarNameExists {
pub(crate) ident_span: Span,
}

#[derive(Diagnostic)]
#[diag(resolve_self_import_can_only_appear_once_in_the_list, code = E0430)]
pub(crate) struct SelfImportCanOnlyAppearOnceInTheList {
#[primary_span]
#[label]
pub(crate) span: Span,
}

#[derive(Diagnostic)]
#[diag(resolve_self_import_only_in_import_list_with_non_empty_prefix, code = E0431)]
pub(crate) struct SelfImportOnlyInImportListWithNonEmptyPrefix {
#[primary_span]
#[label]
pub(crate) span: Span,
}

#[derive(Diagnostic)]
#[diag(resolve_cannot_capture_dynamic_environment_in_fn_item, code = E0434)]
#[help]
Expand Down Expand Up @@ -611,13 +595,6 @@ pub(crate) struct MacroExpandedMacroExportsAccessedByAbsolutePaths {
pub definition: Span,
}

#[derive(Diagnostic)]
#[diag(resolve_imported_crate)]
pub(crate) struct CrateImported {
#[primary_span]
pub(crate) span: Span,
}

#[derive(Diagnostic)]
#[diag(resolve_macro_use_extern_crate_self)]
pub(crate) struct MacroUseExternCrateSelf {
Expand Down Expand Up @@ -928,11 +905,25 @@ pub(crate) struct ArgumentsMacroUseNotAllowed {
pub(crate) span: Span,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(
resolve_unnamed_import_sugg,
applicability = "maybe-incorrect",
style = "verbose"
)]
pub(crate) struct UnnamedImportSugg {
#[suggestion_part(code = "{ident} as name")]
pub(crate) span: Span,
pub(crate) ident: Ident,
}

#[derive(Diagnostic)]
#[diag(resolve_unnamed_crate_root_import)]
pub(crate) struct UnnamedCrateRootImport {
#[diag(resolve_unnamed_import)]
pub(crate) struct UnnamedImport {
#[primary_span]
pub(crate) span: Span,
#[subdiagnostic]
pub(crate) sugg: Option<UnnamedImportSugg>,
}

#[derive(Diagnostic)]
Expand Down
Loading
Loading