@@ -20,21 +20,33 @@ use std::cmp;
20
20
use super :: report_unexpected_variant_def;
21
21
22
22
impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
23
- /// The `is_arg` argument indicates whether this pattern is the
24
- /// *outermost* pattern in an argument (e.g., in `fn foo(&x:
25
- /// &u32)`, it is true for the `&x` pattern but not `x`). This is
26
- /// used to tailor error reporting.
23
+ /// `match_discrim_span` argument having a `Span` indicates that this pattern is part of
24
+ /// a match expression arm guard, and it points to the match discriminant to add context
25
+ /// in type errors. In the folloowing example, `match_discrim_span` corresponds to the
26
+ /// `a + b` expression:
27
+ ///
28
+ /// ```text
29
+ /// error[E0308]: mismatched types
30
+ /// --> src/main.rs:5:9
31
+ /// |
32
+ /// 4 | let temp: usize = match a + b {
33
+ /// | ----- this expression has type `usize`
34
+ /// 5 | Ok(num) => num,
35
+ /// | ^^^^^^^ expected usize, found enum `std::result::Result`
36
+ /// |
37
+ /// = note: expected type `usize`
38
+ /// found type `std::result::Result<_, _>`
39
+ /// ```
27
40
pub fn check_pat_walk (
28
41
& self ,
29
42
pat : & ' gcx hir:: Pat ,
30
43
mut expected : Ty < ' tcx > ,
31
44
mut def_bm : ty:: BindingMode ,
32
- is_arg : bool )
33
- {
45
+ match_discrim_span : Option < Span > ,
46
+ ) {
34
47
let tcx = self . tcx ;
35
48
36
- debug ! ( "check_pat_walk(pat={:?},expected={:?},def_bm={:?},is_arg={})" ,
37
- pat, expected, def_bm, is_arg) ;
49
+ debug ! ( "check_pat_walk(pat={:?},expected={:?},def_bm={:?})" , pat, expected, def_bm) ;
38
50
39
51
let is_non_ref_pat = match pat. node {
40
52
PatKind :: Struct ( ..) |
@@ -210,8 +222,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
210
222
let common_type = self . resolve_type_vars_if_possible ( & lhs_ty) ;
211
223
212
224
// subtyping doesn't matter here, as the value is some kind of scalar
213
- self . demand_eqtype ( pat. span , expected, lhs_ty) ;
214
- self . demand_eqtype ( pat. span , expected, rhs_ty) ;
225
+ self . demand_eqtype_pat ( pat. span , expected, lhs_ty, match_discrim_span ) ;
226
+ self . demand_eqtype_pat ( pat. span , expected, rhs_ty, match_discrim_span ) ;
215
227
common_type
216
228
}
217
229
PatKind :: Binding ( ba, var_id, _, ref sub) => {
@@ -240,37 +252,45 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
240
252
// `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
241
253
// required. However, we use equality, which is stronger. See (*) for
242
254
// an explanation.
243
- self . demand_eqtype ( pat. span , region_ty, local_ty) ;
255
+ self . demand_eqtype_pat ( pat. span , region_ty, local_ty, match_discrim_span ) ;
244
256
}
245
257
// otherwise the type of x is the expected type T
246
258
ty:: BindByValue ( _) => {
247
259
// As above, `T <: typeof(x)` is required but we
248
260
// use equality, see (*) below.
249
- self . demand_eqtype ( pat. span , expected, local_ty) ;
261
+ self . demand_eqtype_pat ( pat. span , expected, local_ty, match_discrim_span ) ;
250
262
}
251
263
}
252
264
253
265
// if there are multiple arms, make sure they all agree on
254
266
// what the type of the binding `x` ought to be
255
267
if var_id != pat. id {
256
268
let vt = self . local_ty ( pat. span , var_id) . decl_ty ;
257
- self . demand_eqtype ( pat. span , vt, local_ty) ;
269
+ self . demand_eqtype_pat ( pat. span , vt, local_ty, match_discrim_span ) ;
258
270
}
259
271
260
272
if let Some ( ref p) = * sub {
261
- self . check_pat_walk ( & p, expected, def_bm, true ) ;
273
+ self . check_pat_walk ( & p, expected, def_bm, match_discrim_span ) ;
262
274
}
263
275
264
276
local_ty
265
277
}
266
278
PatKind :: TupleStruct ( ref qpath, ref subpats, ddpos) => {
267
- self . check_pat_tuple_struct ( pat, qpath, & subpats, ddpos, expected, def_bm)
279
+ self . check_pat_tuple_struct (
280
+ pat,
281
+ qpath,
282
+ & subpats,
283
+ ddpos,
284
+ expected,
285
+ def_bm,
286
+ match_discrim_span,
287
+ )
268
288
}
269
289
PatKind :: Path ( ref qpath) => {
270
290
self . check_pat_path ( pat, qpath, expected)
271
291
}
272
292
PatKind :: Struct ( ref qpath, ref fields, etc) => {
273
- self . check_pat_struct ( pat, qpath, fields, etc, expected, def_bm)
293
+ self . check_pat_struct ( pat, qpath, fields, etc, expected, def_bm, match_discrim_span )
274
294
}
275
295
PatKind :: Tuple ( ref elements, ddpos) => {
276
296
let mut expected_len = elements. len ( ) ;
@@ -295,12 +315,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
295
315
// further errors being emitted when using the bindings. #50333
296
316
let element_tys_iter = ( 0 ..max_len) . map ( |_| tcx. types . err ) ;
297
317
for ( _, elem) in elements. iter ( ) . enumerate_and_adjust ( max_len, ddpos) {
298
- self . check_pat_walk ( elem, & tcx. types . err , def_bm, true ) ;
318
+ self . check_pat_walk ( elem, & tcx. types . err , def_bm, match_discrim_span ) ;
299
319
}
300
320
tcx. mk_tup ( element_tys_iter)
301
321
} else {
302
322
for ( i, elem) in elements. iter ( ) . enumerate_and_adjust ( max_len, ddpos) {
303
- self . check_pat_walk ( elem, & element_tys[ i] , def_bm, true ) ;
323
+ self . check_pat_walk ( elem, & element_tys[ i] , def_bm, match_discrim_span ) ;
304
324
}
305
325
pat_ty
306
326
}
@@ -313,11 +333,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
313
333
// Here, `demand::subtype` is good enough, but I don't
314
334
// think any errors can be introduced by using
315
335
// `demand::eqtype`.
316
- self . demand_eqtype ( pat. span , expected, uniq_ty) ;
317
- self . check_pat_walk ( & inner, inner_ty, def_bm, true ) ;
336
+ self . demand_eqtype_pat ( pat. span , expected, uniq_ty, match_discrim_span ) ;
337
+ self . check_pat_walk ( & inner, inner_ty, def_bm, match_discrim_span ) ;
318
338
uniq_ty
319
339
} else {
320
- self . check_pat_walk ( & inner, tcx. types . err , def_bm, true ) ;
340
+ self . check_pat_walk ( & inner, tcx. types . err , def_bm, match_discrim_span ) ;
321
341
tcx. types . err
322
342
}
323
343
}
@@ -349,15 +369,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
349
369
// Look for a case like `fn foo(&foo: u32)` and suggest
350
370
// `fn foo(foo: &u32)`
351
371
if let Some ( mut err) = err {
352
- if is_arg {
353
- if let PatKind :: Binding ( ..) = inner. node {
354
- if let Ok ( snippet) = tcx. sess . source_map ( )
355
- . span_to_snippet ( pat. span )
356
- {
357
- err. help ( & format ! ( "did you mean `{}: &{}`?" ,
358
- & snippet[ 1 ..] ,
359
- expected) ) ;
360
- }
372
+ if let PatKind :: Binding ( ..) = inner. node {
373
+ if let Ok ( snippet) = tcx. sess . source_map ( )
374
+ . span_to_snippet ( pat. span )
375
+ {
376
+ err. help ( & format ! ( "did you mean `{}: &{}`?" ,
377
+ & snippet[ 1 ..] ,
378
+ expected) ) ;
361
379
}
362
380
}
363
381
err. emit ( ) ;
@@ -366,10 +384,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
366
384
}
367
385
} ;
368
386
369
- self . check_pat_walk ( & inner, inner_ty, def_bm, true ) ;
387
+ self . check_pat_walk ( & inner, inner_ty, def_bm, match_discrim_span ) ;
370
388
rptr_ty
371
389
} else {
372
- self . check_pat_walk ( & inner, tcx. types . err , def_bm, true ) ;
390
+ self . check_pat_walk ( & inner, tcx. types . err , def_bm, match_discrim_span ) ;
373
391
tcx. types . err
374
392
}
375
393
}
@@ -427,13 +445,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
427
445
} ;
428
446
429
447
for elt in before {
430
- self . check_pat_walk ( & elt, inner_ty, def_bm, true ) ;
448
+ self . check_pat_walk ( & elt, inner_ty, def_bm, match_discrim_span ) ;
431
449
}
432
450
if let Some ( ref slice) = * slice {
433
- self . check_pat_walk ( & slice, slice_ty, def_bm, true ) ;
451
+ self . check_pat_walk ( & slice, slice_ty, def_bm, match_discrim_span ) ;
434
452
}
435
453
for elt in after {
436
- self . check_pat_walk ( & elt, inner_ty, def_bm, true ) ;
454
+ self . check_pat_walk ( & elt, inner_ty, def_bm, match_discrim_span ) ;
437
455
}
438
456
expected_ty
439
457
}
@@ -524,12 +542,14 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
524
542
true
525
543
}
526
544
527
- pub fn check_match ( & self ,
528
- expr : & ' gcx hir:: Expr ,
529
- discrim : & ' gcx hir:: Expr ,
530
- arms : & ' gcx [ hir:: Arm ] ,
531
- expected : Expectation < ' tcx > ,
532
- match_src : hir:: MatchSource ) -> Ty < ' tcx > {
545
+ pub fn check_match (
546
+ & self ,
547
+ expr : & ' gcx hir:: Expr ,
548
+ discrim : & ' gcx hir:: Expr ,
549
+ arms : & ' gcx [ hir:: Arm ] ,
550
+ expected : Expectation < ' tcx > ,
551
+ match_src : hir:: MatchSource ,
552
+ ) -> Ty < ' tcx > {
533
553
let tcx = self . tcx ;
534
554
535
555
// Not entirely obvious: if matches may create ref bindings, we want to
@@ -624,8 +644,12 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
624
644
let mut all_pats_diverge = Diverges :: WarnedAlways ;
625
645
for p in & arm. pats {
626
646
self . diverges . set ( Diverges :: Maybe ) ;
627
- self . check_pat_walk ( & p, discrim_ty,
628
- ty:: BindingMode :: BindByValue ( hir:: Mutability :: MutImmutable ) , true ) ;
647
+ self . check_pat_walk (
648
+ & p,
649
+ discrim_ty,
650
+ ty:: BindingMode :: BindByValue ( hir:: Mutability :: MutImmutable ) ,
651
+ Some ( discrim. span ) ,
652
+ ) ;
629
653
all_pats_diverge &= self . diverges . get ( ) ;
630
654
}
631
655
@@ -703,26 +727,34 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
703
727
coercion. complete ( self )
704
728
}
705
729
706
- fn check_pat_struct ( & self ,
707
- pat : & ' gcx hir:: Pat ,
708
- qpath : & hir:: QPath ,
709
- fields : & ' gcx [ Spanned < hir:: FieldPat > ] ,
710
- etc : bool ,
711
- expected : Ty < ' tcx > ,
712
- def_bm : ty:: BindingMode ) -> Ty < ' tcx >
730
+ fn check_pat_struct (
731
+ & self ,
732
+ pat : & ' gcx hir:: Pat ,
733
+ qpath : & hir:: QPath ,
734
+ fields : & ' gcx [ Spanned < hir:: FieldPat > ] ,
735
+ etc : bool ,
736
+ expected : Ty < ' tcx > ,
737
+ def_bm : ty:: BindingMode ,
738
+ match_discrim_span : Option < Span > ,
739
+ ) -> Ty < ' tcx >
713
740
{
714
741
// Resolve the path and check the definition for errors.
715
742
let ( variant, pat_ty) = if let Some ( variant_ty) = self . check_struct_path ( qpath, pat. id ) {
716
743
variant_ty
717
744
} else {
718
745
for field in fields {
719
- self . check_pat_walk ( & field. node . pat , self . tcx . types . err , def_bm, true ) ;
746
+ self . check_pat_walk (
747
+ & field. node . pat ,
748
+ self . tcx . types . err ,
749
+ def_bm,
750
+ match_discrim_span,
751
+ ) ;
720
752
}
721
753
return self . tcx . types . err ;
722
754
} ;
723
755
724
756
// Type-check the path.
725
- self . demand_eqtype ( pat. span , expected, pat_ty) ;
757
+ self . demand_eqtype_pat ( pat. span , expected, pat_ty, match_discrim_span ) ;
726
758
727
759
// Type-check subpatterns.
728
760
if self . check_struct_pat_fields ( pat_ty, pat. id , pat. span , variant, fields, etc, def_bm) {
@@ -732,11 +764,12 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
732
764
}
733
765
}
734
766
735
- fn check_pat_path ( & self ,
736
- pat : & hir:: Pat ,
737
- qpath : & hir:: QPath ,
738
- expected : Ty < ' tcx > ) -> Ty < ' tcx >
739
- {
767
+ fn check_pat_path (
768
+ & self ,
769
+ pat : & hir:: Pat ,
770
+ qpath : & hir:: QPath ,
771
+ expected : Ty < ' tcx > ,
772
+ ) -> Ty < ' tcx > {
740
773
let tcx = self . tcx ;
741
774
742
775
// Resolve the path and check the definition for errors.
@@ -767,18 +800,20 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
767
800
pat_ty
768
801
}
769
802
770
- fn check_pat_tuple_struct ( & self ,
771
- pat : & hir:: Pat ,
772
- qpath : & hir:: QPath ,
773
- subpats : & ' gcx [ P < hir:: Pat > ] ,
774
- ddpos : Option < usize > ,
775
- expected : Ty < ' tcx > ,
776
- def_bm : ty:: BindingMode ) -> Ty < ' tcx >
777
- {
803
+ fn check_pat_tuple_struct (
804
+ & self ,
805
+ pat : & hir:: Pat ,
806
+ qpath : & hir:: QPath ,
807
+ subpats : & ' gcx [ P < hir:: Pat > ] ,
808
+ ddpos : Option < usize > ,
809
+ expected : Ty < ' tcx > ,
810
+ def_bm : ty:: BindingMode ,
811
+ match_arm_pat_span : Option < Span > ,
812
+ ) -> Ty < ' tcx > {
778
813
let tcx = self . tcx ;
779
814
let on_error = || {
780
815
for pat in subpats {
781
- self . check_pat_walk ( & pat, tcx. types . err , def_bm, true ) ;
816
+ self . check_pat_walk ( & pat, tcx. types . err , def_bm, match_arm_pat_span ) ;
782
817
}
783
818
} ;
784
819
let report_unexpected_def = |def : Def | {
@@ -826,7 +861,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
826
861
let pat_ty = pat_ty. fn_sig ( tcx) . output ( ) ;
827
862
let pat_ty = pat_ty. no_bound_vars ( ) . expect ( "expected fn type" ) ;
828
863
829
- self . demand_eqtype ( pat. span , expected, pat_ty) ;
864
+ self . demand_eqtype_pat ( pat. span , expected, pat_ty, match_arm_pat_span ) ;
830
865
831
866
// Type-check subpatterns.
832
867
if subpats. len ( ) == variant. fields . len ( ) ||
@@ -837,7 +872,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
837
872
} ;
838
873
for ( i, subpat) in subpats. iter ( ) . enumerate_and_adjust ( variant. fields . len ( ) , ddpos) {
839
874
let field_ty = self . field_ty ( subpat. span , & variant. fields [ i] , substs) ;
840
- self . check_pat_walk ( & subpat, field_ty, def_bm, true ) ;
875
+ self . check_pat_walk ( & subpat, field_ty, def_bm, match_arm_pat_span ) ;
841
876
842
877
self . tcx . check_stability ( variant. fields [ i] . did , Some ( pat. id ) , subpat. span ) ;
843
878
}
@@ -917,7 +952,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
917
952
}
918
953
} ;
919
954
920
- self . check_pat_walk ( & field. pat , field_ty, def_bm, true ) ;
955
+ self . check_pat_walk ( & field. pat , field_ty, def_bm, None ) ;
921
956
}
922
957
let mut unmentioned_fields = variant. fields
923
958
. iter ( )
0 commit comments