{"record":{"id":"c70fc5c0699e29b9","repo":"zed-industries/zed","slug":"operands-of-must-be-identifiers-c70fc5","errorCode":null,"errorMessage":"operands of != must be identifiers","messagePattern":"operands of != must be identifiers","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gpui/src/keymap/context.rs","lineNumber":443,"sourceCode":"    }\n\n    fn new_child(self, other: Self) -> Result<Self> {\n        Ok(Self::Descendant(Box::new(self), Box::new(other)))\n    }\n\n    fn new_eq(self, other: Self) -> Result<Self> {\n        if let (Self::Identifier(left), Self::Identifier(right)) = (self, other) {\n            Ok(Self::Equal(left, right))\n        } else {\n            anyhow::bail!(\"operands of == must be identifiers\");\n        }\n    }\n\n    fn new_neq(self, other: Self) -> Result<Self> {\n        if let (Self::Identifier(left), Self::Identifier(right)) = (self, other) {\n            Ok(Self::NotEqual(left, right))\n        } else {\n            anyhow::bail!(\"operands of != must be identifiers\");\n        }\n    }\n\n    fn fmt_joined(\n        &self,\n        f: &mut fmt::Formatter<'_>,\n        separator: &str,\n        operator: LogicalOperator,\n        needs_parens: impl Fn(&Self) -> bool + Copy,\n    ) -> fmt::Result {\n        let mut first = true;\n        self.fmt_joined_inner(f, separator, operator, needs_parens, &mut first)\n    }\n\n    fn fmt_joined_inner(\n        &self,\n        f: &mut fmt::Formatter<'_>,\n        separator: &str,","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/gpui/src/keymap/context.rs#L425-L461","documentation":"new_neq mirrors new_eq: '!=' is only defined between two Identifier predicates because evaluation resolves the left identifier's value and compares it for inequality. A composite operand (group, &&/|| chain, '>' descendant, negation) on either side makes the constructor bail.","triggerScenarios":"Writing 'mode != (a || b)', '(a && b) != c', or '!a != b' — any != whose operands are not both identifiers.","commonSituations":"Negated comparisons against multiple values; mixing precedence parentheses into inequality expressions; porting boolean shapes from other tools.","solutions":["Keep both sides of != as bare identifiers: mode != normal","Express multi-value exclusion as a chain: (mode != normal && mode != visual)","Place negation outside the whole comparison if needed: !(mode == normal)"],"exampleFix":"// before (keymap.json)\n\"context\": \"mode != (normal || visual)\"\n\n// after\n\"context\": \"(mode != normal && mode != visual)\"","handlingStrategy":"validation","validationCode":"KeyBindingContextPredicate::parse(\"(mode != normal && mode != visual)\")?; // validate before install","typeGuard":"fn is_parseable_context(source: &str) -> bool {\n    KeyBindingContextPredicate::parse(source).is_ok()\n}","tryCatchPattern":null,"preventionTips":["Remember == and != combine identifiers only","Express multi-value exclusion as chained != comparisons","Put negation outside the whole comparison: !(mode == normal)"],"tags":["gpui","keymap","parsing","keyboard-shortcuts","dsl"],"backgroundTag":"keymap-parse-error","analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}