@@ -448,16 +448,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
448
448
ti : TopInfo < ' tcx > ,
449
449
) -> Ty < ' tcx > {
450
450
let calc_side = |opt_expr : Option < & ' tcx hir:: Expr < ' tcx > > | match opt_expr {
451
- None => ( None , None ) ,
451
+ None => None ,
452
452
Some ( expr) => {
453
453
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 ) )
457
463
}
458
464
} ;
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) ;
461
467
462
468
if let ( Some ( ( true , ..) ) , _) | ( _, Some ( ( true , ..) ) ) = ( lhs, rhs) {
463
469
// There exists a side that didn't meet our criteria that the end-point
@@ -466,25 +472,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
466
472
return self . tcx . ty_error ( ) ;
467
473
}
468
474
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`.
473
476
// 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 {
476
479
if let Some ( mut err) = self . demand_eqtype_pat_diag ( x_span, expected, x_ty, ti) {
477
480
if let Some ( ( _, y_ty, y_span) ) = y {
478
481
self . endpoint_has_type ( & mut err, y_span, y_ty) ;
479
482
}
480
483
err. emit ( ) ;
484
+ * fail = true ;
481
485
} ;
482
486
}
483
487
} ;
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
+ }
486
494
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
488
511
}
489
512
490
513
fn endpoint_has_type ( & self , err : & mut DiagnosticBuilder < ' _ > , span : Span , ty : Ty < ' _ > ) {
@@ -511,10 +534,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
511
534
E0029 ,
512
535
"only `char` and numeric types are allowed in range patterns"
513
536
) ;
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
+ } ;
515
541
let mut one_side_err = |first_span, first_ty, second : Option < ( bool , Ty < ' tcx > , Span ) > | {
516
542
err. span_label ( first_span, & msg ( first_ty) ) ;
517
543
if let Some ( ( _, ty, sp) ) = second {
544
+ let ty = self . resolve_vars_if_possible ( ty) ;
518
545
self . endpoint_has_type ( & mut err, sp, ty) ;
519
546
}
520
547
} ;
0 commit comments