From 9e0ae5122312fb3a6d53adbcbc7b2110c866da46 Mon Sep 17 00:00:00 2001 From: wasd243 Date: Fri, 10 Jul 2026 11:00:08 -0400 Subject: [PATCH 1/5] `missing_asserts_for_indexing`: don't lint when `match` on `len()` guarantees the index is in bounds --- .../src/missing_asserts_for_indexing.rs | 95 ++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 005f1c929a9a..319dfdb0a01e 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -7,12 +7,12 @@ use clippy_utils::higher::{If, Range}; use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace, root_macro_call}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{eq_expr_value, hash_expr}; +use clippy_utils::{eq_expr_value, hash_expr, is_wild}; use rustc_ast::{BinOpKind, LitKind, RangeLimits}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnindexMap; use rustc_errors::{Applicability, Diag}; -use rustc_hir::{Block, Body, Expr, ExprKind, UnOp}; +use rustc_hir::{Arm, Block, Body, Expr, ExprKind, MatchSource, Node, PatExprKind, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::{Span, Spanned, Symbol, sym}; @@ -123,6 +123,96 @@ fn len_comparison<'hir>( } } +/// Checks if the index expression is inside a `match` on the slice's length +/// whose arms make the indexing infallible, e.g. +/// +/// ```no_run +/// # let supported: &[u8] = &[]; +/// match supported.len() { +/// 0 => {}, +/// 1 => println!("{}", supported[0]), +/// _ => println!("{} or {}", supported[0], supported[1]), +/// } +/// ``` +/// +/// Here the `0` and `1` arms rule out all lengths below 2, so `supported[0]` +/// and `supported[1]` in the wildcard arm cannot fail and the bounds checks +/// are elided without an `assert!`. The lint should not fire in this case. +/// +/// This only applies when the non-wildcard arms are integer literals that +/// contiguously cover `0..=max` (see [`match_arms_bound_len `]); otherwise the wildcard +/// arm gives no lower bound on the length and the lint fires as usual. +fn is_index_covered_by_match(cx: &LateContext<'_>, index_expr: &Expr<'_>, slice: &Expr<'_>) -> bool { + for (_, node) in cx.tcx.hir_parent_iter(index_expr.hir_id) { + match node { + Node::Expr(expr) => { + if let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = expr.kind + && is_slice_len_expr(cx, scrutinee, slice) + && match_arms_bound_len (cx, index_expr, arms) + { + return arms.iter().any(|arm| is_wild(arm.pat)); + } + }, + Node::Block(_) | Node::Stmt(_) | Node::Arm(_) | Node::LetStmt(_) => {}, + _ => return false, + } + } + false +} + +/// Checks if the non-wildcard arms are integer literals contiguously covering +/// `0..=max`, so that the wildcard arm implies `len > max`. Returns `true` +/// only if the index used is at most `max`, i.e. provably in bounds. +fn match_arms_bound_len (cx: &LateContext<'_>, index_expr: &Expr<'_>, arms: &[Arm<'_>]) -> bool { + let ExprKind::Index(_, index_lit, _) = index_expr.kind else { + return false; + }; + let Some(index) = upper_index_expr(cx, index_lit) else { + return false; + }; + + let mut excluded = Vec::new(); + for arm in arms { + if arm.guard.is_some() { + return false; + } + if is_wild(arm.pat) { + continue; + } + let PatKind::Expr(pat_expr) = arm.pat.kind else { + return false; + }; + let PatExprKind::Lit { lit, .. } = pat_expr.kind else { + return false; + }; + let LitKind::Int(Pu128(n), _) = lit.node else { + return false; + }; + excluded.push(n as usize); + } + + if excluded.is_empty() { + return false; + } + + excluded.sort_unstable(); + excluded.dedup(); + + // literals must be exactly 0..=max, so `_` implies len > max + let max = *excluded.last().unwrap(); + excluded.len() == max + 1 && index <= max +} + +fn is_slice_len_expr(cx: &LateContext<'_>, expr: &Expr<'_>, slice: &Expr<'_>) -> bool { + if let ExprKind::MethodCall(method, recv, [], _) = expr.kind + && method.ident.name == sym::len + { + eq_expr_value(cx, expr.span.ctxt(), recv, slice) + } else { + false + } +} + /// Attempts to extract parts out of an `assert!`-like expression /// in the form `assert!(some_slice.len() > 5)`. /// @@ -239,6 +329,7 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Uni if let ExprKind::Index(slice, index_lit, _) = expr.kind && cx.typeck_results().expr_ty_adjusted(slice).peel_refs().is_slice() && let Some(index) = upper_index_expr(cx, index_lit) + && !is_index_covered_by_match(cx, expr, slice) { let hash = hash_expr(cx, slice); From 1b37dc23fae8d4a2c386a49778e45f9e9c17a8e3 Mon Sep 17 00:00:00 2001 From: wasd243 Date: Fri, 10 Jul 2026 12:03:37 -0400 Subject: [PATCH 2/5] add tests for `match` check --- .../src/missing_asserts_for_indexing.rs | 4 +- tests/ui/missing_asserts_for_indexing.fixed | 20 ++++++++++ tests/ui/missing_asserts_for_indexing.rs | 20 ++++++++++ .../missing_asserts_for_indexing_unfixable.rs | 38 +++++++++++++++++++ ...sing_asserts_for_indexing_unfixable.stderr | 34 ++++++++++++++++- 5 files changed, 113 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 319dfdb0a01e..30eda82f141e 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -148,7 +148,7 @@ fn is_index_covered_by_match(cx: &LateContext<'_>, index_expr: &Expr<'_>, slice: Node::Expr(expr) => { if let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = expr.kind && is_slice_len_expr(cx, scrutinee, slice) - && match_arms_bound_len (cx, index_expr, arms) + && match_arms_bound_len(cx, index_expr, arms) { return arms.iter().any(|arm| is_wild(arm.pat)); } @@ -163,7 +163,7 @@ fn is_index_covered_by_match(cx: &LateContext<'_>, index_expr: &Expr<'_>, slice: /// Checks if the non-wildcard arms are integer literals contiguously covering /// `0..=max`, so that the wildcard arm implies `len > max`. Returns `true` /// only if the index used is at most `max`, i.e. provably in bounds. -fn match_arms_bound_len (cx: &LateContext<'_>, index_expr: &Expr<'_>, arms: &[Arm<'_>]) -> bool { +fn match_arms_bound_len(cx: &LateContext<'_>, index_expr: &Expr<'_>, arms: &[Arm<'_>]) -> bool { let ExprKind::Index(_, index_lit, _) = index_expr.kind else { return false; }; diff --git a/tests/ui/missing_asserts_for_indexing.fixed b/tests/ui/missing_asserts_for_indexing.fixed index f877cbc1f114..65a744954e85 100644 --- a/tests/ui/missing_asserts_for_indexing.fixed +++ b/tests/ui/missing_asserts_for_indexing.fixed @@ -180,4 +180,24 @@ mod issue15988 { } } +mod issue17398 { + // ok + fn fix_match_case(supported: &[u8]) { + match supported.len() { + 0 => {}, + 1 => println!("{}", supported[0]), + _ => println!("{} or {}", supported[0], supported[1]), + } + } + + // ok + fn one_index_too_high(supported: &[u8]) { + match supported.len() { + 0 => {}, + 1 => {}, + _ => println!("{} {} {}", supported[0], supported[1], supported[2]), + } + } +} + fn main() {} diff --git a/tests/ui/missing_asserts_for_indexing.rs b/tests/ui/missing_asserts_for_indexing.rs index 8084e0b71be9..624d249e316a 100644 --- a/tests/ui/missing_asserts_for_indexing.rs +++ b/tests/ui/missing_asserts_for_indexing.rs @@ -180,4 +180,24 @@ mod issue15988 { } } +mod issue17398 { + // ok + fn fix_match_case(supported: &[u8]) { + match supported.len() { + 0 => {}, + 1 => println!("{}", supported[0]), + _ => println!("{} or {}", supported[0], supported[1]), + } + } + + // ok + fn one_index_too_high(supported: &[u8]) { + match supported.len() { + 0 => {}, + 1 => {}, + _ => println!("{} {} {}", supported[0], supported[1], supported[2]), + } + } +} + fn main() {} diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.rs b/tests/ui/missing_asserts_for_indexing_unfixable.rs index b8cdb71bd30a..5d9770062680 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.rs +++ b/tests/ui/missing_asserts_for_indexing_unfixable.rs @@ -85,4 +85,42 @@ fn issue14255(v1: &[u8]) { //~^ missing_asserts_for_indexing } +// not contiguous from 0: `_` can still be 0 +fn non_contiguous(supported: &[u8]) { + match supported.len() { + 5 => {}, + _ => println!("{} or {}", supported[0], supported[1]), + //~^ missing_asserts_for_indexing + } +} + +// wildcard only: no length information +#[allow(clippy::match_single_binding)] +fn wildcard_only(supported: &[u8]) { + match supported.len() { + _ => println!("{} or {}", supported[0], supported[1]), + //~^ missing_asserts_for_indexing + } +} + +// guard defeats the exclusion +fn with_guard(supported: &[u8], flag: bool) { + match supported.len() { + 0 if flag => {}, + 1 => {}, + _ => println!("{} or {}", supported[0], supported[1]), + //~^ missing_asserts_for_indexing + } +} + +// arms only guarantee len > 1, but 2 and 3 are indexed +fn index_too_high(supported: &[u8]) { + match supported.len() { + 0 => {}, + 1 => {}, + _ => println!("{} {}", supported[2], supported[3]), + //~^ missing_asserts_for_indexing + } +} + fn main() {} diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/tests/ui/missing_asserts_for_indexing_unfixable.stderr index fe929aa36dba..86eb47524824 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.stderr +++ b/tests/ui/missing_asserts_for_indexing_unfixable.stderr @@ -89,5 +89,37 @@ LL | let _ = v1[0] + v1[1] + v1[2]; | = help: consider asserting the length before indexing: `assert!(v1.len() > 2);` -error: aborting due to 10 previous errors +error: indexing into a slice multiple times without an `assert` + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:92:35 + | +LL | _ => println!("{} or {}", supported[0], supported[1]), + | ^^^^^^^^^^^^ ^^^^^^^^^^^^ + | + = help: consider asserting the length before indexing: `assert!(supported.len() > 1);` + +error: indexing into a slice multiple times without an `assert` + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:101:35 + | +LL | _ => println!("{} or {}", supported[0], supported[1]), + | ^^^^^^^^^^^^ ^^^^^^^^^^^^ + | + = help: consider asserting the length before indexing: `assert!(supported.len() > 1);` + +error: indexing into a slice multiple times without an `assert` + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:111:35 + | +LL | _ => println!("{} or {}", supported[0], supported[1]), + | ^^^^^^^^^^^^ ^^^^^^^^^^^^ + | + = help: consider asserting the length before indexing: `assert!(supported.len() > 1);` + +error: indexing into a slice multiple times without an `assert` + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:121:32 + | +LL | _ => println!("{} {}", supported[2], supported[3]), + | ^^^^^^^^^^^^ ^^^^^^^^^^^^ + | + = help: consider asserting the length before indexing: `assert!(supported.len() > 3);` + +error: aborting due to 14 previous errors From d5560c852316b0ba1d0b28d95c179cdc6e674c9e Mon Sep 17 00:00:00 2001 From: Zichen Wang Date: Fri, 10 Jul 2026 17:30:30 -0400 Subject: [PATCH 3/5] Update clippy_lints/src/missing_asserts_for_indexing.rs Co-authored-by: Gri-ffin <82527700+Gri-ffin@users.noreply.github.com> --- .../src/missing_asserts_for_indexing.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 30eda82f141e..5c4ff075a5dc 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -124,23 +124,9 @@ fn len_comparison<'hir>( } /// Checks if the index expression is inside a `match` on the slice's length -/// whose arms make the indexing infallible, e.g. -/// -/// ```no_run -/// # let supported: &[u8] = &[]; -/// match supported.len() { -/// 0 => {}, -/// 1 => println!("{}", supported[0]), -/// _ => println!("{} or {}", supported[0], supported[1]), -/// } -/// ``` -/// -/// Here the `0` and `1` arms rule out all lengths below 2, so `supported[0]` -/// and `supported[1]` in the wildcard arm cannot fail and the bounds checks -/// are elided without an `assert!`. The lint should not fire in this case. -/// +/// whose arms make the indexing infallible. /// This only applies when the non-wildcard arms are integer literals that -/// contiguously cover `0..=max` (see [`match_arms_bound_len `]); otherwise the wildcard +/// contiguously cover `0..=max` otherwise the wildcard /// arm gives no lower bound on the length and the lint fires as usual. fn is_index_covered_by_match(cx: &LateContext<'_>, index_expr: &Expr<'_>, slice: &Expr<'_>) -> bool { for (_, node) in cx.tcx.hir_parent_iter(index_expr.hir_id) { From afc877ef014e6870ec847e80f66acd9e5b887aec Mon Sep 17 00:00:00 2001 From: wasd243 Date: Fri, 10 Jul 2026 17:59:50 -0400 Subject: [PATCH 4/5] Change `excluded` to `matched_lens` --- clippy_lints/src/missing_asserts_for_indexing.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 5c4ff075a5dc..8b1a1eeae5a5 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -157,7 +157,7 @@ fn match_arms_bound_len(cx: &LateContext<'_>, index_expr: &Expr<'_>, arms: &[Arm return false; }; - let mut excluded = Vec::new(); + let mut matched_lens = Vec::new(); for arm in arms { if arm.guard.is_some() { return false; @@ -174,19 +174,19 @@ fn match_arms_bound_len(cx: &LateContext<'_>, index_expr: &Expr<'_>, arms: &[Arm let LitKind::Int(Pu128(n), _) = lit.node else { return false; }; - excluded.push(n as usize); + matched_lens.push(n as usize); } - if excluded.is_empty() { + if matched_lens.is_empty() { return false; } - excluded.sort_unstable(); - excluded.dedup(); + matched_lens.sort_unstable(); + matched_lens.dedup(); // literals must be exactly 0..=max, so `_` implies len > max - let max = *excluded.last().unwrap(); - excluded.len() == max + 1 && index <= max + let max = *matched_lens.last().unwrap(); + matched_lens.len() == max + 1 && index <= max } fn is_slice_len_expr(cx: &LateContext<'_>, expr: &Expr<'_>, slice: &Expr<'_>) -> bool { From cd5f376ea94a5d24c74503d0c8c1f17cbeca2e79 Mon Sep 17 00:00:00 2001 From: wasd243 Date: Fri, 10 Jul 2026 18:35:34 -0400 Subject: [PATCH 5/5] fix(missing_asserts_for_indexing): reject indices at or past the literal arm's length --- .../src/missing_asserts_for_indexing.rs | 51 +++++++++++++------ tests/ui/missing_asserts_for_indexing.fixed | 11 ++++ tests/ui/missing_asserts_for_indexing.rs | 11 ++++ .../missing_asserts_for_indexing_unfixable.rs | 11 ++++ ...sing_asserts_for_indexing_unfixable.stderr | 10 +++- 5 files changed, 77 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 8b1a1eeae5a5..43ee94c86622 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -129,17 +129,19 @@ fn len_comparison<'hir>( /// contiguously cover `0..=max` otherwise the wildcard /// arm gives no lower bound on the length and the lint fires as usual. fn is_index_covered_by_match(cx: &LateContext<'_>, index_expr: &Expr<'_>, slice: &Expr<'_>) -> bool { + let mut containing_arm = None; for (_, node) in cx.tcx.hir_parent_iter(index_expr.hir_id) { match node { Node::Expr(expr) => { if let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = expr.kind && is_slice_len_expr(cx, scrutinee, slice) - && match_arms_bound_len(cx, index_expr, arms) + && match_arms_bound_len(cx, index_expr, arms, containing_arm) { return arms.iter().any(|arm| is_wild(arm.pat)); } }, - Node::Block(_) | Node::Stmt(_) | Node::Arm(_) | Node::LetStmt(_) => {}, + Node::Block(_) | Node::Stmt(_) | Node::LetStmt(_) => {}, + Node::Arm(arm) => containing_arm = Some(arm), _ => return false, } } @@ -149,7 +151,12 @@ fn is_index_covered_by_match(cx: &LateContext<'_>, index_expr: &Expr<'_>, slice: /// Checks if the non-wildcard arms are integer literals contiguously covering /// `0..=max`, so that the wildcard arm implies `len > max`. Returns `true` /// only if the index used is at most `max`, i.e. provably in bounds. -fn match_arms_bound_len(cx: &LateContext<'_>, index_expr: &Expr<'_>, arms: &[Arm<'_>]) -> bool { +fn match_arms_bound_len( + cx: &LateContext<'_>, + index_expr: &Expr<'_>, + arms: &[Arm<'_>], + containing_arm: Option<&Arm<'_>>, +) -> bool { let ExprKind::Index(_, index_lit, _) = index_expr.kind else { return false; }; @@ -157,6 +164,15 @@ fn match_arms_bound_len(cx: &LateContext<'_>, index_expr: &Expr<'_>, arms: &[Arm return false; }; + // index inside a literal arm `n => ...`: len is exactly `n` there, + // so anything at or past `n` is out of bounds + if let Some(arm) = containing_arm + && let Some(n) = arm_len_literal(arm) + && index >= n + { + return false; + } + let mut matched_lens = Vec::new(); for arm in arms { if arm.guard.is_some() { @@ -165,30 +181,33 @@ fn match_arms_bound_len(cx: &LateContext<'_>, index_expr: &Expr<'_>, arms: &[Arm if is_wild(arm.pat) { continue; } - let PatKind::Expr(pat_expr) = arm.pat.kind else { + let Some(n) = arm_len_literal(arm) else { return false; }; - let PatExprKind::Lit { lit, .. } = pat_expr.kind else { - return false; - }; - let LitKind::Int(Pu128(n), _) = lit.node else { - return false; - }; - matched_lens.push(n as usize); - } - - if matched_lens.is_empty() { - return false; + matched_lens.push(n); } matched_lens.sort_unstable(); matched_lens.dedup(); // literals must be exactly 0..=max, so `_` implies len > max - let max = *matched_lens.last().unwrap(); + let Some(&max) = matched_lens.last() else { + return false; + }; matched_lens.len() == max + 1 && index <= max } +fn arm_len_literal(arm: &Arm<'_>) -> Option { + if let PatKind::Expr(pat_expr) = arm.pat.kind + && let PatExprKind::Lit { lit, .. } = pat_expr.kind + && let LitKind::Int(Pu128(n), _) = lit.node + { + Some(n as usize) + } else { + None + } +} + fn is_slice_len_expr(cx: &LateContext<'_>, expr: &Expr<'_>, slice: &Expr<'_>) -> bool { if let ExprKind::MethodCall(method, recv, [], _) = expr.kind && method.ident.name == sym::len diff --git a/tests/ui/missing_asserts_for_indexing.fixed b/tests/ui/missing_asserts_for_indexing.fixed index 65a744954e85..5253d201676f 100644 --- a/tests/ui/missing_asserts_for_indexing.fixed +++ b/tests/ui/missing_asserts_for_indexing.fixed @@ -198,6 +198,17 @@ mod issue17398 { _ => println!("{} {} {}", supported[0], supported[1], supported[2]), } } + + // The `2 =>` arm's `supported[2]` is NOT suppressed (len == 2 there), + // but single remaining access never lints, same as `single_access`. + fn literal_arm_single_unsuppressed(supported: &[u8]) { + match supported.len() { + 0 => {}, + 1 => {}, + 2 => println!("{} {}", supported[0], supported[2]), + _ => println!("{} {}", supported[0], supported[2]), + } + } } fn main() {} diff --git a/tests/ui/missing_asserts_for_indexing.rs b/tests/ui/missing_asserts_for_indexing.rs index 624d249e316a..9a238fcfd52f 100644 --- a/tests/ui/missing_asserts_for_indexing.rs +++ b/tests/ui/missing_asserts_for_indexing.rs @@ -198,6 +198,17 @@ mod issue17398 { _ => println!("{} {} {}", supported[0], supported[1], supported[2]), } } + + // The `2 =>` arm's `supported[2]` is NOT suppressed (len == 2 there), + // but single remaining access never lints, same as `single_access`. + fn literal_arm_single_unsuppressed(supported: &[u8]) { + match supported.len() { + 0 => {}, + 1 => {}, + 2 => println!("{} {}", supported[0], supported[2]), + _ => println!("{} {}", supported[0], supported[2]), + } + } } fn main() {} diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.rs b/tests/ui/missing_asserts_for_indexing_unfixable.rs index 5d9770062680..f61c29097c84 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.rs +++ b/tests/ui/missing_asserts_for_indexing_unfixable.rs @@ -123,4 +123,15 @@ fn index_too_high(supported: &[u8]) { } } +// literal arm pins len to exactly 2, so indexing at 2 and 3 must lint +fn literal_arm_out_of_bounds(supported: &[u8]) { + match supported.len() { + 0 => {}, + 1 => {}, + 2 => println!("{} {}", supported[2], supported[3]), + //~^ missing_asserts_for_indexing + _ => {}, + } +} + fn main() {} diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/tests/ui/missing_asserts_for_indexing_unfixable.stderr index 86eb47524824..4fa83c452df5 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.stderr +++ b/tests/ui/missing_asserts_for_indexing_unfixable.stderr @@ -121,5 +121,13 @@ LL | _ => println!("{} {}", supported[2], supported[3]), | = help: consider asserting the length before indexing: `assert!(supported.len() > 3);` -error: aborting due to 14 previous errors +error: indexing into a slice multiple times without an `assert` + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:131:32 + | +LL | 2 => println!("{} {}", supported[2], supported[3]), + | ^^^^^^^^^^^^ ^^^^^^^^^^^^ + | + = help: consider asserting the length before indexing: `assert!(supported.len() > 3);` + +error: aborting due to 15 previous errors