Change:
currently throws E0029: while it should infer the constant to be . modify labels: +T-compiler +A-inference claim <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
I don't think this is incorrect. doesn't refer to a specific constant, it's just an abstract associated constant. works fine.
Hmm, does work, though. But does not. It does seem inconsistent that works and doesn't.
is just , so type inference should kick in here. In fact you can write and inference works just fine. The issue only happens when used in range patterns. I am prototyping a fix right now and it seems that the issue is just that E0029 check happens a little bit early (before unification is performed).

Discussion:
ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr { <del> None => (None, None), </del> <ins> None => None, </ins> Some(expr) => { let ty = self.check_expr(expr); <del> // Check that the end-point is of numeric or char type. let fail = !(ty.is_numeric() || ty.is_char() || ty.references_error()); (Some(ty), Some((fail, ty, expr.span))) </del> <ins> // Check that the end-point is possibly of numeric or char type. // The early check here is not for correctness, but rather better // 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)) </ins> } }; <del> let (lhs_ty, lhs) = calc_side(lhs); let (rhs_ty, rhs) = calc_side(rhs); </del> <ins> let mut lhs = calc_side(lhs); let mut rhs = calc_side(rhs); </ins> if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) { // There exists a side that didn't meet our criteria that the end-point

return self.tcx.ty_error(); } <del> // Now that we know the types can be unified we find the unified type // and use it to type the entire expression. let common_type = self.resolve_vars_if_possible(lhs_ty.or(rhs_ty).unwrap_or(expected)); </del> <ins> // Unify each side with `expected`. </ins> // Subtyping doesn't matter here, as the value is some kind of scalar. <del> let demand_eqtype = |x, y| { if let Some((_, x_ty, x_span)) = x { </del> <ins> let demand_eqtype = |x: &mut _, y| { if let Some((ref mut fail, x_ty, x_span)) = *x { </ins> if let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) { if let Some((_, y_ty, y_span)) = y { self.endpoint_has_type(&mut err, y_span, y_ty); } err.emit(); <ins> *fail = true; </ins> }; } }; <del> demand_eqtype(lhs, rhs); demand_eqtype(rhs, lhs); </del> <ins> demand_eqtype(&mut lhs, rhs); demand_eqtype(&mut rhs, lhs); if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) { return self.tcx.ty_error(); } </ins> <del> common_type </del> <ins> // 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 </ins> } fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<'_>) {

E0029, "only `char` and numeric types are allowed in range patterns" ); <del> let msg = |ty| format!("this is of type `{}` but it should be `char` or numeric", ty); </del> <ins> let msg = |ty| { let ty = self.resolve_vars_if_possible(ty); format!("this is of type `{}` but it should be `char` or numeric", ty) }; </ins> let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| { err.span_label(first_span, &msg(first_ty)); if let Some((_, ty, sp)) = second { <ins> let ty = self.resolve_vars_if_possible(ty); </ins> self.endpoint_has_type(&mut err, sp, ty); } };

<ins> 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(); } </ins>

<ins> 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`. </ins>

<ins> // check-pass trait Zero { const ZERO: Self; } impl Zero for i32 { const ZERO: Self = 0; } fn main() { match 1 { Zero::ZERO ..= 1 => {}, _ => {}, } } </ins>

Neg = -1, Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns //~| ERROR arbitrary expressions aren't allowed in patterns <del> //~| ERROR only `char` and numeric types are allowed in range patterns </del> }); fn main() {}

LL |     Arith = 1 + 1, |             ^^^^^ <del> error[E0029]: only `char` and numeric types are allowed in range patterns --> $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 </del> <ins> error: aborting due to 2 previous errors </ins> <del> For more information about this error, try `rustc --explain E0029`. </del>