stride3d/stride · error · NotImplementedException

Unsupported constant type

Error message

Unsupported constant type {typeInst.Op}

What it means

ConstantExpression.ParseInstruction throws this NotImplementedException when an OpConstant/OpSpecConstant's result type instruction is neither OpTypeInt nor OpTypeFloat. SPIR-V constants of other types (e.g. OpTypeBool, vectors, structs) are not handled by the scalar constant branch, so the parser refuses to build a ConstantExpression for them.

Solutions

  1. Verify with spirv-dis that the id passed to ParseFromBuffer is a scalar int/float constant, not a bool or composite.
  2. Handle boolean constants (OpConstantTrue/OpConstantFalse) before reaching this branch — they are parsed separately as BoolConstExpr.
  3. If the constant is composite, ensure it comes through the OpConstantComposite branch instead.
  4. If a new scalar type must be supported, add a branch for its type op in ConstantExpression.cs:126.

Example fix

// before: ParseFromBuffer(boolConstantId, ...) -> OpConstant true, type OpTypeBool -> throws
// after: check the opcode first
if (buffer.TryGetInstructionById(id, out var inst) && inst.Op == Op.OpConstantTrue)
    return new BoolConstExpr(true); // or use the constant only when it is an int/float scalar
Defensive patterns

Strategy: type-guard

Validate before calling

static bool IsScalarIntOrFloatConstant(SpirvBuffer buffer, int id)
{
    if (!buffer.TryGetInstructionById(id, out var inst)) return false;
    if (inst.Op is not (Op.OpConstant or Op.OpSpecConstant)) return false;
    var typeId = inst.Data.Memory.Span[1];
    return buffer.TryGetInstructionById(typeId, out var t)
        && t.Op is Op.OpTypeInt or Op.OpTypeFloat;
}

Type guard

static bool IsScalarConstantType(OpDataIndex typeInst)
    => typeInst.Op is Op.OpTypeInt or Op.OpTypeFloat;

Try / catch

try
{
    var expr = ConstantExpression.ParseFromBuffer(id, buffer, context);
}
catch (NotImplementedException)
{
    // constant type is bool/composite; route to the appropriate parser branch or skip
}

Prevention

When it happens

Trigger: Calling ConstantExpression.ParseFromBuffer on an id whose instruction is OpConstant/OpSpecConstant but whose result-type id resolves to a type instruction like OpTypeBool, OpTypeVector, or OpTypeStruct — e.g. extracting an 'array size' or generic argument that is actually a boolean or composite constant.

Common situations: Shader code using a bool spec-constant where an int is expected; pointing ParseFromBuffer at the wrong id in the buffer (a composite rather than scalar constant); SPIR-V produced by another compiler that models constants with types the SDSL parser never anticipated.

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


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Core/ConstantExpression.cs:127

                            { Width: 64, Signedness: 1 } => operand.ToLiteral<long>(),
                            _ => throw new NotImplementedException($"Unsupported int width {type.Width}"),
                        };
                        return new IntConstExpr(val);
                    }
                    else if (typeInst.Op == Op.OpTypeFloat)
                    {
                        var type = new OpTypeFloat(typeInst);
                        double val = type switch
                        {
                            { Width: 16 } => (double)operand.ToLiteral<Half>(),
                            { Width: 32 } => operand.ToLiteral<float>(),
                            { Width: 64 } => operand.ToLiteral<double>(),
                            _ => throw new NotImplementedException($"Unsupported float width {type.Width}"),
                        };
                        return new FloatConstExpr(val);
                    }
                    else
                        throw new NotImplementedException($"Unsupported constant type {typeInst.Op}");
                }
                throw new InvalidOperationException($"Cannot find type instruction for id {typeId}");
            }

            case Op.OpConstantStringSDSL:
            {
                var operand = inst.Data.Get("literalString");
                return new StringConstExpr(operand.ToLiteral<string>());
            }

            case Op.OpGenericParameterSDSL:
            case Op.OpGenericReferenceSDSL:
            {
                var genParam = (OpGenericParameterSDSL)inst;
                return new GenericParamExpr(genParam.Index, genParam.DeclaringClass);
            }

            case Op.OpConstantComposite:

View on GitHub (pinned to 96fad776d2)