{"record":{"id":"2fd40aeaf41e2f58","repo":"stride3d/stride","slug":"binary-operator-op-not-supported-for-element-type","errorCode":null,"errorMessage":"Binary operator {op} not supported for element type {elementType}","messagePattern":"Binary operator (.+?) not supported for element type (.+?)","errorType":"exception","errorClass":"NotImplementedException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs","lineNumber":376,"sourceCode":"        (Operator.NotEquals, ScalarType { Type: Scalar.Boolean }) => Specification.Op.OpLogicalNotEqual,\n        (Operator.NotEquals, _) when elementType.IsInteger() => Specification.Op.OpINotEqual,\n        (Operator.NotEquals, _) when elementType.IsFloating() => Specification.Op.OpFOrdNotEqual,\n\n        // Comparison\n        (Operator.Lower, _) when elementType.IsUnsignedInteger() => Specification.Op.OpULessThan,\n        (Operator.Lower, _) when elementType.IsInteger() => Specification.Op.OpSLessThan,\n        (Operator.Lower, _) when elementType.IsFloating() => Specification.Op.OpFOrdLessThan,\n        (Operator.LowerOrEqual, _) when elementType.IsUnsignedInteger() => Specification.Op.OpULessThanEqual,\n        (Operator.LowerOrEqual, _) when elementType.IsInteger() => Specification.Op.OpSLessThanEqual,\n        (Operator.LowerOrEqual, _) when elementType.IsFloating() => Specification.Op.OpFOrdLessThanEqual,\n        (Operator.Greater, _) when elementType.IsUnsignedInteger() => Specification.Op.OpUGreaterThan,\n        (Operator.Greater, _) when elementType.IsInteger() => Specification.Op.OpSGreaterThan,\n        (Operator.Greater, _) when elementType.IsFloating() => Specification.Op.OpFOrdGreaterThan,\n        (Operator.GreaterOrEqual, _) when elementType.IsUnsignedInteger() => Specification.Op.OpUGreaterThanEqual,\n        (Operator.GreaterOrEqual, _) when elementType.IsInteger() => Specification.Op.OpSGreaterThanEqual,\n        (Operator.GreaterOrEqual, _) when elementType.IsFloating() => Specification.Op.OpFOrdGreaterThanEqual,\n\n        _ => throw new NotImplementedException($\"Binary operator {op} not supported for element type {elementType}\")\n    };\n\n    /// <summary>\n    /// Check if a type can be converted to another.\n    /// </summary>\n    /// <param name=\"valueType\"></param>\n    /// <param name=\"castType\"></param>\n    /// <returns>0 if perfect match, int.MaxValue if failure, a score higher than 0 otherwise.</returns>\n    public static int CanConvertScore(SymbolType valueType, SymbolType castType)\n    {\n        if (castType == valueType)\n            return 0;\n\n        if (castType is StructType || valueType is StructType)\n            throw new NotImplementedException($\"Can't cast between structures (cast from {valueType} to {castType})\");\n\n        if (castType is ArrayType a1 && valueType is ArrayType a2)\n        {","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs#L358-L394","documentation":"SelectBinaryOp maps an Operator plus an element type to a concrete SPIR-V comparison/instruction opcode. If the (operator, elementType) pair has no entry in the switch — e.g. a relational operator on a boolean/pointer element type — it throws NotImplementedException because no valid SPIR-V opcode exists for that combination.","triggerScenarios":"Calling spirvOp/BinaryOperation with a comparison operator (Less, Greater, Equal, etc.) on a value whose component type is neither integer nor floating (e.g. bool vectors, or an operator like Modulus on a type with no matching mapping).","commonSituations":"Comparing bool vectors with < or >; comparing structures/arrays component-wise; type inference producing an unexpected element type after generics instantiation so the switch falls through.","solutions":["Ensure the compared operands have integer or floating-point scalar element types before applying relational operators","Cast operands to a numeric type (e.g. int/float) before comparison","Add the missing (Operator, elementType) case to SelectBinaryOp if the operation should be supported","Log elementType at the call site to see what type inference actually produced"],"exampleFix":"// before\nif (a > b) { ... } // a, b are bool2\n// after\nif (a.x == b.x && a.y == b.y) { ... } // or compare a numeric projection","handlingStrategy":"type-guard","validationCode":"if (!(elementType.IsInteger() || elementType.IsFloating()))\n    throw new InvalidOperationException($\"Relational operator {op} requires numeric element type, got {elementType}\");","typeGuard":"bool IsComparableType(ScalarType t) => t.IsInteger() || t.IsFloating();","tryCatchPattern":"try { opCode = SelectBinaryOp(op, elementType); }\ncatch (NotImplementedException ex) when (ex.Message.Contains(\"Binary operator\"))\n{ /* fall back to manual comparison or fail the pass with a clear diagnostic */ }","preventionTips":["Check operand element types are int/float before relational operators","Never compare bool/pointer-typed vectors with <, >, <=, >=","Log inferred element types when generics are involved"],"tags":["spirv","shader-compiler","binary-operator","type-system"],"backgroundTag":"unsupported-operation","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}