{"record":{"id":"557d9d4628dc9077","repo":"stride3d/stride","slug":"unsupported-type-cast-from-to-to","errorCode":null,"errorMessage":"Unsupported type cast: {from} to {to}","messagePattern":"Unsupported type cast: (.+?) to (.+?)","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs","lineNumber":653,"sourceCode":"\n                    // Half conversions (OpFConvert for float<->half<->double, standard int conversions)\n                    (ScalarType { Type: Scalar.Half }, ScalarType { Type: Scalar.Float }) => InsertData(new OpFConvert(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue)),\n                    (ScalarType { Type: Scalar.Half }, ScalarType { Type: Scalar.Double }) => InsertData(new OpFConvert(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue)),\n                    (ScalarType { Type: Scalar.Float }, ScalarType { Type: Scalar.Half }) => InsertData(new OpFConvert(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue)),\n                    (ScalarType { Type: Scalar.Double }, ScalarType { Type: Scalar.Half }) => InsertData(new OpFConvert(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue)),\n                    (ScalarType { Type: Scalar.Half }, ScalarType { Type: Scalar.Int }) => InsertData(new OpConvertFToS(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue)),\n                    (ScalarType { Type: Scalar.Half }, ScalarType { Type: Scalar.UInt }) => InsertData(new OpConvertFToU(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue)),\n                    (ScalarType { Type: Scalar.Int }, ScalarType { Type: Scalar.Half }) => InsertData(new OpConvertSToF(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue)),\n                    (ScalarType { Type: Scalar.UInt }, ScalarType { Type: Scalar.Half }) => InsertData(new OpConvertUToF(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue)),\n                    (ScalarType { Type: Scalar.Half }, ScalarType { Type: Scalar.Boolean }) => InsertData(new OpFOrdNotEqual(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue, context.CreateConstantCompositeVectorRepeat(new FloatLiteral(new(16, true, true), 0.0, new()), elementSize).Id)),\n                    (ScalarType { Type: Scalar.Boolean }, ScalarType { Type: Scalar.Half }) => InsertData(new OpSelect(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue,\n                                                                                                    context.CreateConstantCompositeVectorRepeat(new FloatLiteral(new(16, true, true), 1.0, new()), elementSize).Id,\n                                                                                                    context.CreateConstantCompositeVectorRepeat(new FloatLiteral(new(16, true, true), 0.0, new()), elementSize).Id)),\n\n                    // Bitcast (int=>uint or uint=>int)\n                    (ScalarType { Type: Scalar.Int }, ScalarType { Type: Scalar.UInt }) => InsertData(new OpBitcast(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue)),\n                    (ScalarType { Type: Scalar.UInt }, ScalarType { Type: Scalar.Int }) => InsertData(new OpBitcast(context.GetOrRegister(castTypeSameSize), context.Bound++, rowValue)),\n                    (ScalarType { Type: var from }, ScalarType { Type: var to }) => throw new NotSupportedException($\"Unsupported type cast: {from} to {to}\"),\n                };\n                values[i] = typeCasting.IdResult!.Value;\n\n                // Update type\n                if (i == valueCount - 1)\n                    valueType = castTypeSameSize;\n            }\n        }\n\n        // Expanding\n        int result = values[0];\n        switch (valueType, castType)\n        {\n            case (ScalarType, VectorType v2):\n                result = Insert(new OpCompositeConstruct(context.GetOrRegister(v2), context.Bound++, new LiteralArray<int>(Enumerable.Repeat(result, v2.Size).ToArray())));\n                valueType = v2;\n                break;\n            case (ScalarType, MatrixType m2):","sourceCodeStart":635,"sourceCodeEnd":671,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs#L635-L671","documentation":"Thrown by Builder.Expressions.Convert in the per-element cast switch when the element type pair is a scalar combination not covered by the implemented SPIR-V conversions (OpConvertFToS/U, OpConvertSToF/U, OpUToF, OpSConvert, OpUConvert, OpBitcast int<->uint). Any other scalar pair, e.g. bool to float, double to bool, raises NotSupportedException.","triggerScenarios":"Calling Convert where both element types are scalars but the (from, to) Scalar.Type pair has no emitted instruction — e.g. Float->Bool, Bool->Float, Double->Int on paths where only bitcast int<->uint was special-cased.","commonSituations":"Shader code casting to/from bool (common in conditionals like `(float)someBool`) or using half/double casts; the converter's supported numeric conversion matrix is narrower than HLSL.","solutions":["Rewrite the cast in the shader using explicit constructs (e.g. `cond ? 1.0 : 0.0` instead of `(float)cond`).","Extend the switch in Builder.Expressions.cs to emit the missing SPIR-V conversion (e.g. OpSelect for bool->numeric).","Cast through an intermediate type that is supported (e.g. bool->int->float via logic ops)."],"exampleFix":"// before (shader)\nfloat f = (float)b;\n// after\nfloat f = b ? 1.0 : 0.0;","handlingStrategy":"type-guard","validationCode":"static readonly HashSet<(Scalar,Scalar)> supported = new() { (Float,Int),(Float,UInt),(Int,Float),(UInt,Float),(Int,Int),(UInt,UInt),(Int,UInt),(UInt,Int) };\nbool scalarCastSupported(Scalar from, Scalar to) => supported.Contains((from,to)) || from == to;","typeGuard":"bool IsUnsupportedScalarCast(ScalarType a, ScalarType b) => a != b && !(a.Type is Scalar.Float or Scalar.Int or Scalar.UInt) || /* check pipeline table */ false;","tryCatchPattern":"try { result = builder.Convert(table, context, value, castType); }\ncatch (NotSupportedException e) when (e.Message.StartsWith(\"Unsupported type cast\"))\n{ /* rewrite the expression in shader source, e.g. bool ? 1 : 0 */ }","preventionTips":["Avoid casting bool to numeric types directly; use ternary/select expressions.","Stick to float<->int/uint conversions supported by the SPIR-V converter.","Consult the implemented conversion list in Builder.Expressions.cs before adding new casts."],"tags":["spirv","unsupported-cast","scalar-types","shader-compilation"],"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"}