stride3d/stride · error · NotSupportedException

OpBitcast result type

Error message

OpBitcast result type {ReverseTypes[resultType]} is not a scalar

What it means

OpBitcast constant folding requires the bitcast's result type to be a scalar (int, uint, or float 32-bit); if ReverseTypes[resultType] is a vector, matrix, or any non-scalar type, the code throws NotSupportedException 'OpBitcast result type ... is not a scalar'. Bitcasting aggregate or non-32-bit types is not supported at compile-time fold.

Solutions

  1. Bitcast scalar components individually instead of the whole vector/composite constant.
  2. Keep the bitcast as a runtime instruction (avoid constant folding) so it executes per-component on the GPU.
  3. Extend the folding code to handle vector bitcasts component-wise if needed.

Example fix

// before
var bits = context.GetConstantValue(context.Bitcast(f4Const, uint4Type)); // throws
// after
var bits = new uint4(context.GetConstantValue(Bitcast(f4.x, uintType)), ...); // per-component
Defensive patterns

Strategy: validation

Validate before calling

if (context.ReverseTypes[resultType] is not ScalarType) EmitRuntimeInstruction(Specification.Op.OpBitcast); // defer vector/composite bitcasts

Type guard

bool IsScalarBitcast(Context ctx, int resultTypeId) => ctx.ReverseTypes[resultTypeId] is ScalarType;

Try / catch

try { folded = context.GetConstantValue(bitcastId); } catch (NotSupportedException ex) when (ex.Message.Contains("is not a scalar")) { EmitRuntimeInstruction(Specification.Op.OpBitcast); }

Prevention

When it happens

Trigger: Constant-folding an OpBitcast whose result type id maps to a non-scalar type — e.g. bitcasting to vec2/vec4/ivec, a struct, or a 64-bit type — in the TryGetConstantValue bitcast case.

Common situations: Shaders bitcasting float4 to uint4 or double to uint2 on constant expressions, a common pattern for float bit inspection or hashing; generated code that moves bit tricks into constant subexpressions.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/63a5a133700a272f. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Context.Constants.cs:113

                case Specification.Op.OpConvertUToF:
                    if (!TryGetConstantValue(i.Data.Memory.Span[4], out var convertOperand, out var convertOperandTypeId))
                        return false;
                    value = op switch
                    {
                        // Note: first cast to object is important, otherwise int/float will be cast as float
                        Specification.Op.OpConvertFToS => (object)(int)(float)convertOperand,
                        Specification.Op.OpConvertFToU => (uint)(float)convertOperand,
                        Specification.Op.OpConvertSToF => (float)(int)convertOperand,
                        Specification.Op.OpConvertUToF => (float)(uint)convertOperand,
                        _ => throw new NotSupportedException($"Unsupported conversion op: {op}"),
                    };
                    break;
                // Bitcast: reinterpret the operand's bits as the target scalar type.
                case Specification.Op.OpBitcast:
                    if (!TryGetConstantValue(i.Data.Memory.Span[4], out var bitcastOperand, out _))
                        return false;
                    if (ReverseTypes[resultType] is not ScalarType { Type: var bitcastTargetScalar })
                        throw new NotSupportedException($"OpBitcast result type {ReverseTypes[resultType]} is not a scalar");
                    var bitcastBits = bitcastOperand switch
                    {
                        int v => (uint)v,
                        uint v => v,
                        float v => BitConverter.SingleToUInt32Bits(v),
                        _ => throw new NotSupportedException($"OpBitcast operand type {bitcastOperand.GetType()} is not supported"),
                    };
                    value = bitcastTargetScalar switch
                    {
                        Scalar.Int => (object)(int)bitcastBits,
                        Scalar.UInt => bitcastBits,
                        Scalar.Float => BitConverter.UInt32BitsToSingle(bitcastBits),
                        _ => throw new NotSupportedException($"OpBitcast target scalar {bitcastTargetScalar} is not supported"),
                    };
                    break;
                // Unary operations
                case Specification.Op.OpSNegate:
                case Specification.Op.OpFNegate:

View on GitHub (pinned to 96fad776d2)