{"record":{"id":"51e3ef38b478204e","repo":"gleam-lang/gleam","slug":"trailing-zeros-to-return-a-value-for-non-zero-numbers","errorCode":null,"errorMessage":"trailing_zeros to return a value for non-zero numbers","messagePattern":"trailing_zeros to return a value for non-zero numbers","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler-core/src/exhaustiveness.rs","lineNumber":4243,"sourceCode":"        return false;\n    }\n\n    let required_bits = match (value.sign(), signed) {\n        // Zero always needs one bit.\n        (Sign::NoSign, _) => 1,\n\n        // `BigInt::bits` does not consider the sign!\n        (Sign::Plus, false) => value.bits(),\n        // Therefore we need to add the sign bit here: `10` -> `010`\n        (Sign::Plus, true) => value.bits() + 1,\n\n        // A negative number must be signed\n        (Sign::Minus, false) => return false,\n        (Sign::Minus, true) => {\n            let bits_unsigned = value.bits();\n            let trailing_zeros = value\n                .trailing_zeros()\n                .expect(\"trailing_zeros to return a value for non-zero numbers\");\n            let is_power_of_2 = trailing_zeros == bits_unsigned - 1;\n\n            // Negative powers of two don't need an extra sign bit. E.g. `-2 == 0b10`\n            if is_power_of_2 {\n                bits_unsigned\n            } else {\n                bits_unsigned + 1\n            }\n        }\n    };\n\n    match required_bits.to_u32() {\n        Some(required_bits) => bits >= required_bits,\n        None => false,\n    }\n}\n\n#[cfg(test)]","sourceCodeStart":4225,"sourceCodeEnd":4261,"githubUrl":"https://github.com/gleam-lang/gleam/blob/49f8762da595eb3c8f576656a4200a142ca188c9/compiler-core/src/exhaustiveness.rs#L4225-L4261","documentation":"When computing the required bit width for a negative integer pattern (adding sign bits), the code calls `trailing_zeros().expect(...)` which panics if the BigInt is zero — `trailing_zeros` returns None only for zero, but the comment says it is expected to be non-zero here. A zero value reaching this branch means the earlier zero/sign classification was wrong.","triggerScenarios":"The exhaustiveness integer-range analysis classifies a value as `Sign::Minus` (negative) but the value is actually zero, so `trailing_zeros()` returns None and the expect panics.","commonSituations":"Seen when adding large/edge-case integer literals to bit-array or case pattern checks in Gleam; typically caused by a sign-detection bug (e.g. comparing magnitudes incorrectly) or a custom BigInt literal that round-trips to zero.","solutions":["Fix the sign classification so zero is never classified as `Sign::Minus` (check `value == 0` before the match)","Return the appropriate bit width directly for zero values before entering the negative branch","Use `trailing_zeros().unwrap_or(bits_unsigned - 1)` style fallback only if zero can legitimately arrive","Report a compiler bug with the literal that triggers it"],"exampleFix":"// before\nlet trailing_zeros = value.trailing_zeros().expect(\"trailing_zeros to return a value for non-zero numbers\");\n// after\nlet Some(trailing_zeros) = value.trailing_zeros() else {\n    return 1; // value is zero despite negative sign classification\n};","handlingStrategy":"type-guard","validationCode":"if value.sign() == Sign::NoSign {\n    return 1; // zero\n}","typeGuard":"let Some(trailing_zeros) = value.trailing_zeros() else { return fallback_width(value); };","tryCatchPattern":null,"preventionTips":["Classify zero explicitly before the Sign::Minus branch","Use exhaustive match on (sign, is_signed) including the zero case","Property-test bit-width computation over negative, zero, and boundary BigInts"],"tags":["rust","integers","bit-width","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"49f8762da595eb3c8f576656a4200a142ca188c9","analyzedAt":"2026-09-14T11:14:59.388Z","contentChangedAt":"2026-09-14T11:14:59.388Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}