Skip to content

Commit a245221

Browse files
authoredFeb 28, 2020
Rollup merge of #69452 - Centril:typeck-pat, r=estebank
typeck: use `Pattern` obligation cause more for better diagnostics r? @estebank
2 parents 3828fa2 + d234e13 commit a245221

28 files changed

+284
-102
lines changed
 

‎src/librustc/hir/map/mod.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -153,17 +153,13 @@ pub struct Map<'hir> {
153153
hir_to_node_id: FxHashMap<HirId, NodeId>,
154154
}
155155

156-
struct ParentHirIterator<'map, 'hir> {
156+
/// An iterator that walks up the ancestor tree of a given `HirId`.
157+
/// Constructed using `tcx.hir().parent_iter(hir_id)`.
158+
pub struct ParentHirIterator<'map, 'hir> {
157159
current_id: HirId,
158160
map: &'map Map<'hir>,
159161
}
160162

161-
impl<'map, 'hir> ParentHirIterator<'map, 'hir> {
162-
fn new(current_id: HirId, map: &'map Map<'hir>) -> Self {
163-
Self { current_id, map }
164-
}
165-
}
166-
167163
impl<'hir> Iterator for ParentHirIterator<'_, 'hir> {
168164
type Item = (HirId, Node<'hir>);
169165

@@ -618,6 +614,12 @@ impl<'hir> Map<'hir> {
618614
self.find_entry(hir_id).and_then(|x| x.parent_node()).unwrap_or(hir_id)
619615
}
620616

617+
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
618+
/// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
619+
pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> {
620+
ParentHirIterator { current_id, map: self }
621+
}
622+
621623
/// Checks if the node is an argument. An argument is a local variable whose
622624
/// immediate parent is an item or a closure.
623625
pub fn is_argument(&self, id: HirId) -> bool {
@@ -684,7 +686,7 @@ impl<'hir> Map<'hir> {
684686
/// }
685687
/// ```
686688
pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
687-
let mut iter = ParentHirIterator::new(id, &self).peekable();
689+
let mut iter = self.parent_iter(id).peekable();
688690
let mut ignore_tail = false;
689691
if let Some(entry) = self.find_entry(id) {
690692
if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = entry.node {
@@ -731,7 +733,7 @@ impl<'hir> Map<'hir> {
731733
/// in the HIR which is recorded by the map and is an item, either an item
732734
/// in a module, trait, or impl.
733735
pub fn get_parent_item(&self, hir_id: HirId) -> HirId {
734-
for (hir_id, node) in ParentHirIterator::new(hir_id, &self) {
736+
for (hir_id, node) in self.parent_iter(hir_id) {
735737
match node {
736738
Node::Crate
737739
| Node::Item(_)
@@ -753,7 +755,7 @@ impl<'hir> Map<'hir> {
753755
/// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
754756
/// module parent is in this map.
755757
pub fn get_module_parent_node(&self, hir_id: HirId) -> HirId {
756-
for (hir_id, node) in ParentHirIterator::new(hir_id, &self) {
758+
for (hir_id, node) in self.parent_iter(hir_id) {
757759
if let Node::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
758760
return hir_id;
759761
}
@@ -767,7 +769,7 @@ impl<'hir> Map<'hir> {
767769
/// Used by error reporting when there's a type error in a match arm caused by the `match`
768770
/// expression needing to be unit.
769771
pub fn get_match_if_cause(&self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
770-
for (_, node) in ParentHirIterator::new(hir_id, &self) {
772+
for (_, node) in self.parent_iter(hir_id) {
771773
match node {
772774
Node::Item(_) | Node::ForeignItem(_) | Node::TraitItem(_) | Node::ImplItem(_) => {
773775
break;
@@ -788,7 +790,7 @@ impl<'hir> Map<'hir> {
788790

789791
/// Returns the nearest enclosing scope. A scope is roughly an item or block.
790792
pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
791-
for (hir_id, node) in ParentHirIterator::new(hir_id, &self) {
793+
for (hir_id, node) in self.parent_iter(hir_id) {
792794
if match node {
793795
Node::Item(i) => match i.kind {
794796
ItemKind::Fn(..)

‎src/librustc_typeck/check/demand.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4343
expected: Ty<'tcx>,
4444
actual: Ty<'tcx>,
4545
) -> Option<DiagnosticBuilder<'tcx>> {
46-
let cause = &self.misc(sp);
46+
self.demand_suptype_with_origin(&self.misc(sp), expected, actual)
47+
}
48+
49+
pub fn demand_suptype_with_origin(
50+
&self,
51+
cause: &ObligationCause<'tcx>,
52+
expected: Ty<'tcx>,
53+
actual: Ty<'tcx>,
54+
) -> Option<DiagnosticBuilder<'tcx>> {
4755
match self.at(cause, self.param_env).sup(expected, actual) {
4856
Ok(InferOk { obligations, value: () }) => {
4957
self.register_predicates(obligations);

‎src/librustc_typeck/check/pat.rs

+39-22
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
99
use rustc_hir::{HirId, Pat, PatKind};
1010
use rustc_infer::infer;
1111
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
12-
use rustc_infer::traits::Pattern;
12+
use rustc_infer::traits::{ObligationCause, Pattern};
1313
use rustc_span::hygiene::DesugaringKind;
14-
use rustc_span::Span;
14+
use rustc_span::source_map::{Span, Spanned};
1515
use syntax::ast;
1616
use syntax::util::lev_distance::find_best_match_for_name;
1717

@@ -66,16 +66,19 @@ struct TopInfo<'tcx> {
6666
}
6767

6868
impl<'tcx> FnCtxt<'_, 'tcx> {
69+
fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
70+
let code = Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr };
71+
self.cause(cause_span, code)
72+
}
73+
6974
fn demand_eqtype_pat_diag(
7075
&self,
7176
cause_span: Span,
7277
expected: Ty<'tcx>,
7378
actual: Ty<'tcx>,
7479
ti: TopInfo<'tcx>,
7580
) -> Option<DiagnosticBuilder<'tcx>> {
76-
let code = Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr };
77-
let cause = self.cause(cause_span, code);
78-
self.demand_eqtype_with_origin(&cause, expected, actual)
81+
self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)
7982
}
8083

8184
fn demand_eqtype_pat(
@@ -152,7 +155,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
152155
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti)
153156
}
154157
PatKind::Path(ref qpath) => {
155-
self.check_pat_path(pat, path_res.unwrap(), qpath, expected)
158+
self.check_pat_path(pat, path_res.unwrap(), qpath, expected, ti)
156159
}
157160
PatKind::Struct(ref qpath, fields, etc) => {
158161
self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti)
@@ -361,16 +364,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
361364
// Byte string patterns behave the same way as array patterns
362365
// They can denote both statically and dynamically-sized byte arrays.
363366
let mut pat_ty = ty;
364-
if let hir::ExprKind::Lit(ref lt) = lt.kind {
365-
if let ast::LitKind::ByteStr(_) = lt.node {
366-
let expected_ty = self.structurally_resolved_type(span, expected);
367-
if let ty::Ref(_, r_ty, _) = expected_ty.kind {
368-
if let ty::Slice(_) = r_ty.kind {
369-
let tcx = self.tcx;
370-
pat_ty =
371-
tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8));
372-
}
373-
}
367+
if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(_), .. }) = lt.kind {
368+
let expected = self.structurally_resolved_type(span, expected);
369+
if let ty::Ref(_, ty::TyS { kind: ty::Slice(_), .. }, _) = expected.kind {
370+
let tcx = self.tcx;
371+
pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8));
374372
}
375373
}
376374

@@ -384,7 +382,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
384382
// &'static str <: expected
385383
//
386384
// then that's equivalent to there existing a LUB.
387-
if let Some(mut err) = self.demand_suptype_diag(span, expected, pat_ty) {
385+
let cause = self.pattern_cause(ti, span);
386+
if let Some(mut err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
388387
err.emit_unless(
389388
ti.span
390389
.filter(|&s| {
@@ -543,8 +542,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
543542
// If there are multiple arms, make sure they all agree on
544543
// what the type of the binding `x` ought to be.
545544
if var_id != pat.hir_id {
546-
let vt = self.local_ty(pat.span, var_id).decl_ty;
547-
self.demand_eqtype_pat(pat.span, vt, local_ty, ti);
545+
self.check_binding_alt_eq_ty(pat.span, var_id, local_ty, ti);
548546
}
549547

550548
if let Some(p) = sub {
@@ -554,6 +552,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
554552
local_ty
555553
}
556554

555+
fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx>) {
556+
let var_ty = self.local_ty(span, var_id).decl_ty;
557+
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
558+
let hir = self.tcx.hir();
559+
let var_ty = self.resolve_vars_with_obligations(var_ty);
560+
let msg = format!("first introduced with type `{}` here", var_ty);
561+
err.span_label(hir.span(var_id), msg);
562+
let in_arm = hir.parent_iter(var_id).any(|(_, n)| matches!(n, hir::Node::Arm(..)));
563+
let pre = if in_arm { "in the same arm, " } else { "" };
564+
err.note(&format!("{}a binding must have the same type in all alternatives", pre));
565+
err.emit();
566+
}
567+
}
568+
557569
fn borrow_pat_suggestion(
558570
&self,
559571
err: &mut DiagnosticBuilder<'_>,
@@ -659,6 +671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
659671
path_resolution: (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]),
660672
qpath: &hir::QPath<'_>,
661673
expected: Ty<'tcx>,
674+
ti: TopInfo<'tcx>,
662675
) -> Ty<'tcx> {
663676
let tcx = self.tcx;
664677

@@ -684,7 +697,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
684697

685698
// Type-check the path.
686699
let pat_ty = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id).0;
687-
self.demand_suptype(pat.span, expected, pat_ty);
700+
if let Some(mut err) =
701+
self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty)
702+
{
703+
err.emit();
704+
}
688705
pat_ty
689706
}
690707

@@ -901,7 +918,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
901918
});
902919
let element_tys = tcx.mk_substs(element_tys_iter);
903920
let pat_ty = tcx.mk_ty(ty::Tuple(element_tys));
904-
if let Some(mut err) = self.demand_eqtype_diag(span, expected, pat_ty) {
921+
if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) {
905922
err.emit();
906923
// Walk subpatterns with an expected type of `err` in this case to silence
907924
// further errors being emitted when using the bindings. #50333
@@ -1205,7 +1222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12051222
});
12061223
let rptr_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
12071224
debug!("check_pat_ref: demanding {:?} = {:?}", expected, rptr_ty);
1208-
let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty);
1225+
let err = self.demand_eqtype_pat_diag(pat.span, expected, rptr_ty, ti);
12091226

12101227
// Look for a case like `fn foo(&foo: u32)` and suggest
12111228
// `fn foo(foo: &u32)`

‎src/test/ui/destructure-trait-ref.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ error[E0308]: mismatched types
2020
--> $DIR/destructure-trait-ref.rs:32:10
2121
|
2222
LL | let &&x = &1isize as &dyn T;
23-
| ^^
23+
| ^^ ----------------- this expression has type `&dyn T`
2424
| |
2525
| expected trait object `dyn T`, found reference
2626
| help: you can probably remove the explicit borrow: `x`
@@ -32,7 +32,7 @@ error[E0308]: mismatched types
3232
--> $DIR/destructure-trait-ref.rs:36:11
3333
|
3434
LL | let &&&x = &(&1isize as &dyn T);
35-
| ^^
35+
| ^^ -------------------- this expression has type `&&dyn T`
3636
| |
3737
| expected trait object `dyn T`, found reference
3838
| help: you can probably remove the explicit borrow: `x`

‎src/test/ui/elide-errors-on-mismatched-tuple.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
22
--> $DIR/elide-errors-on-mismatched-tuple.rs:14:9
33
|
44
LL | let (a, b, c) = (A::new(), A::new()); // This tuple is 2 elements, should be three
5-
| ^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements
5+
| ^^^^^^^^^ -------------------- this expression has type `(A, A)`
6+
| |
7+
| expected a tuple with 2 elements, found one with 3 elements
68
|
79
= note: expected tuple `(A, A)`
810
found tuple `(_, _, _)`

‎src/test/ui/issues/issue-12552.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ LL | Some(k) => match k {
1212
error[E0308]: mismatched types
1313
--> $DIR/issue-12552.rs:9:5
1414
|
15+
LL | match t {
16+
| - this expression has type `std::result::Result<_, {integer}>`
17+
...
1518
LL | None => ()
1619
| ^^^^ expected enum `std::result::Result`, found enum `std::option::Option`
1720
|

‎src/test/ui/issues/issue-37026.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
22
--> $DIR/issue-37026.rs:6:9
33
|
44
LL | let empty_struct::XEmpty2 = ();
5-
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `empty_struct::XEmpty2`
5+
| ^^^^^^^^^^^^^^^^^^^^^ -- this expression has type `()`
6+
| |
7+
| expected `()`, found struct `empty_struct::XEmpty2`
68

79
error[E0308]: mismatched types
810
--> $DIR/issue-37026.rs:7:9

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

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0308]: mismatched types
22
--> $DIR/issue-5100.rs:8:9
33
|
4+
LL | match (true, false) {
5+
| ------------- this expression has type `(bool, bool)`
46
LL | A::B => (),
57
| ^^^^ expected tuple, found enum `A`
68
|
@@ -10,6 +12,8 @@ LL | A::B => (),
1012
error[E0308]: mismatched types
1113
--> $DIR/issue-5100.rs:17:9
1214
|
15+
LL | match (true, false) {
16+
| ------------- this expression has type `(bool, bool)`
1317
LL | (true, false, false) => ()
1418
| ^^^^^^^^^^^^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements
1519
|
@@ -19,6 +23,8 @@ LL | (true, false, false) => ()
1923
error[E0308]: mismatched types
2024
--> $DIR/issue-5100.rs:25:9
2125
|
26+
LL | match (true, false) {
27+
| ------------- this expression has type `(bool, bool)`
2228
LL | (true, false, false) => ()
2329
| ^^^^^^^^^^^^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements
2430
|
@@ -39,6 +45,8 @@ LL | box (true, false) => ()
3945
error[E0308]: mismatched types
4046
--> $DIR/issue-5100.rs:40:9
4147
|
48+
LL | match (true, false) {
49+
| ------------- this expression has type `(bool, bool)`
4250
LL | &(true, false) => ()
4351
| ^^^^^^^^^^^^^^ expected tuple, found reference
4452
|

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

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0308]: mismatched types
22
--> $DIR/issue-7867.rs:7:9
33
|
4+
LL | match (true, false) {
5+
| ------------- this expression has type `(bool, bool)`
46
LL | A::B => (),
57
| ^^^^ expected tuple, found enum `A`
68
|

‎src/test/ui/match/match-ill-type2.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0308]: mismatched types
22
--> $DIR/match-ill-type2.rs:4:9
33
|
4+
LL | match 1i32 {
5+
| ---- this expression has type `i32`
6+
LL | 1i32 => 1,
47
LL | 2u32 => 1,
58
| ^^^^ expected `i32`, found `u32`
69

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
22
--> $DIR/match-tag-nullary.rs:4:40
33
|
44
LL | fn main() { let x: A = A::A; match x { B::B => { } } }
5-
| ^^^^ expected enum `A`, found enum `B`
5+
| - ^^^^ expected enum `A`, found enum `B`
6+
| |
7+
| this expression has type `A`
68

79
error: aborting due to previous error
810

‎src/test/ui/mismatched_types/E0409.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ error[E0308]: mismatched types
1212
LL | match x {
1313
| - this expression has type `({integer}, {integer})`
1414
LL | (0, ref y) | (y, 0) => {}
15-
| ^ expected `&{integer}`, found integer
15+
| ----- ^ expected `&{integer}`, found integer
16+
| |
17+
| first introduced with type `&{integer}` here
18+
|
19+
= note: in the same arm, a binding must have the same type in all alternatives
1620

1721
error: aborting due to 2 previous errors
1822

0 commit comments

Comments
 (0)
Please sign in to comment.