Skip to content

Commit

Permalink
Auto merge of #74005 - estebank:type-ascription-redux, r=petrochenkov
Browse files Browse the repository at this point in the history
Clean up errors in typeck and resolve

* Tweak ordering of suggestions
* Do not suggest similarly named enclosing item
* Point at item definition in foreign crates
* Add missing primary label

CC #34255.
  • Loading branch information
bors committed Aug 10, 2020
2 parents 770bd3d + 54f1b43 commit 3bb5a86
Show file tree
Hide file tree
Showing 26 changed files with 225 additions and 146 deletions.
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
Loading

0 comments on commit 3bb5a86

Please sign in to comment.