Skip to content

Commit d4afae9

Browse files
committed
typeck/pat.rs: extract check_pat_range.
1 parent d891e70 commit d4afae9

File tree

1 file changed

+63
-50
lines changed
  • src/librustc_typeck/check

1 file changed

+63
-50
lines changed

src/librustc_typeck/check/pat.rs

Lines changed: 63 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -71,57 +71,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7171
self.check_pat_lit(pat.span, lt, expected, discrim_span)
7272
}
7373
PatKind::Range(ref begin, ref end, _) => {
74-
let lhs_ty = self.check_expr(begin);
75-
let rhs_ty = self.check_expr(end);
76-
77-
// Check that both end-points are of numeric or char type.
78-
let numeric_or_char = |ty: Ty<'_>| {
79-
ty.is_numeric()
80-
|| ty.is_char()
81-
|| ty.references_error()
82-
};
83-
let lhs_compat = numeric_or_char(lhs_ty);
84-
let rhs_compat = numeric_or_char(rhs_ty);
85-
86-
if !lhs_compat || !rhs_compat {
87-
let span = if !lhs_compat && !rhs_compat {
88-
pat.span
89-
} else if !lhs_compat {
90-
begin.span
91-
} else {
92-
end.span
93-
};
94-
95-
let mut err = struct_span_err!(
96-
tcx.sess,
97-
span,
98-
E0029,
99-
"only char and numeric types are allowed in range patterns"
100-
);
101-
err.span_label(span, "ranges require char or numeric types");
102-
err.note(&format!("start type: {}", self.ty_to_string(lhs_ty)));
103-
err.note(&format!("end type: {}", self.ty_to_string(rhs_ty)));
104-
if tcx.sess.teach(&err.get_code().unwrap()) {
105-
err.note(
106-
"In a match expression, only numbers and characters can be matched \
107-
against a range. This is because the compiler checks that the range \
108-
is non-empty at compile-time, and is unable to evaluate arbitrary \
109-
comparison functions. If you want to capture values of an orderable \
110-
type between two end-points, you can use a guard."
111-
);
112-
}
113-
err.emit();
114-
return;
74+
match self.check_pat_range(pat.span, begin, end, expected, discrim_span) {
75+
None => return,
76+
Some(ty) => ty,
11577
}
116-
117-
// Now that we know the types can be unified we find the unified type and use
118-
// it to type the entire expression.
119-
let common_type = self.resolve_vars_if_possible(&lhs_ty);
120-
121-
// Subtyping doesn't matter here, as the value is some kind of scalar.
122-
self.demand_eqtype_pat(pat.span, expected, lhs_ty, discrim_span);
123-
self.demand_eqtype_pat(pat.span, expected, rhs_ty, discrim_span);
124-
common_type
12578
}
12679
PatKind::Binding(ba, var_id, _, ref sub) => {
12780
let bm = if ba == hir::BindingAnnotation::Unannotated {
@@ -597,6 +550,66 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
597550
pat_ty
598551
}
599552

553+
fn check_pat_range(
554+
&self,
555+
span: Span,
556+
begin: &'tcx hir::Expr,
557+
end: &'tcx hir::Expr,
558+
expected: Ty<'tcx>,
559+
discrim_span: Option<Span>,
560+
) -> Option<Ty<'tcx>> {
561+
let lhs_ty = self.check_expr(begin);
562+
let rhs_ty = self.check_expr(end);
563+
564+
// Check that both end-points are of numeric or char type.
565+
let numeric_or_char = |ty: Ty<'_>| {
566+
ty.is_numeric()
567+
|| ty.is_char()
568+
|| ty.references_error()
569+
};
570+
let lhs_compat = numeric_or_char(lhs_ty);
571+
let rhs_compat = numeric_or_char(rhs_ty);
572+
573+
if !lhs_compat || !rhs_compat {
574+
let span = if !lhs_compat && !rhs_compat {
575+
span
576+
} else if !lhs_compat {
577+
begin.span
578+
} else {
579+
end.span
580+
};
581+
582+
let mut err = struct_span_err!(
583+
self.tcx.sess,
584+
span,
585+
E0029,
586+
"only char and numeric types are allowed in range patterns"
587+
);
588+
err.span_label(span, "ranges require char or numeric types");
589+
err.note(&format!("start type: {}", self.ty_to_string(lhs_ty)));
590+
err.note(&format!("end type: {}", self.ty_to_string(rhs_ty)));
591+
if self.tcx.sess.teach(&err.get_code().unwrap()) {
592+
err.note(
593+
"In a match expression, only numbers and characters can be matched \
594+
against a range. This is because the compiler checks that the range \
595+
is non-empty at compile-time, and is unable to evaluate arbitrary \
596+
comparison functions. If you want to capture values of an orderable \
597+
type between two end-points, you can use a guard."
598+
);
599+
}
600+
err.emit();
601+
return None;
602+
}
603+
604+
// Now that we know the types can be unified we find the unified type and use
605+
// it to type the entire expression.
606+
let common_type = self.resolve_vars_if_possible(&lhs_ty);
607+
608+
// Subtyping doesn't matter here, as the value is some kind of scalar.
609+
self.demand_eqtype_pat(span, expected, lhs_ty, discrim_span);
610+
self.demand_eqtype_pat(span, expected, rhs_ty, discrim_span);
611+
Some(common_type)
612+
}
600613

601614
fn borrow_pat_suggestion(
602615
&self,

0 commit comments

Comments
 (0)