Skip to content

Commit

Permalink
Rollup merge of #81504 - matsujika:suggestion-field-access, r=estebank
Browse files Browse the repository at this point in the history
Suggest accessing field when appropriate

Fix #81222

r? ``@estebank``
  • Loading branch information
jonas-schievink committed Feb 1, 2021
2 parents 9e8753e + f45a993 commit 853cfd4
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 0 deletions.
48 changes: 48 additions & 0 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1661,6 +1661,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
debug!("exp_found {:?} terr {:?}", exp_found, terr);
if let Some(exp_found) = exp_found {
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
}

Expand Down Expand Up @@ -1819,6 +1820,53 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}

fn suggest_accessing_field_where_appropriate(
&self,
cause: &ObligationCause<'tcx>,
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
diag: &mut DiagnosticBuilder<'tcx>,
) {
debug!(
"suggest_accessing_field_where_appropriate(cause={:?}, exp_found={:?})",
cause, exp_found
);
if let ty::Adt(expected_def, expected_substs) = exp_found.expected.kind() {
if expected_def.is_enum() {
return;
}

if let Some((name, ty)) = expected_def
.non_enum_variant()
.fields
.iter()
.filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
.map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
.find(|(_, ty)| ty::TyS::same_type(ty, exp_found.found))
{
if let ObligationCauseCode::Pattern { span: Some(span), .. } = cause.code {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
let suggestion = if expected_def.is_struct() {
format!("{}.{}", snippet, name)
} else if expected_def.is_union() {
format!("unsafe {{ {}.{} }}", snippet, name)
} else {
return;
};
diag.span_suggestion(
span,
&format!(
"you might have meant to use field `{}` of type `{}`",
name, ty
),
suggestion,
Applicability::MaybeIncorrect,
);
}
}
}
}
}

/// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
/// suggests it.
fn suggest_as_ref_where_appropriate(
Expand Down
35 changes: 35 additions & 0 deletions src/test/ui/suggestions/field-access.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// run-rustfix
#![allow(dead_code)]

struct A {
b: B,
}

enum B {
Fst,
Snd,
}

union Foo {
bar: u32,
qux: f32,
}

fn main() {
let a = A { b: B::Fst };
if let B::Fst = a.b {}; //~ ERROR mismatched types [E0308]
//~^ HELP you might have meant to use field `b` of type `B`
match a.b {
//~^ HELP you might have meant to use field `b` of type `B`
//~| HELP you might have meant to use field `b` of type `B`
B::Fst => (), //~ ERROR mismatched types [E0308]
B::Snd => (), //~ ERROR mismatched types [E0308]
}

let foo = Foo { bar: 42 };
match unsafe { foo.bar } {
//~^ HELP you might have meant to use field `bar` of type `u32`
1u32 => (), //~ ERROR mismatched types [E0308]
_ => (),
}
}
35 changes: 35 additions & 0 deletions src/test/ui/suggestions/field-access.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// run-rustfix
#![allow(dead_code)]

struct A {
b: B,
}

enum B {
Fst,
Snd,
}

union Foo {
bar: u32,
qux: f32,
}

fn main() {
let a = A { b: B::Fst };
if let B::Fst = a {}; //~ ERROR mismatched types [E0308]
//~^ HELP you might have meant to use field `b` of type `B`
match a {
//~^ HELP you might have meant to use field `b` of type `B`
//~| HELP you might have meant to use field `b` of type `B`
B::Fst => (), //~ ERROR mismatched types [E0308]
B::Snd => (), //~ ERROR mismatched types [E0308]
}

let foo = Foo { bar: 42 };
match foo {
//~^ HELP you might have meant to use field `bar` of type `u32`
1u32 => (), //~ ERROR mismatched types [E0308]
_ => (),
}
}
67 changes: 67 additions & 0 deletions src/test/ui/suggestions/field-access.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
error[E0308]: mismatched types
--> $DIR/field-access.rs:20:12
|
LL | Fst,
| --- unit variant defined here
...
LL | if let B::Fst = a {};
| ^^^^^^ - this expression has type `A`
| |
| expected struct `A`, found enum `B`
|
help: you might have meant to use field `b` of type `B`
|
LL | if let B::Fst = a.b {};
| ^^^

error[E0308]: mismatched types
--> $DIR/field-access.rs:25:9
|
LL | Fst,
| --- unit variant defined here
...
LL | match a {
| - this expression has type `A`
...
LL | B::Fst => (),
| ^^^^^^ expected struct `A`, found enum `B`
|
help: you might have meant to use field `b` of type `B`
|
LL | match a.b {
| ^^^

error[E0308]: mismatched types
--> $DIR/field-access.rs:26:9
|
LL | Snd,
| --- unit variant defined here
...
LL | match a {
| - this expression has type `A`
...
LL | B::Snd => (),
| ^^^^^^ expected struct `A`, found enum `B`
|
help: you might have meant to use field `b` of type `B`
|
LL | match a.b {
| ^^^

error[E0308]: mismatched types
--> $DIR/field-access.rs:32:9
|
LL | match foo {
| --- this expression has type `Foo`
LL |
LL | 1u32 => (),
| ^^^^ expected union `Foo`, found `u32`
|
help: you might have meant to use field `bar` of type `u32`
|
LL | match unsafe { foo.bar } {
| ^^^^^^^^^^^^^^^^^^

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0308`.

0 comments on commit 853cfd4

Please sign in to comment.