Skip to content

Commit 9e4ed33

Browse files
committed
Suggest accessing field when code compiles with it
1 parent e32f372 commit 9e4ed33

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,6 +1661,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16611661
debug!("exp_found {:?} terr {:?}", exp_found, terr);
16621662
if let Some(exp_found) = exp_found {
16631663
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
1664+
self.suggest_field_where_appropriate(cause, &exp_found, diag);
16641665
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
16651666
}
16661667

@@ -1819,6 +1820,46 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
18191820
}
18201821
}
18211822

1823+
fn suggest_field_where_appropriate(
1824+
&self,
1825+
cause: &ObligationCause<'tcx>,
1826+
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
1827+
diag: &mut DiagnosticBuilder<'tcx>,
1828+
) {
1829+
debug!("suggest_field_where_appropriate(cause={:?}, exp_found={:?})", cause, exp_found);
1830+
if let ty::Adt(expected_def, expected_substs) = exp_found.expected.kind() {
1831+
if expected_def.is_enum() {
1832+
return;
1833+
}
1834+
1835+
if let Some((name, ty)) = expected_def
1836+
.non_enum_variant()
1837+
.fields
1838+
.iter()
1839+
.filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
1840+
.map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
1841+
.inspect(|(name, ty)| {
1842+
debug!("suggest_field_where_appropriate: name={:?}, ty={:?}", name, ty)
1843+
})
1844+
.find(|(_, ty)| ty::TyS::same_type(ty, exp_found.found))
1845+
{
1846+
if let ObligationCauseCode::Pattern { span: Some(span), .. } = cause.code {
1847+
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
1848+
diag.span_suggestion(
1849+
span,
1850+
&format!(
1851+
"you might have meant to use field `{}` of type `{}`",
1852+
name, ty
1853+
),
1854+
format!("{}.{}", snippet, name),
1855+
Applicability::MaybeIncorrect,
1856+
);
1857+
}
1858+
}
1859+
}
1860+
}
1861+
}
1862+
18221863
/// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
18231864
/// suggests it.
18241865
fn suggest_as_ref_where_appropriate(
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
struct A {
2+
b: B,
3+
}
4+
5+
enum B {
6+
Fst,
7+
Snd,
8+
}
9+
10+
fn main() {
11+
let a = A { b: B::Fst };
12+
if let B::Fst = a {};
13+
//~^ ERROR mismatched types [E0308]
14+
// note: you might have meant to use field `b` of type `B`
15+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/field-access.rs:12:12
3+
|
4+
LL | Fst,
5+
| --- unit variant defined here
6+
...
7+
LL | if let B::Fst = a {};
8+
| ^^^^^^ - this expression has type `A`
9+
| |
10+
| expected struct `A`, found enum `B`
11+
|
12+
help: you might have meant to use field `b` of type `B`
13+
|
14+
LL | if let B::Fst = a.b {};
15+
| ^^^
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)