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