@@ -20,21 +20,33 @@ use std::cmp;
2020use super :: report_unexpected_variant_def;
2121
2222impl < ' 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+ /// ```
2740 pub fn check_pat_walk (
2841 & self ,
2942 pat : & ' gcx hir:: Pat ,
3043 mut expected : Ty < ' tcx > ,
3144 mut def_bm : ty:: BindingMode ,
32- is_arg : bool )
33- {
45+ match_discrim_span : Option < Span > ,
46+ ) {
3447 let tcx = self . tcx ;
3548
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) ;
3850
3951 let is_non_ref_pat = match pat. node {
4052 PatKind :: Struct ( ..) |
@@ -210,8 +222,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
210222 let common_type = self . resolve_type_vars_if_possible ( & lhs_ty) ;
211223
212224 // 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 ) ;
215227 common_type
216228 }
217229 PatKind :: Binding ( ba, var_id, _, ref sub) => {
@@ -240,37 +252,45 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
240252 // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
241253 // required. However, we use equality, which is stronger. See (*) for
242254 // 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 ) ;
244256 }
245257 // otherwise the type of x is the expected type T
246258 ty:: BindByValue ( _) => {
247259 // As above, `T <: typeof(x)` is required but we
248260 // 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 ) ;
250262 }
251263 }
252264
253265 // if there are multiple arms, make sure they all agree on
254266 // what the type of the binding `x` ought to be
255267 if var_id != pat. id {
256268 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 ) ;
258270 }
259271
260272 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 ) ;
262274 }
263275
264276 local_ty
265277 }
266278 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+ )
268288 }
269289 PatKind :: Path ( ref qpath) => {
270290 self . check_pat_path ( pat, qpath, expected)
271291 }
272292 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 )
274294 }
275295 PatKind :: Tuple ( ref elements, ddpos) => {
276296 let mut expected_len = elements. len ( ) ;
@@ -295,12 +315,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
295315 // further errors being emitted when using the bindings. #50333
296316 let element_tys_iter = ( 0 ..max_len) . map ( |_| tcx. types . err ) ;
297317 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 ) ;
299319 }
300320 tcx. mk_tup ( element_tys_iter)
301321 } else {
302322 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 ) ;
304324 }
305325 pat_ty
306326 }
@@ -313,11 +333,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
313333 // Here, `demand::subtype` is good enough, but I don't
314334 // think any errors can be introduced by using
315335 // `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 ) ;
318338 uniq_ty
319339 } 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 ) ;
321341 tcx. types . err
322342 }
323343 }
@@ -349,15 +369,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
349369 // Look for a case like `fn foo(&foo: u32)` and suggest
350370 // `fn foo(foo: &u32)`
351371 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) ) ;
361379 }
362380 }
363381 err. emit ( ) ;
@@ -366,10 +384,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
366384 }
367385 } ;
368386
369- self . check_pat_walk ( & inner, inner_ty, def_bm, true ) ;
387+ self . check_pat_walk ( & inner, inner_ty, def_bm, match_discrim_span ) ;
370388 rptr_ty
371389 } 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 ) ;
373391 tcx. types . err
374392 }
375393 }
@@ -427,13 +445,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
427445 } ;
428446
429447 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 ) ;
431449 }
432450 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 ) ;
434452 }
435453 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 ) ;
437455 }
438456 expected_ty
439457 }
@@ -524,12 +542,14 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
524542 true
525543 }
526544
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 > {
533553 let tcx = self . tcx ;
534554
535555 // 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");
624644 let mut all_pats_diverge = Diverges :: WarnedAlways ;
625645 for p in & arm. pats {
626646 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+ ) ;
629653 all_pats_diverge &= self . diverges . get ( ) ;
630654 }
631655
@@ -703,26 +727,34 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
703727 coercion. complete ( self )
704728 }
705729
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 >
713740 {
714741 // Resolve the path and check the definition for errors.
715742 let ( variant, pat_ty) = if let Some ( variant_ty) = self . check_struct_path ( qpath, pat. id ) {
716743 variant_ty
717744 } else {
718745 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+ ) ;
720752 }
721753 return self . tcx . types . err ;
722754 } ;
723755
724756 // 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 ) ;
726758
727759 // Type-check subpatterns.
728760 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");
732764 }
733765 }
734766
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 > {
740773 let tcx = self . tcx ;
741774
742775 // Resolve the path and check the definition for errors.
@@ -767,18 +800,20 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
767800 pat_ty
768801 }
769802
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 > {
778813 let tcx = self . tcx ;
779814 let on_error = || {
780815 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 ) ;
782817 }
783818 } ;
784819 let report_unexpected_def = |def : Def | {
@@ -826,7 +861,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
826861 let pat_ty = pat_ty. fn_sig ( tcx) . output ( ) ;
827862 let pat_ty = pat_ty. no_bound_vars ( ) . expect ( "expected fn type" ) ;
828863
829- self . demand_eqtype ( pat. span , expected, pat_ty) ;
864+ self . demand_eqtype_pat ( pat. span , expected, pat_ty, match_arm_pat_span ) ;
830865
831866 // Type-check subpatterns.
832867 if subpats. len ( ) == variant. fields . len ( ) ||
@@ -837,7 +872,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
837872 } ;
838873 for ( i, subpat) in subpats. iter ( ) . enumerate_and_adjust ( variant. fields . len ( ) , ddpos) {
839874 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 ) ;
841876
842877 self . tcx . check_stability ( variant. fields [ i] . did , Some ( pat. id ) , subpat. span ) ;
843878 }
@@ -917,7 +952,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
917952 }
918953 } ;
919954
920- self . check_pat_walk ( & field. pat , field_ty, def_bm, true ) ;
955+ self . check_pat_walk ( & field. pat , field_ty, def_bm, None ) ;
921956 }
922957 let mut unmentioned_fields = variant. fields
923958 . iter ( )
0 commit comments