Skip to content

Commit

Permalink
Rollup merge of rust-lang#40775 - estebank:variant-as-type, r=petroch…
Browse files Browse the repository at this point in the history
…enkov

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;`
```

Fix rust-lang#35675.
  • Loading branch information
frewsxcv authored Apr 5, 2017
2 parents a276d9c + 73f6f5e commit 4408748
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Def>| {
Expand Down Expand Up @@ -2270,6 +2271,21 @@ 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);
let mut enum_candidates = enum_candidates.iter()
.map(|suggestion| import_candidate_to_paths(&suggestion)).collect::<Vec<_>>();
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 sp == DUMMY_SP {
err.help(&msg);
} else {
err.span_help(sp, &msg);
}
}
}
if path.len() == 1 && this.self_type_is_available() {
if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) {
Expand Down Expand Up @@ -3422,6 +3438,22 @@ fn path_names_to_string(path: &Path) -> String {
names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>())
}

/// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant.
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);

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);

(suggestion.path.span, 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
Expand Down
44 changes: 44 additions & 0 deletions src/test/ui/did_you_mean/issue-35675.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 {},
}
}
74 changes: 74 additions & 0 deletions src/test/ui/did_you_mean/issue-35675.stderr
Original file line number Diff line number Diff line change
@@ -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::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

0 comments on commit 4408748

Please sign in to comment.