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