|
1 | 1 | use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; |
| 2 | +use clippy_utils::higher::Range; |
2 | 3 | use clippy_utils::source::SpanRangeExt; |
3 | 4 | use clippy_utils::ty::{expr_type_is_certain, has_drop}; |
4 | 5 | use clippy_utils::{ |
@@ -355,6 +356,26 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(Ve |
355 | 356 | ExprKind::Cast(inner, _) if expr_type_is_certain(cx, inner) => { |
356 | 357 | reduce_expression(cx, inner).or_else(|| Some((vec![inner], Applicability::MachineApplicable))) |
357 | 358 | }, |
| 359 | + // In the normal `Struct` case, we bail out if any of the fields has an uncertain type. |
| 360 | + // But for two-sided ranges, we know that if the type of one of the sides is certain, then so is the other |
| 361 | + // one's. So we only check that, more relaxed pre-condition. |
| 362 | + // |
| 363 | + // Note that that condition true in general for any struct with a generic present in two fields, but |
| 364 | + // generalizing the check to those would be cumbersome. |
| 365 | + ExprKind::Struct(..) |
| 366 | + if let Some(range) = Range::hir(expr) |
| 367 | + && let Some(start) = range.start |
| 368 | + && let Some(end) = range.end => |
| 369 | + { |
| 370 | + let applicability = if [start, end].into_iter().any(|e| expr_type_is_certain(cx, e)) { |
| 371 | + Applicability::MachineApplicable |
| 372 | + } else { |
| 373 | + // there's a risk that if we take the field exprs out of the context of the range constructor, |
| 374 | + // their types might become ambiguous |
| 375 | + Applicability::MaybeIncorrect |
| 376 | + }; |
| 377 | + Some((vec![start, end], applicability)) |
| 378 | + }, |
358 | 379 | ExprKind::Struct(_, fields, ref base) => { |
359 | 380 | let applicability = if fields.iter().all(|f| expr_type_is_certain(cx, f.expr)) { |
360 | 381 | Applicability::MachineApplicable |
|
0 commit comments