From b946ecd02018d1671c990057d7136176df60da35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 23 Mar 2017 15:14:45 -0700 Subject: [PATCH 1/3] Suggest using enum when a variant is used as a type Given a file: ```rust enum Fruit { Apple(i64), Orange(i64), } fn should_return_fruit() -> Apple { Apple(5) } ``` Provide the following output: ```rust error[E0412]: cannot find type `Apple` in this scope --> file.rs:16:29 | 16 | fn should_return_fruit() -> Apple { | ^^^^^ not found in this scope | help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? --> file.rs:12:5 | 12 | Apple(i64), | ^^^^^^^^^^ error[E0425]: cannot find function `Apple` in this scope --> file.rs:17:5 | 17 | Apple(5) | ^^^^^ not found in this scope | = help: possible candidate is found in another module, you can import it into scope: `use Fruit::Apple;` ``` --- src/librustc_resolve/lib.rs | 30 +++++++++ src/test/ui/did_you_mean/issue-35675.rs | 44 ++++++++++++ src/test/ui/did_you_mean/issue-35675.stderr | 74 +++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 src/test/ui/did_you_mean/issue-35675.rs create mode 100644 src/test/ui/did_you_mean/issue-35675.stderr diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0466e76475da3..a39cd3b0d551c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2220,6 +2220,7 @@ impl<'a> Resolver<'a> { -> PathResolution { let ns = source.namespace(); let is_expected = &|def| source.is_expected(def); + let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false }; // Base error is amended with one short label and possibly some longer helps/notes. let report_errors = |this: &mut Self, def: Option| { @@ -2270,6 +2271,19 @@ impl<'a> Resolver<'a> { if !candidates.is_empty() { // Report import candidates as help and proceed searching for labels. show_candidates(&mut err, &candidates, def.is_some()); + } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { + let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant); + for suggestion in enum_candidates { + let (variant_path, enum_path) = import_candidate_to_paths(&suggestion); + let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?", + variant_path, + enum_path); + if suggestion.path.span == DUMMY_SP { + err.help(&msg); + } else { + err.span_help(suggestion.path.span, &msg); + } + } } if path.len() == 1 && this.self_type_is_available() { if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) { @@ -3422,6 +3436,22 @@ fn path_names_to_string(path: &Path) -> String { names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::>()) } +/// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant. +fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) { + let variant_path = &suggestion.path; + let variant_path_string = path_names_to_string(variant_path); + + let path_len = suggestion.path.segments.len(); + let enum_path = ast::Path { + span: suggestion.path.span, + segments: suggestion.path.segments[0..path_len - 1].to_vec(), + }; + let enum_path_string = path_names_to_string(&enum_path); + + (variant_path_string, enum_path_string) +} + + /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way diff --git a/src/test/ui/did_you_mean/issue-35675.rs b/src/test/ui/did_you_mean/issue-35675.rs new file mode 100644 index 0000000000000..ff29f3ad4078b --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35675.rs @@ -0,0 +1,44 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Fruit { + Apple(i64), + Orange(i64), +} + +fn should_return_fruit() -> Apple { + Apple(5) +} + +fn should_return_fruit_too() -> Fruit::Apple { + Apple(5) +} + +fn foo() -> Ok { + Ok(()) +} + +fn bar() -> Variant3 { +} + +fn qux() -> Some { + Some(1) +} + +fn main() {} + +mod x { + enum Enum { + Variant1, + Variant2(), + Variant3(usize), + Variant4 {}, + } +} diff --git a/src/test/ui/did_you_mean/issue-35675.stderr b/src/test/ui/did_you_mean/issue-35675.stderr new file mode 100644 index 0000000000000..43851d76029df --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35675.stderr @@ -0,0 +1,74 @@ +error[E0412]: cannot find type `Apple` in this scope + --> $DIR/issue-35675.rs:16:29 + | +16 | fn should_return_fruit() -> Apple { + | ^^^^^ not found in this scope + | +help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + --> $DIR/issue-35675.rs:12:5 + | +12 | Apple(i64), + | ^^^^^^^^^^ + +error[E0425]: cannot find function `Apple` in this scope + --> $DIR/issue-35675.rs:17:5 + | +17 | Apple(5) + | ^^^^^ not found in this scope + | + = help: possible candidate is found in another module, you can import it into scope: + `use Fruit::Apple;` + +error[E0573]: expected type, found variant `Fruit::Apple` + --> $DIR/issue-35675.rs:20:33 + | +20 | fn should_return_fruit_too() -> Fruit::Apple { + | ^^^^^^^^^^^^ not a type + | +help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + --> $DIR/issue-35675.rs:12:5 + | +12 | Apple(i64), + | ^^^^^^^^^^ + +error[E0425]: cannot find function `Apple` in this scope + --> $DIR/issue-35675.rs:21:5 + | +21 | Apple(5) + | ^^^^^ not found in this scope + | + = help: possible candidate is found in another module, you can import it into scope: + `use Fruit::Apple;` + +error[E0573]: expected type, found variant `Ok` + --> $DIR/issue-35675.rs:24:13 + | +24 | fn foo() -> Ok { + | ^^ not a type + | + = help: there is an enum variant `std::result::Result::Ok`, did you mean to use `std::result::Result`? + = help: there is an enum variant `std::prelude::v1::Ok`, did you mean to use `std::prelude::v1`? + +error[E0412]: cannot find type `Variant3` in this scope + --> $DIR/issue-35675.rs:28:13 + | +28 | fn bar() -> Variant3 { + | ^^^^^^^^ not found in this scope + | +help: there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`? + --> $DIR/issue-35675.rs:41:9 + | +41 | Variant3(usize), + | ^^^^^^^^^^^^^^^ + +error[E0573]: expected type, found variant `Some` + --> $DIR/issue-35675.rs:31:13 + | +31 | fn qux() -> Some { + | ^^^^ not a type + | + = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? + = help: there is an enum variant `std::prelude::v1::Option::Some`, did you mean to use `std::prelude::v1::Option`? + +error: aborting due to 7 previous errors + From 73f6f5e0968ebe032a0730e2e3dfccea5a61c384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 3 Apr 2017 07:46:35 -0700 Subject: [PATCH 2/3] Sort enum suggestions --- src/librustc_resolve/lib.rs | 14 ++++++++------ src/test/ui/did_you_mean/issue-35675.stderr | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a39cd3b0d551c..e191fadc01beb 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2273,15 +2273,17 @@ impl<'a> Resolver<'a> { show_candidates(&mut err, &candidates, def.is_some()); } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant); - for suggestion in enum_candidates { - let (variant_path, enum_path) = import_candidate_to_paths(&suggestion); + let mut enum_candidates = enum_candidates.iter() + .map(|suggestion| import_candidate_to_paths(&suggestion)).collect::>(); + enum_candidates.sort(); + for (sp, variant_path, enum_path) in enum_candidates { let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?", variant_path, enum_path); - if suggestion.path.span == DUMMY_SP { + if sp == DUMMY_SP { err.help(&msg); } else { - err.span_help(suggestion.path.span, &msg); + err.span_help(sp, &msg); } } } @@ -3437,7 +3439,7 @@ fn path_names_to_string(path: &Path) -> String { } /// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant. -fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) { +fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, String) { let variant_path = &suggestion.path; let variant_path_string = path_names_to_string(variant_path); @@ -3448,7 +3450,7 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) }; let enum_path_string = path_names_to_string(&enum_path); - (variant_path_string, enum_path_string) + (suggestion.path.span, variant_path_string, enum_path_string) } diff --git a/src/test/ui/did_you_mean/issue-35675.stderr b/src/test/ui/did_you_mean/issue-35675.stderr index 43851d76029df..3d615785b25fa 100644 --- a/src/test/ui/did_you_mean/issue-35675.stderr +++ b/src/test/ui/did_you_mean/issue-35675.stderr @@ -46,8 +46,8 @@ error[E0573]: expected type, found variant `Ok` 24 | fn foo() -> Ok { | ^^ not a type | - = help: there is an enum variant `std::result::Result::Ok`, did you mean to use `std::result::Result`? = help: there is an enum variant `std::prelude::v1::Ok`, did you mean to use `std::prelude::v1`? + = help: there is an enum variant `std::prelude::v1::Result::Ok`, did you mean to use `std::prelude::v1::Result`? error[E0412]: cannot find type `Variant3` in this scope --> $DIR/issue-35675.rs:28:13 @@ -67,8 +67,8 @@ error[E0573]: expected type, found variant `Some` 31 | fn qux() -> Some { | ^^^^ not a type | - = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? = help: there is an enum variant `std::prelude::v1::Option::Some`, did you mean to use `std::prelude::v1::Option`? + = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? error: aborting due to 7 previous errors From 2b2eeda0831401935a45c70667cf4c3eaedafe7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 7 Apr 2017 16:08:07 -0700 Subject: [PATCH 3/3] Move tests from ui to cfail --- src/test/compile-fail/issue-35675.rs | 67 +++++++++++++++++++ src/test/ui/did_you_mean/issue-35675.rs | 44 ------------ src/test/ui/did_you_mean/issue-35675.stderr | 74 --------------------- 3 files changed, 67 insertions(+), 118 deletions(-) create mode 100644 src/test/compile-fail/issue-35675.rs delete mode 100644 src/test/ui/did_you_mean/issue-35675.rs delete mode 100644 src/test/ui/did_you_mean/issue-35675.stderr diff --git a/src/test/compile-fail/issue-35675.rs b/src/test/compile-fail/issue-35675.rs new file mode 100644 index 0000000000000..f990c2c42fe14 --- /dev/null +++ b/src/test/compile-fail/issue-35675.rs @@ -0,0 +1,67 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Fruit { + Apple(i64), + //~^ HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + //~| HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + Orange(i64), +} + +fn should_return_fruit() -> Apple { + //~^ ERROR cannot find type `Apple` in this scope + //~| NOTE not found in this scope + Apple(5) + //~^ ERROR cannot find function `Apple` in this scope + //~| NOTE not found in this scope + //~| HELP possible candidate is found in another module, you can import it into scope +} + +fn should_return_fruit_too() -> Fruit::Apple { + //~^ ERROR expected type, found variant `Fruit::Apple` + //~| NOTE not a type + Apple(5) + //~^ ERROR cannot find function `Apple` in this scope + //~| NOTE not found in this scope + //~| HELP possible candidate is found in another module, you can import it into scope +} + +fn foo() -> Ok { + //~^ ERROR expected type, found variant `Ok` + //~| NOTE not a type + //~| HELP there is an enum variant + //~| HELP there is an enum variant + Ok(()) +} + +fn bar() -> Variant3 { + //~^ ERROR cannot find type `Variant3` in this scope + //~| NOTE not found in this scope +} + +fn qux() -> Some { + //~^ ERROR expected type, found variant `Some` + //~| NOTE not a type + //~| HELP there is an enum variant + //~| HELP there is an enum variant + Some(1) +} + +fn main() {} + +mod x { + enum Enum { + Variant1, + Variant2(), + Variant3(usize), + //~^ HELP there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`? + Variant4 {}, + } +} diff --git a/src/test/ui/did_you_mean/issue-35675.rs b/src/test/ui/did_you_mean/issue-35675.rs deleted file mode 100644 index ff29f3ad4078b..0000000000000 --- a/src/test/ui/did_you_mean/issue-35675.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -enum Fruit { - Apple(i64), - Orange(i64), -} - -fn should_return_fruit() -> Apple { - Apple(5) -} - -fn should_return_fruit_too() -> Fruit::Apple { - Apple(5) -} - -fn foo() -> Ok { - Ok(()) -} - -fn bar() -> Variant3 { -} - -fn qux() -> Some { - Some(1) -} - -fn main() {} - -mod x { - enum Enum { - Variant1, - Variant2(), - Variant3(usize), - Variant4 {}, - } -} diff --git a/src/test/ui/did_you_mean/issue-35675.stderr b/src/test/ui/did_you_mean/issue-35675.stderr deleted file mode 100644 index 3d615785b25fa..0000000000000 --- a/src/test/ui/did_you_mean/issue-35675.stderr +++ /dev/null @@ -1,74 +0,0 @@ -error[E0412]: cannot find type `Apple` in this scope - --> $DIR/issue-35675.rs:16:29 - | -16 | fn should_return_fruit() -> Apple { - | ^^^^^ not found in this scope - | -help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? - --> $DIR/issue-35675.rs:12:5 - | -12 | Apple(i64), - | ^^^^^^^^^^ - -error[E0425]: cannot find function `Apple` in this scope - --> $DIR/issue-35675.rs:17:5 - | -17 | Apple(5) - | ^^^^^ not found in this scope - | - = help: possible candidate is found in another module, you can import it into scope: - `use Fruit::Apple;` - -error[E0573]: expected type, found variant `Fruit::Apple` - --> $DIR/issue-35675.rs:20:33 - | -20 | fn should_return_fruit_too() -> Fruit::Apple { - | ^^^^^^^^^^^^ not a type - | -help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? - --> $DIR/issue-35675.rs:12:5 - | -12 | Apple(i64), - | ^^^^^^^^^^ - -error[E0425]: cannot find function `Apple` in this scope - --> $DIR/issue-35675.rs:21:5 - | -21 | Apple(5) - | ^^^^^ not found in this scope - | - = help: possible candidate is found in another module, you can import it into scope: - `use Fruit::Apple;` - -error[E0573]: expected type, found variant `Ok` - --> $DIR/issue-35675.rs:24:13 - | -24 | fn foo() -> Ok { - | ^^ not a type - | - = help: there is an enum variant `std::prelude::v1::Ok`, did you mean to use `std::prelude::v1`? - = help: there is an enum variant `std::prelude::v1::Result::Ok`, did you mean to use `std::prelude::v1::Result`? - -error[E0412]: cannot find type `Variant3` in this scope - --> $DIR/issue-35675.rs:28:13 - | -28 | fn bar() -> Variant3 { - | ^^^^^^^^ not found in this scope - | -help: there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`? - --> $DIR/issue-35675.rs:41:9 - | -41 | Variant3(usize), - | ^^^^^^^^^^^^^^^ - -error[E0573]: expected type, found variant `Some` - --> $DIR/issue-35675.rs:31:13 - | -31 | fn qux() -> Some { - | ^^^^ not a type - | - = help: there is an enum variant `std::prelude::v1::Option::Some`, did you mean to use `std::prelude::v1::Option`? - = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? - -error: aborting due to 7 previous errors -