{"record":{"id":"f2f44840a9c92e7d","repo":"stride3d/stride","slug":"cast-only-work-between-numeral-types-cast-from-valuetype-to","errorCode":null,"errorMessage":"Cast only work between numeral types (cast from {valueType} to {castType})","messagePattern":"Cast only work between numeral types \\(cast from (.+?) to (.+?)\\)","errorType":"exception","errorClass":"NotImplementedException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs","lineNumber":418,"sourceCode":"                // TODO: do a \"check pass\" later to make sure this won't happen after generics instantiation?\n                return 0;\n            }\n            else\n            {\n                return int.MaxValue;\n            }\n        }\n\n        if (castType is StreamsType { Kind: var targetKind }\n            && valueType is StreamsType { Kind: var sourceKind }\n            // Note: order is Input, Streams, Output\n            && targetKind > sourceKind)\n            return 1;\n\n        // We don't support cast with object yet, filter for numeral types\n        if ((castType is not ScalarType && castType is not VectorType && castType is not MatrixType)\n            || (valueType is not ScalarType && valueType is not VectorType && valueType is not MatrixType))\n            throw new NotImplementedException($\"Cast only work between numeral types (cast from {valueType} to {castType})\");\n\n        var conversionScore = (valueType, castType) switch\n        {\n            // Same size\n            (ScalarType, ScalarType) => 0,\n            (VectorType v1, VectorType v2) when v1.Size == v2.Size => 0,\n            (MatrixType m1, MatrixType m2) when m1.Rows == m2.Rows && m1.Columns == m2.Columns => 0,\n\n            // Promotion scalar to vector or matrix (replicate value) — more expensive than scalar-to-scalar conversion\n            (ScalarType, VectorType or MatrixType) => 5,\n\n            // Truncation\n            // Shape-changing truncation (vector/matrix to scalar) costs more than dimension-reducing truncation\n            // This ensures e.g. mul(float3, float4x4) picks mul_vm(float3, float3x4) over mul_sm(float, float4x4)\n            (VectorType or MatrixType, ScalarType) => 20,\n            (VectorType v1, VectorType v2) when v1.Size > v2.Size => 10 + (v1.Size - v2.Size),\n            (MatrixType m1, MatrixType m2) when (m1.Rows > m2.Rows && m1.Columns >= m2.Columns) || (m1.Rows >= m2.Rows && m1.Columns > m2.Columns) => 10 + (m1.Rows - m2.Rows) + (m1.Columns - m2.Columns),\n","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs#L400-L436","documentation":"CanConvertScore only supports conversion scoring between numeral types (ScalarType, VectorType, MatrixType). If either the source or target type is anything else (e.g. StreamsType, ArrayType, object), the function throws because the library deliberately filters casts to numeric types.","triggerScenarios":"Requesting a conversion score where valueType or castType is not a ScalarType/VectorType/MatrixType — e.g. casting a stream or array to a numeral type or vice versa.","commonSituations":"Casting between streams and vectors in shader code; accidentally casting an array to a scalar; overload resolution reaching CanConvertScore with non-numeric candidate types after generics instantiation.","solutions":["Restrict the cast to scalar/vector/matrix types on both sides","Convert via an explicit operation appropriate for the type (e.g. sample a stream into a vector before casting)","Remove the cast if the value is already the correct type and fix the surrounding type inference","Extend the conversion logic if this numeric/non-numeric cast should be legitimate"],"exampleFix":"// before\nfloat x = (float)someStream; // cast from StreamsType\n// after\nfloat x = someStream.Load(0); // or bind stream values via proper stream access","handlingStrategy":"type-guard","validationCode":"static bool IsNumeral(SymbolType t) => t is ScalarType or VectorType or MatrixType;\nif (!IsNumeral(valueType) || !IsNumeral(castType)) throw new InvalidOperationException(\"Cast requires numeral types\");","typeGuard":"bool IsNumeralType(SymbolType t) => t is ScalarType or VectorType or MatrixType;","tryCatchPattern":"try { score = CanConvertScore(valueType, castType); }\ncatch (NotImplementedException ex) when (ex.Message.Contains(\"numeral types\"))\n{ /* reject the overload or pick a non-cast path */ }","preventionTips":["Only cast between scalar/vector/matrix values","Access streams via stream APIs, not casts","Verify inferred types before invoking conversion scoring"],"tags":["spirv","shader-compiler","casting","numeric-types"],"backgroundTag":"type-mismatch","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"}