Skip to content

Commit

Permalink
Point at local similarly named element and tweak references to variants
Browse files Browse the repository at this point in the history
Point at the span for the definition of ADTs internal to the current
crate.

Look at the leading char of the ident to determine whether we're
expecting a likely fn or any of a fn, a tuple struct or a tuple variant.

Turn fn `add_typo_suggestion` into a `Resolver` method.
  • Loading branch information
estebank committed Oct 27, 2019
1 parent 0f677c6 commit b26ddb8
Show file tree
Hide file tree
Showing 132 changed files with 600 additions and 331 deletions.
20 changes: 11 additions & 9 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -850,12 +850,14 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
Res::Def(kind @ DefKind::Mod, def_id)
| Res::Def(kind @ DefKind::Enum, def_id)
| Res::Def(kind @ DefKind::Trait, def_id) => {
let module = self.r.new_module(parent,
ModuleKind::Def(kind, def_id, ident.name),
def_id,
expansion,
span);
self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
let module = self.r.new_module(
parent,
ModuleKind::Def(kind, def_id, ident.name),
def_id,
expansion,
span,
);
self.r.define(parent, ident, TypeNS, (module, vis, span, expansion));
}
Res::Def(DefKind::Struct, _)
| Res::Def(DefKind::Union, _)
Expand All @@ -868,17 +870,17 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
| Res::Def(DefKind::AssocOpaqueTy, _)
| Res::PrimTy(..)
| Res::ToolMod =>
self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)),
self.r.define(parent, ident, TypeNS, (res, vis, span, expansion)),
Res::Def(DefKind::Fn, _)
| Res::Def(DefKind::Method, _)
| Res::Def(DefKind::Static, _)
| Res::Def(DefKind::Const, _)
| Res::Def(DefKind::AssocConst, _)
| Res::Def(DefKind::Ctor(..), _) =>
self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)),
self.r.define(parent, ident, ValueNS, (res, vis, span, expansion)),
Res::Def(DefKind::Macro(..), _)
| Res::NonMacroAttr(..) =>
self.r.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion)),
self.r.define(parent, ident, MacroNS, (res, vis, span, expansion)),
Res::Def(DefKind::TyParam, _) | Res::Def(DefKind::ConstParam, _)
| Res::Local(..) | Res::SelfTy(..) | Res::SelfCtor(..) | Res::Err =>
bug!("unexpected resolution: {:?}", res)
Expand Down
44 changes: 28 additions & 16 deletions src/librustc_resolve/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,6 @@ fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span {
impl_span
}

crate fn add_typo_suggestion(
err: &mut DiagnosticBuilder<'_>, suggestion: Option<TypoSuggestion>, span: Span
) -> bool {
if let 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
);
return true;
}
false
}

impl<'a> Resolver<'a> {
crate fn add_module_candidates(
&mut self,
Expand Down Expand Up @@ -641,7 +626,7 @@ impl<'a> Resolver<'a> {
let suggestion = self.early_lookup_typo_candidate(
ScopeSet::Macro(macro_kind), parent_scope, ident, is_expected
);
add_typo_suggestion(err, suggestion, ident.span);
self.add_typo_suggestion(err, suggestion, ident.span);

if macro_kind == MacroKind::Derive &&
(ident.as_str() == "Send" || ident.as_str() == "Sync") {
Expand All @@ -652,6 +637,33 @@ impl<'a> Resolver<'a> {
err.help("have you added the `#[macro_use]` on the module/import?");
}
}

crate fn add_typo_suggestion(
&self,
err: &mut DiagnosticBuilder<'_>,
suggestion: Option<TypoSuggestion>,
span: Span,
) -> bool {
if let 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| self.definitions.opt_span(def_id));
if let Some(span) = def_span {
err.span_label(span, &format!(
"similarly named {} `{}` defined here",
suggestion.res.descr(),
suggestion.candidate.as_str(),
));
}
return true;
}
false
}
}

impl<'a, 'b> ImportResolver<'a, 'b> {
Expand Down
7 changes: 4 additions & 3 deletions src/librustc_resolve/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,7 @@ function:
struct Foo { a: bool };
let f = Foo();
// error: expected function, found `Foo`
// error: expected function, tuple struct or tuple variant, found `Foo`
// `Foo` is a struct name, but this expression uses it like a function name
```
Expand All @@ -992,7 +992,8 @@ yield this error:
```compile_fail,E0423
println("");
// error: expected function, found macro `println`
// error: expected function, tuple struct or tuple variant,
// found macro `println`
// did you mean `println!(...)`? (notice the trailing `!`)
```
Expand Down Expand Up @@ -1592,7 +1593,7 @@ enum State {
fn print_on_failure(state: &State) {
match *state {
// error: expected unit struct/variant or constant, found tuple
// error: expected unit struct, unit variant or constant, found tuple
// variant `State::Failed`
State::Failed => println!("Failed"),
_ => ()
Expand Down
25 changes: 20 additions & 5 deletions src/librustc_resolve/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,21 +199,36 @@ impl<'a> PathSource<'a> {
}

fn descr_expected(self) -> &'static str {
match self {
match &self {
PathSource::Type => "type",
PathSource::Trait(_) => "trait",
PathSource::Pat => "unit struct/variant or constant",
PathSource::Pat => "unit struct, unit variant or constant",
PathSource::Struct => "struct, variant or union type",
PathSource::TupleStruct => "tuple struct/variant",
PathSource::TupleStruct => "tuple struct or tuple variant",
PathSource::TraitItem(ns) => match ns {
TypeNS => "associated type",
ValueNS => "method or associated constant",
MacroNS => bug!("associated macro"),
},
PathSource::Expr(parent) => match parent.map(|p| &p.kind) {
PathSource::Expr(parent) => match &parent.as_ref().map(|p| &p.kind) {
// "function" here means "anything callable" rather than `DefKind::Fn`,
// this is not precise but usually more helpful than just "value".
Some(&ExprKind::Call(..)) => "function",
Some(ExprKind::Call(call_expr, _)) => {
match &call_expr.kind {
ExprKind::Path(_, path) => {
let mut msg = "function";
if let Some(segment) = path.segments.iter().last() {
if let Some(c) = segment.ident.to_string().chars().next() {
if c.is_uppercase() {
msg = "function, tuple struct or tuple variant";
}
}
}
msg
}
_ => "function"
}
}
_ => "value",
},
}
Expand Down
21 changes: 11 additions & 10 deletions src/librustc_resolve/late/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
use crate::{PathResult, PathSource, Segment};
use crate::path_names_to_string;
use crate::diagnostics::{add_typo_suggestion, ImportSuggestion, TypoSuggestion};
use crate::diagnostics::{ImportSuggestion, TypoSuggestion};
use crate::late::{LateResolutionVisitor, RibKind};

use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
Expand Down Expand Up @@ -237,18 +237,19 @@ impl<'a> LateResolutionVisitor<'a, '_> {
}

// Try Levenshtein algorithm.
let levenshtein_worked = add_typo_suggestion(
&mut err, self.lookup_typo_candidate(path, ns, is_expected, span), ident_span
);
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(&mut err,
span,
source,
res,
&path_str,
&fallback_label) {
if self.smart_resolve_context_dependent_help(
&mut err,
span,
source,
res,
&path_str,
&fallback_label,
) {
return (err, candidates);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2269,7 +2269,7 @@ pub fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, vs: &'tcx [hir::Variant], i

fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span, qpath: &QPath) {
span_err!(tcx.sess, span, E0533,
"expected unit struct/variant or constant, found {} `{}`",
"expected unit struct, unit variant or constant, found {} `{}`",
res.descr(),
hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false)));
}
Expand Down
8 changes: 5 additions & 3 deletions src/librustc_typeck/check/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,9 +613,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
let report_unexpected_res = |res: Res| {
let msg = format!("expected tuple struct/variant, found {} `{}`",
res.descr(),
hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false)));
let msg = format!(
"expected tuple struct or tuple variant, found {} `{}`",
res.descr(),
hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false)),
);
let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg);
match (res, &pat.kind) {
(Res::Def(DefKind::Fn, _), _) | (Res::Def(DefKind::Method, _), _) => {
Expand Down
5 changes: 3 additions & 2 deletions src/librustc_typeck/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4346,11 +4346,12 @@ enum X {
Entry,
}
X::Entry(); // error: expected function, found `X::Entry`
X::Entry(); // error: expected function, tuple struct or tuple variant,
// found `X::Entry`
// Or even simpler:
let x = 0i32;
x(); // error: expected function, found `i32`
x(); // error: expected function, tuple struct or tuple variant, found `i32`
```
Only functions and methods can be called using `()`. Example:
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/associated-types/associated-types-eq-1.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
error[E0412]: cannot find type `A` in this scope
--> $DIR/associated-types-eq-1.rs:10:12
|
LL | fn foo2<I: Foo>(x: I) {
| - similarly named type parameter `I` defined here
LL | let _: A = x.boo();
| ^ help: a type parameter with a similar name exists: `I`

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/class-missing-self.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ impl Cat {
fn meow(&self) {
println!("Meow");
meows += 1; //~ ERROR cannot find value `meows` in this scope
sleep(); //~ ERROR cannot find function `sleep` in this scope
sleep(); //~ ERROR cannot find function `sleep` in this
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ 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`
| ----------------------^--
| | |
| | help: a struct with a similar name exists: `S`
| similarly named struct `S` defined here

warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/struct-with-invalid-const-param.rs:1:12
Expand Down
10 changes: 5 additions & 5 deletions src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,21 @@ enum ManyVariants {
}

fn result_test() {
let x = Option(1); //~ ERROR expected function, found enum
let x = Option(1); //~ ERROR expected function, tuple struct or tuple variant, found enum

if let Option(_) = x { //~ ERROR expected tuple struct/variant, found enum
if let Option(_) = x { //~ ERROR expected tuple struct or tuple variant, found enum
println!("It is OK.");
}

let y = Example::Ex(String::from("test"));

if let Example(_) = y { //~ ERROR expected tuple struct/variant, found enum
if let Example(_) = y { //~ ERROR expected tuple struct or tuple variant, found enum
println!("It is OK.");
}

let y = Void(); //~ ERROR expected function, found enum
let y = Void(); //~ ERROR expected function, tuple struct or tuple variant, found enum

let z = ManyVariants(); //~ ERROR expected function, found enum
let z = ManyVariants(); //~ ERROR expected function, tuple struct or tuple variant, found enum
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0423]: expected function, found enum `Option`
error[E0423]: expected function, tuple struct or tuple variant, found enum `Option`
--> $DIR/issue-43871-enum-instead-of-variant.rs:19:13
|
LL | let x = Option(1);
Expand All @@ -11,7 +11,7 @@ LL | let x = std::option::Option::None(1);
LL | let x = std::option::Option::Some(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0532]: expected tuple struct/variant, found enum `Option`
error[E0532]: expected tuple struct or tuple variant, found enum `Option`
--> $DIR/issue-43871-enum-instead-of-variant.rs:21:12
|
LL | if let Option(_) = x {
Expand All @@ -24,7 +24,7 @@ LL | if let std::option::Option::None(_) = x {
LL | if let std::option::Option::Some(_) = x {
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0532]: expected tuple struct/variant, found enum `Example`
error[E0532]: expected tuple struct or tuple variant, found enum `Example`
--> $DIR/issue-43871-enum-instead-of-variant.rs:27:12
|
LL | if let Example(_) = y {
Expand All @@ -37,13 +37,13 @@ LL | if let Example::Ex(_) = y {
LL | if let Example::NotEx(_) = y {
| ^^^^^^^^^^^^^^

error[E0423]: expected function, found enum `Void`
error[E0423]: expected function, tuple struct or tuple variant, found enum `Void`
--> $DIR/issue-43871-enum-instead-of-variant.rs:31:13
|
LL | let y = Void();
| ^^^^

error[E0423]: expected function, found enum `ManyVariants`
error[E0423]: expected function, tuple struct or tuple variant, found enum `ManyVariants`
--> $DIR/issue-43871-enum-instead-of-variant.rs:33:13
|
LL | let z = ManyVariants();
Expand Down
9 changes: 6 additions & 3 deletions src/test/ui/empty/empty-struct-braces-expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ enum E {

fn main() {
let e1 = Empty1; //~ ERROR expected value, found struct `Empty1`
let e1 = Empty1(); //~ ERROR expected function, found struct `Empty1`
let e1 = Empty1();
//~^ ERROR expected function, tuple struct or tuple variant, found struct `Empty1`
let e3 = E::Empty3; //~ ERROR expected value, found struct variant `E::Empty3`
let e3 = E::Empty3(); //~ ERROR expected function, found struct variant `E::Empty3`
let e3 = E::Empty3();
//~^ ERROR expected function, tuple struct or tuple variant, found struct variant `E::Empty3`

let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1`
let xe1 = XEmpty1(); //~ ERROR expected function, found struct `XEmpty1`
let xe1 = XEmpty1();
//~^ ERROR expected function, tuple struct or tuple variant, found struct `XEmpty1`
let xe3 = XE::Empty3; //~ ERROR no variant or associated item named `Empty3` found for type
let xe3 = XE::Empty3(); //~ ERROR no variant or associated item named `Empty3` found for type

Expand Down
Loading

0 comments on commit b26ddb8

Please sign in to comment.