@@ -449,16 +449,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
449449 ti : TopInfo < ' tcx > ,
450450 ) -> Ty < ' tcx > {
451451 let calc_side = |opt_expr : Option < & ' tcx hir:: Expr < ' tcx > > | match opt_expr {
452- None => ( None , None ) ,
452+ None => None ,
453453 Some ( expr) => {
454454 let ty = self . check_expr ( expr) ;
455- // Check that the end-point is of numeric or char type.
456- let fail = !( ty. is_numeric ( ) || ty. is_char ( ) || ty. references_error ( ) ) ;
457- ( Some ( ty) , Some ( ( fail, ty, expr. span ) ) )
455+ // Check that the end-point is possibly of numeric or char type.
456+ // The early check here is not for correctness, but rather better
457+ // diagnostics (e.g. when `&str` is being matched, `expected` will
458+ // be peeled to `str` while ty here is still `&str`, if we don't
459+ // err ealy here, a rather confusing unification error will be
460+ // emitted instead).
461+ let fail =
462+ !( ty. is_numeric ( ) || ty. is_char ( ) || ty. is_ty_var ( ) || ty. references_error ( ) ) ;
463+ Some ( ( fail, ty, expr. span ) )
458464 }
459465 } ;
460- let ( lhs_ty , lhs) = calc_side ( lhs) ;
461- let ( rhs_ty , rhs) = calc_side ( rhs) ;
466+ let mut lhs = calc_side ( lhs) ;
467+ let mut rhs = calc_side ( rhs) ;
462468
463469 if let ( Some ( ( true , ..) ) , _) | ( _, Some ( ( true , ..) ) ) = ( lhs, rhs) {
464470 // There exists a side that didn't meet our criteria that the end-point
@@ -467,25 +473,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
467473 return self . tcx . ty_error ( ) ;
468474 }
469475
470- // Now that we know the types can be unified we find the unified type
471- // and use it to type the entire expression.
472- let common_type = self . resolve_vars_if_possible ( lhs_ty. or ( rhs_ty) . unwrap_or ( expected) ) ;
473-
476+ // Unify each side with `expected`.
474477 // Subtyping doesn't matter here, as the value is some kind of scalar.
475- let demand_eqtype = |x, y| {
476- if let Some ( ( _ , x_ty, x_span) ) = x {
478+ let demand_eqtype = |x : & mut _ , y| {
479+ if let Some ( ( ref mut fail , x_ty, x_span) ) = * x {
477480 if let Some ( mut err) = self . demand_eqtype_pat_diag ( x_span, expected, x_ty, ti) {
478481 if let Some ( ( _, y_ty, y_span) ) = y {
479482 self . endpoint_has_type ( & mut err, y_span, y_ty) ;
480483 }
481484 err. emit ( ) ;
485+ * fail = true ;
482486 } ;
483487 }
484488 } ;
485- demand_eqtype ( lhs, rhs) ;
486- demand_eqtype ( rhs, lhs) ;
489+ demand_eqtype ( & mut lhs, rhs) ;
490+ demand_eqtype ( & mut rhs, lhs) ;
491+
492+ if let ( Some ( ( true , ..) ) , _) | ( _, Some ( ( true , ..) ) ) = ( lhs, rhs) {
493+ return self . tcx . ty_error ( ) ;
494+ }
487495
488- common_type
496+ // Find the unified type and check if it's of numeric or char type again.
497+ // This check is needed if both sides are inference variables.
498+ // We require types to be resolved here so that we emit inference failure
499+ // rather than "_ is not a char or numeric".
500+ let ty = self . structurally_resolved_type ( span, expected) ;
501+ if !( ty. is_numeric ( ) || ty. is_char ( ) || ty. references_error ( ) ) {
502+ if let Some ( ( ref mut fail, _, _) ) = lhs {
503+ * fail = true ;
504+ }
505+ if let Some ( ( ref mut fail, _, _) ) = rhs {
506+ * fail = true ;
507+ }
508+ self . emit_err_pat_range ( span, lhs, rhs) ;
509+ return self . tcx . ty_error ( ) ;
510+ }
511+ ty
489512 }
490513
491514 fn endpoint_has_type ( & self , err : & mut DiagnosticBuilder < ' _ > , span : Span , ty : Ty < ' _ > ) {
@@ -512,10 +535,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
512535 E0029 ,
513536 "only `char` and numeric types are allowed in range patterns"
514537 ) ;
515- let msg = |ty| format ! ( "this is of type `{}` but it should be `char` or numeric" , ty) ;
538+ let msg = |ty| {
539+ let ty = self . resolve_vars_if_possible ( ty) ;
540+ format ! ( "this is of type `{}` but it should be `char` or numeric" , ty)
541+ } ;
516542 let mut one_side_err = |first_span, first_ty, second : Option < ( bool , Ty < ' tcx > , Span ) > | {
517543 err. span_label ( first_span, & msg ( first_ty) ) ;
518544 if let Some ( ( _, ty, sp) ) = second {
545+ let ty = self . resolve_vars_if_possible ( ty) ;
519546 self . endpoint_has_type ( & mut err, sp, ty) ;
520547 }
521548 } ;
0 commit comments