stride3d/stride · error · NotImplementedException
Binary operator not supported for element type
Error message
Binary operator {op} not supported for element type {elementType} What it means
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.
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
Example fix
// before
if (a > b) { ... } // a, b are bool2
// after
if (a.x == b.x && a.y == b.y) { ... } // or compare a numeric projection Defensive patterns
Strategy: type-guard
Validate before calling
if (!(elementType.IsInteger() || elementType.IsFloating()))
throw new InvalidOperationException($"Relational operator {op} requires numeric element type, got {elementType}"); Type guard
bool IsComparableType(ScalarType t) => t.IsInteger() || t.IsFloating();
Try / catch
try { opCode = SelectBinaryOp(op, elementType); }
catch (NotImplementedException ex) when (ex.Message.Contains("Binary operator"))
{ /* fall back to manual comparison or fail the pass with a clear diagnostic */ } Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Can't add type
- Can't cast between array of different sizes
- Can't cast between array of different types
- Can't cast between structures
- Can't cast from to (more components)
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/2fd40aeaf41e2f58.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs:376
(Operator.NotEquals, ScalarType { Type: Scalar.Boolean }) => Specification.Op.OpLogicalNotEqual,
(Operator.NotEquals, _) when elementType.IsInteger() => Specification.Op.OpINotEqual,
(Operator.NotEquals, _) when elementType.IsFloating() => Specification.Op.OpFOrdNotEqual,
// Comparison
(Operator.Lower, _) when elementType.IsUnsignedInteger() => Specification.Op.OpULessThan,
(Operator.Lower, _) when elementType.IsInteger() => Specification.Op.OpSLessThan,
(Operator.Lower, _) when elementType.IsFloating() => Specification.Op.OpFOrdLessThan,
(Operator.LowerOrEqual, _) when elementType.IsUnsignedInteger() => Specification.Op.OpULessThanEqual,
(Operator.LowerOrEqual, _) when elementType.IsInteger() => Specification.Op.OpSLessThanEqual,
(Operator.LowerOrEqual, _) when elementType.IsFloating() => Specification.Op.OpFOrdLessThanEqual,
(Operator.Greater, _) when elementType.IsUnsignedInteger() => Specification.Op.OpUGreaterThan,
(Operator.Greater, _) when elementType.IsInteger() => Specification.Op.OpSGreaterThan,
(Operator.Greater, _) when elementType.IsFloating() => Specification.Op.OpFOrdGreaterThan,
(Operator.GreaterOrEqual, _) when elementType.IsUnsignedInteger() => Specification.Op.OpUGreaterThanEqual,
(Operator.GreaterOrEqual, _) when elementType.IsInteger() => Specification.Op.OpSGreaterThanEqual,
(Operator.GreaterOrEqual, _) when elementType.IsFloating() => Specification.Op.OpFOrdGreaterThanEqual,
_ => throw new NotImplementedException($"Binary operator {op} not supported for element type {elementType}")
};
/// <summary>
/// Check if a type can be converted to another.
/// </summary>
/// <param name="valueType"></param>
/// <param name="castType"></param>
/// <returns>0 if perfect match, int.MaxValue if failure, a score higher than 0 otherwise.</returns>
public static int CanConvertScore(SymbolType valueType, SymbolType castType)
{
if (castType == valueType)
return 0;
if (castType is StructType || valueType is StructType)
throw new NotImplementedException($"Can't cast between structures (cast from {valueType} to {castType})");
if (castType is ArrayType a1 && valueType is ArrayType a2)
{View on GitHub (pinned to 96fad776d2)