Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up errors in typeck and resolve #74005

Merged
merged 4 commits into from
Aug 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
47 changes: 34 additions & 13 deletions src/librustc_resolve/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -942,17 +942,6 @@ impl<'a> Resolver<'a> {
Some(suggestion) if suggestion.candidate == kw::Underscore => return false,
Some(suggestion) => suggestion,
};
let msg = format!(
"{} {} with a similar name exists",
suggestion.res.article(),
suggestion.res.descr()
);
err.span_suggestion(
span,
&msg,
suggestion.candidate.to_string(),
Applicability::MaybeIncorrect,
);
let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
LOCAL_CRATE => self.opt_span(def_id),
_ => Some(
Expand All @@ -961,16 +950,48 @@ impl<'a> Resolver<'a> {
.guess_head_span(self.cstore().get_span_untracked(def_id, self.session)),
),
});
if let Some(span) = def_span {
if let Some(def_span) = def_span {
if span.overlaps(def_span) {
// Don't suggest typo suggestion for itself like in the followoing:
// error[E0423]: expected function, tuple struct or tuple variant, found struct `X`
// --> $DIR/issue-64792-bad-unicode-ctor.rs:3:14
// |
// LL | struct X {}
// | ----------- `X` defined here
// LL |
// LL | const Y: X = X("ö");
// | -------------^^^^^^- similarly named constant `Y` defined here
// |
// help: use struct literal syntax instead
// |
// LL | const Y: X = X {};
// | ^^^^
// help: a constant with a similar name exists
// |
// LL | const Y: X = Y("ö");
// | ^
return false;
}
err.span_label(
self.session.source_map().guess_head_span(span),
self.session.source_map().guess_head_span(def_span),
&format!(
"similarly named {} `{}` defined here",
suggestion.res.descr(),
suggestion.candidate.as_str(),
),
);
}
let msg = format!(
"{} {} with a similar name exists",
suggestion.res.article(),
suggestion.res.descr()
);
err.span_suggestion(
span,
&msg,
suggestion.candidate.to_string(),
Applicability::MaybeIncorrect,
);
true
}

Expand Down
42 changes: 31 additions & 11 deletions src/librustc_resolve/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}
use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_session::config::nightly_options;
use rustc_span::hygiene::MacroKind;
Expand Down Expand Up @@ -88,6 +88,18 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str
}

impl<'a> LateResolutionVisitor<'a, '_, '_> {
fn def_span(&self, def_id: DefId) -> Option<Span> {
match def_id.krate {
LOCAL_CRATE => self.r.opt_span(def_id),
_ => Some(
self.r
.session
.source_map()
.guess_head_span(self.r.cstore().get_span_untracked(def_id, self.r.session)),
),
}
}

/// Handles error reporting for `smart_resolve_path_fragment` function.
/// Creates base error and amends it with one short label and possibly some longer helps/notes.
pub(crate) fn smart_resolve_report_errors(
Expand Down Expand Up @@ -339,8 +351,6 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {

// Try Levenshtein algorithm.
let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected, span);
let levenshtein_worked = self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);

// Try context-dependent help if relaxed lookup didn't work.
if let Some(res) = res {
if self.smart_resolve_context_dependent_help(
Expand All @@ -351,14 +361,18 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
&path_str,
&fallback_label,
) {
// We do this to avoid losing a secondary span when we override the main error span.
self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
return (err, candidates);
}
}

// Fallback label.
if !levenshtein_worked {
if !self.type_ascription_suggestion(&mut err, base_span)
&& !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span)
{
// Fallback label.
err.span_label(base_span, fallback_label);
self.type_ascription_suggestion(&mut err, base_span);

match self.diagnostic_metadata.current_let_binding {
Some((pat_sp, Some(ty_sp), None)) if ty_sp.contains(base_span) && could_be_expr => {
err.span_suggestion_short(
Expand Down Expand Up @@ -518,6 +532,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
}),
) if followed_by_brace => {
if let Some(sp) = closing_brace {
err.span_label(span, fallback_label);
err.multipart_suggestion(
"surround the struct literal with parentheses",
vec![
Expand Down Expand Up @@ -550,7 +565,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
}
_ => span,
};
if let Some(span) = self.r.opt_span(def_id) {
if let Some(span) = self.def_span(def_id) {
err.span_label(span, &format!("`{}` defined here", path_str));
}
let (tail, descr, applicability) = match source {
Expand Down Expand Up @@ -581,12 +596,15 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
applicability,
);
}
_ => {}
_ => {
err.span_label(span, fallback_label);
}
}
};

match (res, source) {
(Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
err.span_label(span, fallback_label);
err.span_suggestion_verbose(
span.shrink_to_hi(),
"use `!` to invoke the macro",
Expand All @@ -602,7 +620,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
if nightly_options::is_nightly_build() {
let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
`type` alias";
if let Some(span) = self.r.opt_span(def_id) {
if let Some(span) = self.def_span(def_id) {
err.span_help(span, msg);
} else {
err.help(msg);
Expand Down Expand Up @@ -680,7 +698,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
bad_struct_syntax_suggestion(def_id);
}
(Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
if let Some(span) = self.r.opt_span(def_id) {
if let Some(span) = self.def_span(def_id) {
err.span_label(span, &format!("`{}` defined here", path_str));
}
err.span_label(span, format!("did you mean `{}( /* fields */ )`?", path_str));
Expand Down Expand Up @@ -869,7 +887,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
start.to(sm.next_point(start))
}

fn type_ascription_suggestion(&self, err: &mut DiagnosticBuilder<'_>, base_span: Span) {
fn type_ascription_suggestion(&self, err: &mut DiagnosticBuilder<'_>, base_span: Span) -> bool {
let sm = self.r.session.source_map();
let base_snippet = sm.span_to_snippet(base_span);
if let Some(&sp) = self.diagnostic_metadata.current_type_ascription.last() {
Expand Down Expand Up @@ -939,9 +957,11 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
"expecting a type here because of type ascription",
);
}
return show_label;
}
}
}
false
}

fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ error[E0573]: expected type, found const parameter `C`
--> $DIR/struct-with-invalid-const-param.rs:4:23
|
LL | struct S<const C: u8>(C);
| ----------------------^--
| | |
| | help: a struct with a similar name exists: `S`
| similarly named struct `S` defined here
| ^ not a type

warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/struct-with-invalid-const-param.rs:1:12
Expand Down
44 changes: 29 additions & 15 deletions src/test/ui/empty/empty-struct-braces-expr.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ LL | let e1 = Empty1;
LL | pub struct XEmpty2;
| ------------------- similarly named unit struct `XEmpty2` defined here
|
help: a unit struct with a similar name exists
|
LL | let e1 = XEmpty2;
| ^^^^^^^
help: use struct literal syntax instead
|
LL | let e1 = Empty1 {};
| ^^^^^^^^^
help: a unit struct with a similar name exists
|
LL | let e1 = XEmpty2;
| ^^^^^^^

error[E0423]: expected function, tuple struct or tuple variant, found struct `Empty1`
--> $DIR/empty-struct-braces-expr.rs:16:14
Expand All @@ -29,15 +29,20 @@ LL | struct Empty1 {}
...
LL | let e1 = Empty1();
| ^^^^^^^^
|
::: $DIR/auxiliary/empty-struct.rs:2:1
|
help: a unit struct with a similar name exists
LL | pub struct XEmpty2;
| ------------------- similarly named unit struct `XEmpty2` defined here
|
LL | let e1 = XEmpty2();
| ^^^^^^^
help: use struct literal syntax instead
|
LL | let e1 = Empty1 {};
| ^^^^^^^^^
help: a unit struct with a similar name exists
|
LL | let e1 = XEmpty2();
| ^^^^^^^

error[E0423]: expected value, found struct variant `E::Empty3`
--> $DIR/empty-struct-braces-expr.rs:18:14
Expand All @@ -63,34 +68,43 @@ error[E0423]: expected value, found struct `XEmpty1`
LL | let xe1 = XEmpty1;
| ^^^^^^^
|
::: $DIR/auxiliary/empty-struct.rs:2:1
::: $DIR/auxiliary/empty-struct.rs:1:1
|
LL | pub struct XEmpty1 {}
| ------------------ `XEmpty1` defined here
LL | pub struct XEmpty2;
| ------------------- similarly named unit struct `XEmpty2` defined here
|
help: a unit struct with a similar name exists
|
LL | let xe1 = XEmpty2;
| ^^^^^^^
help: use struct literal syntax instead
|
LL | let xe1 = XEmpty1 {};
| ^^^^^^^^^^
help: a unit struct with a similar name exists
|
LL | let xe1 = XEmpty2;
| ^^^^^^^

error[E0423]: expected function, tuple struct or tuple variant, found struct `XEmpty1`
--> $DIR/empty-struct-braces-expr.rs:23:15
|
LL | let xe1 = XEmpty1();
| ^^^^^^^^^
|
::: $DIR/auxiliary/empty-struct.rs:1:1
|
help: a unit struct with a similar name exists
LL | pub struct XEmpty1 {}
| ------------------ `XEmpty1` defined here
LL | pub struct XEmpty2;
| ------------------- similarly named unit struct `XEmpty2` defined here
|
LL | let xe1 = XEmpty2();
| ^^^^^^^
help: use struct literal syntax instead
|
LL | let xe1 = XEmpty1 {};
| ^^^^^^^^^^
help: a unit struct with a similar name exists
|
LL | let xe1 = XEmpty2();
| ^^^^^^^

error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
--> $DIR/empty-struct-braces-expr.rs:25:19
Expand Down
12 changes: 7 additions & 5 deletions src/test/ui/empty/empty-struct-braces-pat-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,21 @@ error[E0532]: expected unit struct, unit variant or constant, found struct varia
LL | XE::XEmpty3 => ()
| ^^^^^^^^^^^
|
::: $DIR/auxiliary/empty-struct.rs:7:5
::: $DIR/auxiliary/empty-struct.rs:6:5
|
LL | XEmpty3 {},
| ------- `XE::XEmpty3` defined here
LL | XEmpty4,
| ------- similarly named unit variant `XEmpty4` defined here
|
help: a unit variant with a similar name exists
|
LL | XE::XEmpty4 => ()
| ^^^^^^^
help: use struct pattern syntax instead
|
LL | XE::XEmpty3 { /* fields */ } => ()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: a unit variant with a similar name exists
|
LL | XE::XEmpty4 => ()
| ^^^^^^^

error: aborting due to 2 previous errors

Expand Down