{"record":{"id":"c4b7a3a4c86ecf8f","repo":"astral-sh/ruff","slug":"matched-type-divergent-above","errorCode":null,"errorMessage":"matched `Type::Divergent` above","messagePattern":"matched `Type::Divergent` above","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ty_python_semantic/src/types.rs","lineNumber":2711,"sourceCode":"\n    /// Returns `Some(UnionType)` if this type behaves like a union. Apart from explicit unions,\n    /// this returns `Some` for `TypeAlias`es of unions and `NewType`s of `float` and `complex`.\n    fn as_union_like(self, db: &'db dyn Db) -> Option<UnionType<'db>> {\n        match self.resolve_type_alias(db) {\n            Type::Union(union) => Some(union),\n            Type::NewTypeInstance(newtype) => newtype.concrete_base_type(db).as_union_like(db),\n            _ => None,\n        }\n    }\n\n    const fn as_dynamic(self) -> Option<DynamicType<'db>> {\n        match self {\n            Type::Dynamic(dynamic_type) => Some(dynamic_type),\n            _ => None,\n        }\n    }\n\n    const fn as_callable(self) -> Option<CallableType<'db>> {\n        match self {\n            Type::Callable(callable_type) => Some(callable_type),\n            _ => None,\n        }\n    }\n\n    const fn expect_dynamic(self) -> DynamicType<'db> {\n        self.as_dynamic().expect(\"Expected a Type::Dynamic variant\")\n    }\n\n    const fn as_protocol_instance(self) -> Option<ProtocolInstanceType<'db>> {\n        match self {\n            Type::ProtocolInstance(instance) => Some(instance),\n            _ => None,\n        }\n    }\n\n    #[cfg(test)]","sourceCodeStart":2693,"sourceCodeEnd":2729,"githubUrl":"https://github.com/astral-sh/ruff/blob/15f3fe6b15a5f00172f34b0f542f8ea277f5a586/crates/ty_python_semantic/src/types.rs#L2693-L2729","documentation":"Type::negate special-cases Type::Divergent through negated_divergent(), which returns an Option because not every divergent type has a meaningful negation. Inside the Divergent match arm the Option is unwrapped: the arm guarantees the outer variant, so a None means a divergent sub-case without negation support reached the fast path that bypasses the IntersectionBuilder.","triggerScenarios":"Negating a Divergent type whose kind has no negation rule - a newly added Divergent variant for which negated_divergent returns None - while the fast path in negate() skips the general intersection machinery that would otherwise handle it.","commonSituations":"Contributor additions of new divergent-type flavors (TypeIs-like constructs) without a negation rule; refactors of the negation fast path. The property test all_negated_types_identical_to_intersection_with_single_negated_element guards the equivalence.","solutions":["File a ty issue with the expression triggering negation (typically `not x` narrowing) and the backtrace","As a contributor: implement the missing negation in negated_divergent, or route that variant through the IntersectionBuilder path instead of the fast path","Re-run the referenced property test after any change to negation logic"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"fn has_negation_divergent(ty: Type<'_>) -> bool {\n    // mirrors negated_divergent()'s Option contract\n    ty.negated_divergent().is_some()\n}","tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| check_file(&db, file)));\nmatch result {\n    Ok(diags) => diags,\n    Err(payload) => { log::warn!(\"ty panicked during negation of {}: {:?}\", file, payload); vec![] }\n}","preventionTips":["Run the negation property test (all_negated_types_identical_to_intersection_with_single_negated_element) after touching negate() or Divergent","When adding a Divergent sub-case, either implement its negation or route it through the IntersectionBuilder path","Test `not x` narrowing for every new divergent construct"],"tags":["rust","ty","types","negation","divergent","panic"],"backgroundTag":"enum-variant-expect-mismatch","analyzedSha":"15f3fe6b15a5f00172f34b0f542f8ea277f5a586","analyzedAt":"2026-08-20T16:33:49.445Z","contentChangedAt":"2026-08-20T16:33:49.445Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}