stride3d/stride · error · InvalidOperationException
Unexpected type for f32tof16
Error message
Unexpected type {inputType} for f32tof16 What it means
CompileF32tof16 packs float values into 16-bit halves using GLSLstd450 PackHalf2x16 and expects the input to resolve to a float scalar or float vector; the per-element results are recomposed into the uint return type. If the input type is not a supported float type/vector, it throws InvalidOperationException naming the resolved input type.
Solutions
- Cast the argument to float (or floatN) before f32tof16, e.g. f32tof16((float)x).
- Use asuint/asint for pure bit reinterpretation instead of f32tof16.
- Ensure generic shader code constrains T to float types for this call path.
- If another input kind should be supported, extend the type dispatch in CompileF32tof16.
Example fix
// before (SDSL) int i = 3; uint p = f32tof16(i); // throws: Unexpected type int // after uint p = f32tof16((float)i);
Defensive patterns
Strategy: validation
Validate before calling
bool IsFloatInput(TypeBase t) =>
t is ScalarType { Type: Scalar.Float } or VectorType { BaseType: ScalarType { Type: Scalar.Float } }; Type guard
bool IsFloatOrFloatVec(TypeBase t) => t.GetElementType() is ScalarType { Type: Scalar.Float }; Try / catch
try { result = intrinsics.CompileF32tof16(table, ctx, builder, fnType, x); }
catch (InvalidOperationException ex) { /* report that input must be float/floatN */ } Prevention
- Cast ints/doubles to float before f32tof16
- Use asuint/asint for bit reinterpretation instead
- Keep generic T constrained to float for packing intrinsics
When it happens
Trigger: Calling f32tof16(x) where x resolves to int, uint, double, or a non-float vector — only float scalars/vectors can be packed with PackHalf2x16 in the generated code.
Common situations: Passing an int assuming bit-level reinterpretation; passing a double from double-precision math; generic T functions instantiating to non-float types.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Unsupported element type for clamp
- Unsupported mul operand types
- Unsupported element type for saturate
- Unsupported element type for sign
- Unexpected type for f16tof32
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/7a66405350d7d24e.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/IntrinsicImplementations.cs:456
}
else if (inputType is VectorType v)
{
var components = new int[v.Size];
for (int i = 0; i < v.Size; i++)
{
// Extract float component
var comp = new SpirvValue(builder.InsertData(new OpCompositeExtract(floatType, context.Bound++, x.Id, [i])));
// Construct float2(comp, 0.0)
var float2Val = new SpirvValue(builder.InsertData(new OpCompositeConstruct(float2Type, context.Bound++, [comp.Id, zero])));
// PackHalf2x16 -> uint
var pack = builder.Insert(new GLSLExp(uintType, context.Bound++, context.GetGLSL(), float2Val.Id));
pack.InstructionMemory.Span[4] = 58; // GLSLstd450 PackHalf2x16
components[i] = pack.ResultId;
}
var result = new SpirvValue(builder.InsertData(new OpCompositeConstruct(context.GetOrRegister(returnType), context.Bound++, [.. components])));
return result;
}
throw new InvalidOperationException($"Unexpected type {inputType} for f32tof16");
}
public override SpirvValue CompileFirstbitlow(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue x, TextLocation location = default) => CompileGLSLFloatUnaryCall(table, context, builder, functionType.ReturnType, Specification.GLSLOp.GLSLFindILsb, x);
public override SpirvValue CompileFma(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue a, SpirvValue b, SpirvValue c, TextLocation location = default)
{
var instruction = builder.Insert(new GLSLFma(a.TypeId, context.Bound++, context.GetGLSL(), a.Id, b.Id, c.Id));
return new(instruction.ResultId, instruction.ResultType);
}
public override SpirvValue CompileFrexp(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue x, SpirvValue exp, TextLocation location = default)
{
var instruction = builder.Insert(new GLSLFrexp(context.GetOrRegister(functionType.ReturnType), context.Bound++, context.GetGLSL(), x.Id, exp.Id));
return new(instruction.ResultId, instruction.ResultType);
}
public override SpirvValue CompileIsfinite(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue x, TextLocation location = default)
{
// isfinite(x) = !(isinf(x) || isnan(x))
var boolType = context.GetOrRegister(functionType.ReturnType);
var isInf = builder.Insert(new OpIsInf(boolType, context.Bound++, x.Id));
var isNan = builder.Insert(new OpIsNan(boolType, context.Bound++, x.Id));View on GitHub (pinned to 96fad776d2)