mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-22 12:37:32 +00:00
Rollup merge of #88090 - nbdd0121:inference, r=nikomatsakis
Perform type inference in range pattern Fix #88074
This commit is contained in:
commit
4f6afee4e5
@ -449,16 +449,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
ti: TopInfo<'tcx>,
|
ti: TopInfo<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr {
|
let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr {
|
||||||
None => (None, None),
|
None => None,
|
||||||
Some(expr) => {
|
Some(expr) => {
|
||||||
let ty = self.check_expr(expr);
|
let ty = self.check_expr(expr);
|
||||||
// Check that the end-point is of numeric or char type.
|
// Check that the end-point is possibly of numeric or char type.
|
||||||
let fail = !(ty.is_numeric() || ty.is_char() || ty.references_error());
|
// The early check here is not for correctness, but rather better
|
||||||
(Some(ty), Some((fail, ty, expr.span)))
|
// diagnostics (e.g. when `&str` is being matched, `expected` will
|
||||||
|
// be peeled to `str` while ty here is still `&str`, if we don't
|
||||||
|
// err ealy here, a rather confusing unification error will be
|
||||||
|
// emitted instead).
|
||||||
|
let fail =
|
||||||
|
!(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error());
|
||||||
|
Some((fail, ty, expr.span))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (lhs_ty, lhs) = calc_side(lhs);
|
let mut lhs = calc_side(lhs);
|
||||||
let (rhs_ty, rhs) = calc_side(rhs);
|
let mut rhs = calc_side(rhs);
|
||||||
|
|
||||||
if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
|
if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
|
||||||
// There exists a side that didn't meet our criteria that the end-point
|
// There exists a side that didn't meet our criteria that the end-point
|
||||||
@ -467,25 +473,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
return self.tcx.ty_error();
|
return self.tcx.ty_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we know the types can be unified we find the unified type
|
// Unify each side with `expected`.
|
||||||
// and use it to type the entire expression.
|
|
||||||
let common_type = self.resolve_vars_if_possible(lhs_ty.or(rhs_ty).unwrap_or(expected));
|
|
||||||
|
|
||||||
// Subtyping doesn't matter here, as the value is some kind of scalar.
|
// Subtyping doesn't matter here, as the value is some kind of scalar.
|
||||||
let demand_eqtype = |x, y| {
|
let demand_eqtype = |x: &mut _, y| {
|
||||||
if let Some((_, x_ty, x_span)) = x {
|
if let Some((ref mut fail, x_ty, x_span)) = *x {
|
||||||
if let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) {
|
if let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) {
|
||||||
if let Some((_, y_ty, y_span)) = y {
|
if let Some((_, y_ty, y_span)) = y {
|
||||||
self.endpoint_has_type(&mut err, y_span, y_ty);
|
self.endpoint_has_type(&mut err, y_span, y_ty);
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
|
*fail = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
demand_eqtype(lhs, rhs);
|
demand_eqtype(&mut lhs, rhs);
|
||||||
demand_eqtype(rhs, lhs);
|
demand_eqtype(&mut rhs, lhs);
|
||||||
|
|
||||||
common_type
|
if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
|
||||||
|
return self.tcx.ty_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the unified type and check if it's of numeric or char type again.
|
||||||
|
// This check is needed if both sides are inference variables.
|
||||||
|
// We require types to be resolved here so that we emit inference failure
|
||||||
|
// rather than "_ is not a char or numeric".
|
||||||
|
let ty = self.structurally_resolved_type(span, expected);
|
||||||
|
if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
|
||||||
|
if let Some((ref mut fail, _, _)) = lhs {
|
||||||
|
*fail = true;
|
||||||
|
}
|
||||||
|
if let Some((ref mut fail, _, _)) = rhs {
|
||||||
|
*fail = true;
|
||||||
|
}
|
||||||
|
self.emit_err_pat_range(span, lhs, rhs);
|
||||||
|
return self.tcx.ty_error();
|
||||||
|
}
|
||||||
|
ty
|
||||||
}
|
}
|
||||||
|
|
||||||
fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<'_>) {
|
fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<'_>) {
|
||||||
@ -512,10 +535,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
E0029,
|
E0029,
|
||||||
"only `char` and numeric types are allowed in range patterns"
|
"only `char` and numeric types are allowed in range patterns"
|
||||||
);
|
);
|
||||||
let msg = |ty| format!("this is of type `{}` but it should be `char` or numeric", ty);
|
let msg = |ty| {
|
||||||
|
let ty = self.resolve_vars_if_possible(ty);
|
||||||
|
format!("this is of type `{}` but it should be `char` or numeric", ty)
|
||||||
|
};
|
||||||
let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
|
let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
|
||||||
err.span_label(first_span, &msg(first_ty));
|
err.span_label(first_span, &msg(first_ty));
|
||||||
if let Some((_, ty, sp)) = second {
|
if let Some((_, ty, sp)) = second {
|
||||||
|
let ty = self.resolve_vars_if_possible(ty);
|
||||||
self.endpoint_has_type(&mut err, sp, ty);
|
self.endpoint_has_type(&mut err, sp, ty);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
trait Zero {
|
||||||
|
const ZERO: Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Zero for String {
|
||||||
|
const ZERO: Self = String::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
match String::new() {
|
||||||
|
Zero::ZERO ..= Zero::ZERO => {},
|
||||||
|
//~^ ERROR only `char` and numeric types are allowed in range patterns
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() {
|
||||||
|
match Zero::ZERO {
|
||||||
|
Zero::ZERO ..= Zero::ZERO => {},
|
||||||
|
//~^ ERROR type annotations needed [E0282]
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
error[E0029]: only `char` and numeric types are allowed in range patterns
|
||||||
|
--> $DIR/issue-88074-pat-range-type-inference-err.rs:11:9
|
||||||
|
|
|
||||||
|
LL | Zero::ZERO ..= Zero::ZERO => {},
|
||||||
|
| ----------^^^^^----------
|
||||||
|
| | |
|
||||||
|
| | this is of type `String` but it should be `char` or numeric
|
||||||
|
| this is of type `String` but it should be `char` or numeric
|
||||||
|
|
||||||
|
error[E0282]: type annotations needed
|
||||||
|
--> $DIR/issue-88074-pat-range-type-inference-err.rs:19:9
|
||||||
|
|
|
||||||
|
LL | Zero::ZERO ..= Zero::ZERO => {},
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
|
||||||
|
|
|
||||||
|
= note: type must be known at this point
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0029, E0282.
|
||||||
|
For more information about an error, try `rustc --explain E0029`.
|
16
src/test/ui/pattern/issue-88074-pat-range-type-inference.rs
Normal file
16
src/test/ui/pattern/issue-88074-pat-range-type-inference.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
trait Zero {
|
||||||
|
const ZERO: Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Zero for i32 {
|
||||||
|
const ZERO: Self = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match 1 {
|
||||||
|
Zero::ZERO ..= 1 => {},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,6 @@ enum_number!(Change {
|
|||||||
Neg = -1,
|
Neg = -1,
|
||||||
Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns
|
Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns
|
||||||
//~| ERROR arbitrary expressions aren't allowed in patterns
|
//~| ERROR arbitrary expressions aren't allowed in patterns
|
||||||
//~| ERROR only `char` and numeric types are allowed in range patterns
|
|
||||||
});
|
});
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -10,15 +10,5 @@ error: arbitrary expressions aren't allowed in patterns
|
|||||||
LL | Arith = 1 + 1,
|
LL | Arith = 1 + 1,
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error[E0029]: only `char` and numeric types are allowed in range patterns
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/patkind-litrange-no-expr.rs:20:13
|
|
||||||
|
|
|
||||||
LL | $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range
|
|
||||||
| -- this is of type `{integer}`
|
|
||||||
...
|
|
||||||
LL | Arith = 1 + 1,
|
|
||||||
| ^^^^^ this is of type `_` but it should be `char` or numeric
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0029`.
|
|
||||||
|
Loading…
Reference in New Issue
Block a user