Skip to content

Commit 39ca644

Browse files
authored
Rollup merge of rust-lang#67741 - estebank:point-at-pat-def, r=Centril
When encountering an Item in a pat context, point at the item def ``` error[E0308]: mismatched types --> $DIR/const-in-struct-pat.rs:8:17 | LL | struct foo; | ----------- `foo` defined here ... LL | let Thing { foo } = t; | ^^^ expected struct `std::string::String`, found struct `foo` | = note: `foo` is interpreted as a unit struct, not a new binding help: you can bind the struct field to a different name | LL | let Thing { foo: other_foo } = t; | ^^^^^^^^^^^^^^ ``` ``` error[E0308]: mismatched types --> $DIR/const.rs:14:9 | LL | const FOO: Foo = Foo{bar: 5}; | ----------------------------- constant defined here ... LL | FOO => {}, | ^^^ | | | expected `&Foo`, found struct `Foo` | `FOO` is interpreted as a constant, not a new binding | help: use different name to introduce a new binding: `other_foo` ``` Fix rust-lang#55631, fix rust-lang#48062, cc rust-lang#42876.
2 parents 2890b37 + 125159f commit 39ca644

File tree

10 files changed

+147
-28
lines changed

10 files changed

+147
-28
lines changed

src/librustc_typeck/check/pat.rs

+79-24
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,22 @@ struct TopInfo<'tcx> {
6363
/// found type `std::result::Result<_, _>`
6464
/// ```
6565
span: Option<Span>,
66+
/// This refers to the parent pattern. Used to provide extra diagnostic information on errors.
67+
/// ```text
68+
/// error[E0308]: mismatched types
69+
/// --> $DIR/const-in-struct-pat.rs:8:17
70+
/// |
71+
/// L | struct f;
72+
/// | --------- unit struct defined here
73+
/// ...
74+
/// L | let Thing { f } = t;
75+
/// | ^
76+
/// | |
77+
/// | expected struct `std::string::String`, found struct `f`
78+
/// | `f` is interpreted as a unit struct, not a new binding
79+
/// | help: bind the struct field to a different name instead: `f: other_f`
80+
/// ```
81+
parent_pat: Option<&'tcx Pat<'tcx>>,
6682
}
6783

6884
impl<'tcx> FnCtxt<'_, 'tcx> {
@@ -120,7 +136,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
120136
span: Option<Span>,
121137
origin_expr: bool,
122138
) {
123-
self.check_pat(pat, expected, INITIAL_BM, TopInfo { expected, origin_expr, span });
139+
let info = TopInfo { expected, origin_expr, span, parent_pat: None };
140+
self.check_pat(pat, expected, INITIAL_BM, info);
124141
}
125142

126143
/// Type check the given `pat` against the `expected` type
@@ -161,8 +178,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
161178
self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti)
162179
}
163180
PatKind::Or(pats) => {
181+
let parent_pat = Some(pat);
164182
for pat in pats {
165-
self.check_pat(pat, expected, def_bm, ti);
183+
self.check_pat(pat, expected, def_bm, TopInfo { parent_pat, ..ti });
166184
}
167185
expected
168186
}
@@ -501,7 +519,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
501519

502520
fn check_pat_ident(
503521
&self,
504-
pat: &Pat<'_>,
522+
pat: &'tcx Pat<'tcx>,
505523
ba: hir::BindingAnnotation,
506524
var_id: HirId,
507525
sub: Option<&'tcx Pat<'tcx>>,
@@ -546,7 +564,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
546564
}
547565

548566
if let Some(p) = sub {
549-
self.check_pat(&p, expected, def_bm, ti);
567+
self.check_pat(&p, expected, def_bm, TopInfo { parent_pat: Some(&pat), ..ti });
550568
}
551569

552570
local_ty
@@ -647,6 +665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
647665
variant_ty
648666
} else {
649667
for field in fields {
668+
let ti = TopInfo { parent_pat: Some(&pat), ..ti };
650669
self.check_pat(&field.pat, self.tcx.types.err, def_bm, ti);
651670
}
652671
return self.tcx.types.err;
@@ -656,9 +675,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
656675
self.demand_eqtype_pat(pat.span, expected, pat_ty, ti);
657676

658677
// Type-check subpatterns.
659-
if self
660-
.check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm, ti)
661-
{
678+
if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, etc, def_bm, ti) {
662679
pat_ty
663680
} else {
664681
self.tcx.types.err
@@ -696,18 +713,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
696713
}
697714

698715
// Type-check the path.
699-
let pat_ty = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id).0;
700-
if let Some(mut err) =
716+
let (pat_ty, pat_res) =
717+
self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id);
718+
if let Some(err) =
701719
self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty)
702720
{
703-
err.emit();
721+
self.emit_bad_pat_path(err, pat.span, res, pat_res, segments, ti.parent_pat);
704722
}
705723
pat_ty
706724
}
707725

726+
fn emit_bad_pat_path(
727+
&self,
728+
mut e: DiagnosticBuilder<'_>,
729+
pat_span: Span,
730+
res: Res,
731+
pat_res: Res,
732+
segments: &'b [hir::PathSegment<'b>],
733+
parent_pat: Option<&Pat<'_>>,
734+
) {
735+
if let Some(span) = self.tcx.hir().res_span(pat_res) {
736+
e.span_label(span, &format!("{} defined here", res.descr()));
737+
if let [hir::PathSegment { ident, .. }] = &*segments {
738+
e.span_label(
739+
pat_span,
740+
&format!(
741+
"`{}` is interpreted as {} {}, not a new binding",
742+
ident,
743+
res.article(),
744+
res.descr(),
745+
),
746+
);
747+
let (msg, sugg) = match parent_pat {
748+
Some(Pat { kind: hir::PatKind::Struct(..), .. }) => (
749+
"bind the struct field to a different name instead",
750+
format!("{}: other_{}", ident, ident.as_str().to_lowercase()),
751+
),
752+
_ => (
753+
"introduce a new binding instead",
754+
format!("other_{}", ident.as_str().to_lowercase()),
755+
),
756+
};
757+
e.span_suggestion(ident.span, msg, sugg, Applicability::HasPlaceholders);
758+
}
759+
}
760+
e.emit();
761+
}
762+
708763
fn check_pat_tuple_struct(
709764
&self,
710-
pat: &Pat<'_>,
765+
pat: &'tcx Pat<'tcx>,
711766
qpath: &hir::QPath<'_>,
712767
subpats: &'tcx [&'tcx Pat<'tcx>],
713768
ddpos: Option<usize>,
@@ -717,8 +772,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
717772
) -> Ty<'tcx> {
718773
let tcx = self.tcx;
719774
let on_error = || {
775+
let parent_pat = Some(pat);
720776
for pat in subpats {
721-
self.check_pat(&pat, tcx.types.err, def_bm, ti);
777+
self.check_pat(&pat, tcx.types.err, def_bm, TopInfo { parent_pat, ..ti });
722778
}
723779
};
724780
let report_unexpected_res = |res: Res| {
@@ -793,7 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
793849
};
794850
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
795851
let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs);
796-
self.check_pat(&subpat, field_ty, def_bm, ti);
852+
self.check_pat(&subpat, field_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti });
797853

798854
self.tcx.check_stability(variant.fields[i].did, Some(pat.hir_id), subpat.span);
799855
}
@@ -938,8 +994,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
938994
fn check_struct_pat_fields(
939995
&self,
940996
adt_ty: Ty<'tcx>,
941-
pat_id: HirId,
942-
span: Span,
997+
pat: &'tcx Pat<'tcx>,
943998
variant: &'tcx ty::VariantDef,
944999
fields: &'tcx [hir::FieldPat<'tcx>],
9451000
etc: bool,
@@ -950,7 +1005,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9501005

9511006
let (substs, adt) = match adt_ty.kind {
9521007
ty::Adt(adt, substs) => (substs, adt),
953-
_ => span_bug!(span, "struct pattern is not an ADT"),
1008+
_ => span_bug!(pat.span, "struct pattern is not an ADT"),
9541009
};
9551010
let kind_name = adt.variant_descr();
9561011

@@ -983,7 +1038,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9831038
.get(&ident)
9841039
.map(|(i, f)| {
9851040
self.write_field_index(field.hir_id, *i);
986-
self.tcx.check_stability(f.did, Some(pat_id), span);
1041+
self.tcx.check_stability(f.did, Some(pat.hir_id), span);
9871042
self.field_ty(span, f, substs)
9881043
})
9891044
.unwrap_or_else(|| {
@@ -994,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9941049
}
9951050
};
9961051

997-
self.check_pat(&field.pat, field_ty, def_bm, ti);
1052+
self.check_pat(&field.pat, field_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti });
9981053
}
9991054

10001055
let mut unmentioned_fields = variant
@@ -1017,7 +1072,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10171072
if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc {
10181073
struct_span_err!(
10191074
tcx.sess,
1020-
span,
1075+
pat.span,
10211076
E0638,
10221077
"`..` required with {} marked as non-exhaustive",
10231078
kind_name
@@ -1029,14 +1084,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10291084
if kind_name == "union" {
10301085
if fields.len() != 1 {
10311086
tcx.sess
1032-
.struct_span_err(span, "union patterns should have exactly one field")
1087+
.struct_span_err(pat.span, "union patterns should have exactly one field")
10331088
.emit();
10341089
}
10351090
if etc {
1036-
tcx.sess.struct_span_err(span, "`..` cannot be used in union patterns").emit();
1091+
tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
10371092
}
10381093
} else if !etc && !unmentioned_fields.is_empty() {
1039-
self.error_unmentioned_fields(span, &unmentioned_fields, variant);
1094+
self.error_unmentioned_fields(pat.span, &unmentioned_fields, variant);
10401095
}
10411096
no_field_errors
10421097
}
@@ -1196,7 +1251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11961251

11971252
fn check_pat_ref(
11981253
&self,
1199-
pat: &Pat<'_>,
1254+
pat: &'tcx Pat<'tcx>,
12001255
inner: &'tcx Pat<'tcx>,
12011256
mutbl: hir::Mutability,
12021257
expected: Ty<'tcx>,
@@ -1236,7 +1291,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12361291
} else {
12371292
(tcx.types.err, tcx.types.err)
12381293
};
1239-
self.check_pat(&inner, inner_ty, def_bm, ti);
1294+
self.check_pat(&inner, inner_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti });
12401295
rptr_ty
12411296
}
12421297

src/test/ui/blind/blind-item-block-middle.stderr

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
error[E0308]: mismatched types
22
--> $DIR/blind-item-block-middle.rs:6:9
33
|
4+
LL | mod foo { pub struct bar; }
5+
| --------------- unit struct defined here
6+
...
47
LL | let bar = 5;
5-
| ^^^ expected integer, found struct `foo::bar`
8+
| ^^^
9+
| |
10+
| expected integer, found struct `foo::bar`
11+
| `bar` is interpreted as a unit struct, not a new binding
12+
| help: introduce a new binding instead: `other_bar`
613

714
error: aborting due to previous error
815

src/test/ui/issues/issue-33504.stderr

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
error[E0308]: mismatched types
22
--> $DIR/issue-33504.rs:7:13
33
|
4+
LL | struct Test;
5+
| ------------ unit struct defined here
6+
...
47
LL | let Test = 1;
5-
| ^^^^ expected integer, found struct `Test`
8+
| ^^^^
9+
| |
10+
| expected integer, found struct `Test`
11+
| `Test` is interpreted as a unit struct, not a new binding
12+
| help: introduce a new binding instead: `other_test`
613

714
error: aborting due to previous error
815

src/test/ui/issues/issue-4968.stderr

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
error[E0308]: mismatched types
22
--> $DIR/issue-4968.rs:5:16
33
|
4+
LL | const A: (isize,isize) = (4,2);
5+
| ------------------------------- constant defined here
6+
LL | fn main() {
47
LL | match 42 { A => () }
5-
| ^ expected integer, found tuple
8+
| ^
9+
| |
10+
| expected integer, found tuple
11+
| `A` is interpreted as a constant, not a new binding
12+
| help: introduce a new binding instead: `other_a`
613
|
714
= note: expected type `{integer}`
815
found tuple `(isize, isize)`

src/test/ui/issues/issue-5100.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0308]: mismatched types
22
--> $DIR/issue-5100.rs:8:9
33
|
4+
LL | enum A { B, C }
5+
| - unit variant defined here
6+
...
47
LL | match (true, false) {
58
| ------------- this expression has type `(bool, bool)`
69
LL | A::B => (),

src/test/ui/issues/issue-7867.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0308]: mismatched types
22
--> $DIR/issue-7867.rs:7:9
33
|
4+
LL | enum A { B, C }
5+
| - unit variant defined here
6+
...
47
LL | match (true, false) {
58
| ------------- this expression has type `(bool, bool)`
69
LL | A::B => (),

src/test/ui/match/match-tag-nullary.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0308]: mismatched types
22
--> $DIR/match-tag-nullary.rs:4:40
33
|
4+
LL | enum B { B }
5+
| - unit variant defined here
6+
LL |
47
LL | fn main() { let x: A = A::A; match x { B::B => { } } }
58
| - ^^^^ expected enum `A`, found enum `B`
69
| |

src/test/ui/rfc-2005-default-binding-mode/const.stderr

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
error[E0308]: mismatched types
22
--> $DIR/const.rs:14:9
33
|
4+
LL | const FOO: Foo = Foo{bar: 5};
5+
| ----------------------------- constant defined here
6+
...
47
LL | match &f {
58
| -- this expression has type `&Foo`
69
LL | FOO => {},
7-
| ^^^ expected `&Foo`, found struct `Foo`
10+
| ^^^
11+
| |
12+
| expected `&Foo`, found struct `Foo`
13+
| `FOO` is interpreted as a constant, not a new binding
14+
| help: introduce a new binding instead: `other_foo`
815

916
error: aborting due to previous error
1017

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[allow(non_camel_case_types)]
2+
struct foo;
3+
struct Thing {
4+
foo: String,
5+
}
6+
7+
fn example(t: Thing) {
8+
let Thing { foo } = t; //~ ERROR mismatched types
9+
}
10+
11+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/const-in-struct-pat.rs:8:17
3+
|
4+
LL | struct foo;
5+
| ----------- unit struct defined here
6+
...
7+
LL | let Thing { foo } = t;
8+
| ^^^ - this expression has type `Thing`
9+
| |
10+
| expected struct `std::string::String`, found struct `foo`
11+
| `foo` is interpreted as a unit struct, not a new binding
12+
| help: bind the struct field to a different name instead: `foo: other_foo`
13+
14+
error: aborting due to previous error
15+
16+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)