@@ -362,66 +362,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
362362 || ty. is_char ( )
363363 || ty. references_error ( )
364364 } ;
365- let lhs_compat = numeric_or_char ( lhs_ty) ;
366- let rhs_compat = numeric_or_char ( rhs_ty) ;
367-
368- if !lhs_compat || !rhs_compat {
369- let span = if !lhs_compat && !rhs_compat {
370- span
371- } else if !lhs_compat {
372- begin. span
373- } else {
374- end. span
375- } ;
365+ let lhs_fail = !numeric_or_char ( lhs_ty) ;
366+ let rhs_fail = !numeric_or_char ( rhs_ty) ;
376367
377- let mut err = struct_span_err ! (
378- self . tcx. sess,
379- span,
380- E0029 ,
381- "only char and numeric types are allowed in range patterns"
368+ if lhs_fail || rhs_fail {
369+ self . emit_err_pat_range (
370+ span, begin. span , end. span , lhs_fail, rhs_fail, lhs_ty, rhs_ty
382371 ) ;
383- if !lhs_compat && !rhs_compat {
384- err. span_label (
385- begin. span ,
386- & format ! ( "this is of type `{}` but it should be `char` or numeric" , lhs_ty)
387- ) ;
388- err. span_label (
389- end. span ,
390- & format ! ( "this is of type `{}` but it should be `char` or numeric" , rhs_ty)
391- ) ;
392- } else if !lhs_compat {
393- err. span_label (
394- begin. span ,
395- & format ! ( "this is of type `{}` but it should be `char` or numeric" , lhs_ty)
396- ) ;
397- if !rhs_ty. references_error ( ) {
398- err. span_label (
399- end. span ,
400- & format ! ( "this is of type `{}`" , rhs_ty)
401- ) ;
402- }
403- } else {
404- err. span_label (
405- end. span ,
406- & format ! ( "this is of type `{}` but it should be `char` or numeric" , rhs_ty)
407- ) ;
408- if !lhs_ty. references_error ( ) {
409- err. span_label (
410- begin. span ,
411- & format ! ( "this is of type `{}`" , lhs_ty)
412- ) ;
413- }
414- }
415- if self . tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
416- err. note (
417- "In a match expression, only numbers and characters can be matched \
418- against a range. This is because the compiler checks that the range \
419- is non-empty at compile-time, and is unable to evaluate arbitrary \
420- comparison functions. If you want to capture values of an orderable \
421- type between two end-points, you can use a guard."
422- ) ;
423- }
424- err. emit ( ) ;
425372 return None ;
426373 }
427374
@@ -435,6 +382,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
435382 Some ( common_type)
436383 }
437384
385+ fn emit_err_pat_range (
386+ & self ,
387+ span : Span ,
388+ begin_span : Span ,
389+ end_span : Span ,
390+ lhs_fail : bool ,
391+ rhs_fail : bool ,
392+ lhs_ty : Ty < ' tcx > ,
393+ rhs_ty : Ty < ' tcx > ,
394+ ) {
395+ let span = if lhs_fail && rhs_fail {
396+ span
397+ } else if lhs_fail {
398+ begin_span
399+ } else {
400+ end_span
401+ } ;
402+
403+ let mut err = struct_span_err ! (
404+ self . tcx. sess,
405+ span,
406+ E0029 ,
407+ "only char and numeric types are allowed in range patterns"
408+ ) ;
409+ let msg = |ty| {
410+ format ! ( "this is of type `{}` but it should be `char` or numeric" , ty)
411+ } ;
412+ let mut one_side_err = |first_span, first_ty, second_span, second_ty : Ty < ' _ > | {
413+ err. span_label ( first_span, & msg ( first_ty) ) ;
414+ if !second_ty. references_error ( ) {
415+ err. span_label (
416+ second_span,
417+ & format ! ( "this is of type `{}`" , second_ty)
418+ ) ;
419+ }
420+ } ;
421+ if lhs_fail && rhs_fail {
422+ err. span_label ( begin_span, & msg ( lhs_ty) ) ;
423+ err. span_label ( end_span, & msg ( rhs_ty) ) ;
424+ } else if lhs_fail {
425+ one_side_err ( begin_span, lhs_ty, end_span, rhs_ty) ;
426+ } else {
427+ one_side_err ( end_span, rhs_ty, begin_span, lhs_ty) ;
428+ }
429+ if self . tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
430+ err. note (
431+ "In a match expression, only numbers and characters can be matched \
432+ against a range. This is because the compiler checks that the range \
433+ is non-empty at compile-time, and is unable to evaluate arbitrary \
434+ comparison functions. If you want to capture values of an orderable \
435+ type between two end-points, you can use a guard."
436+ ) ;
437+ }
438+ err. emit ( ) ;
439+ }
440+
438441 fn check_pat_ident (
439442 & self ,
440443 pat : & Pat ,
0 commit comments