{"record":{"id":"87895ae1422ef06a","repo":"rust-lang/rust-analyzer","slug":"segments-are-always-nested-in-paths","errorCode":null,"errorMessage":"segments are always nested in paths","messagePattern":"segments are always nested in paths","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/syntax/src/ast/node_ext.rs","lineNumber":338,"sourceCode":"    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum PathSegmentKind {\n    Name(ast::NameRef),\n    Type { type_ref: Option<ast::Type>, trait_ref: Option<ast::PathType> },\n    SelfTypeKw,\n    SelfKw,\n    SuperKw,\n    CrateKw,\n}\n\nimpl ast::PathSegment {\n    pub fn parent_path(&self) -> ast::Path {\n        self.syntax()\n            .parent()\n            .and_then(ast::Path::cast)\n            .expect(\"segments are always nested in paths\")\n    }\n\n    pub fn crate_token(&self) -> Option<SyntaxToken> {\n        self.name_ref().and_then(|it| it.crate_token())\n    }\n\n    pub fn self_token(&self) -> Option<SyntaxToken> {\n        self.name_ref().and_then(|it| it.self_token())\n    }\n\n    pub fn self_type_token(&self) -> Option<SyntaxToken> {\n        self.name_ref().and_then(|it| it.Self_token())\n    }\n\n    pub fn super_token(&self) -> Option<SyntaxToken> {\n        self.name_ref().and_then(|it| it.super_token())\n    }\n","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/syntax/src/ast/node_ext.rs#L320-L356","documentation":"ast::PathSegment::parent_path() asserts that a path segment's parent in the syntax tree is always a Path node. It casts the parent and panics if the cast fails. The grammar guarantees PathSegment only appears inside Path, so a panic signals a hand-built or corrupted tree rather than user code error.","triggerScenarios":"Calling parent_path() on a PathSegment node detached from a tree (no parent), on a synthetic segment whose parent is not a Path, or after tree mutation reparented the segment. Called by top_path() and validate_path_keywords().","commonSituations":"Constructing synthetic AST nodes in tests or IDE assists without a Path parent; mutating the tree and keeping stale segment references; incremental-reparse corruption (report upstream).","solutions":["Ensure the segment belongs to a parsed tree and is not detached before calling parent_path().","After tree mutations, re-query the segment from the new tree instead of reusing stale syntax nodes.","Use a defensive cast (syntax().parent().and_then(ast::Path::cast)) if you must handle synthetic nodes.","If reproducible on plain parsed source, minimize and file a rust-analyzer parser bug."],"exampleFix":"// before\nlet path = segment.parent_path();\n// after\nlet path = segment.syntax().parent().and_then(ast::Path::cast);\nif let Some(path) = path { /* ... */ }","handlingStrategy":"type-guard","validationCode":"// Verify the segment is attached with a Path parent before calling parent_path\nfn segment_has_path_parent(segment: &ast::PathSegment) -> bool {\n    segment.syntax().parent().map_or(false, |p| ast::Path::can_cast(p.kind()))\n}","typeGuard":"fn safe_parent_path(segment: &ast::PathSegment) -> Option<ast::Path> {\n    segment.syntax().parent().and_then(ast::Path::cast)\n}","tryCatchPattern":"let path = std::panic::catch_unwind(AssertUnwindSafe(|| segment.parent_path()))\n    .ok()\n    .or_else(|| segment.syntax().parent().and_then(ast::Path::cast));","preventionTips":["Never call on detached/synthetic PathSegment nodes.","Drop stale syntax node references after tree edits and re-query.","In IDE assists, re-resolve nodes from the current file version.","Use and_then(cast) chains instead of expect in downstream code."],"tags":["rust","syntax","ast","invariant"],"backgroundTag":"ast-invariant-panic","analyzedSha":"e8f7e90aa3e7b26aa9a000200f606c1078da99ec","analyzedAt":"2026-09-03T21:08:06.959Z","contentChangedAt":"2026-09-03T21:08:06.959Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}