{"record":{"id":"6f0e74c996c919ef","repo":"stride3d/stride","slug":"can-t-cast-between-structures-cast-from-valuetype-to","errorCode":null,"errorMessage":"Can't cast between structures (cast from {valueType} to {castType})","messagePattern":"Can't cast between structures \\(cast from (.+?) to (.+?)\\)","errorType":"exception","errorClass":"NotImplementedException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs","lineNumber":391,"sourceCode":"        (Operator.GreaterOrEqual, _) when elementType.IsInteger() => Specification.Op.OpSGreaterThanEqual,\n        (Operator.GreaterOrEqual, _) when elementType.IsFloating() => Specification.Op.OpFOrdGreaterThanEqual,\n\n        _ => throw new NotImplementedException($\"Binary operator {op} not supported for element type {elementType}\")\n    };\n\n    /// <summary>\n    /// Check if a type can be converted to another.\n    /// </summary>\n    /// <param name=\"valueType\"></param>\n    /// <param name=\"castType\"></param>\n    /// <returns>0 if perfect match, int.MaxValue if failure, a score higher than 0 otherwise.</returns>\n    public static int CanConvertScore(SymbolType valueType, SymbolType castType)\n    {\n        if (castType == valueType)\n            return 0;\n\n        if (castType is StructType || valueType is StructType)\n            throw new NotImplementedException($\"Can't cast between structures (cast from {valueType} to {castType})\");\n\n        if (castType is ArrayType a1 && valueType is ArrayType a2)\n        {\n            if (a1.BaseType == a2.BaseType)\n            {\n                if (a1.Size != -1 && a1.Size != a2.Size)\n                    return int.MaxValue;\n                // Some sizes are undetermined; this can only happen during compilation due to incomplete generics type\n                // 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 }","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs#L373-L409","documentation":"CanConvertScore computes an implicit-conversion score for overload/cast resolution. Struct types are excluded from conversion scoring because the builder does not implement struct-to-struct casts, so encountering a StructType on either side is treated as an unimplemented path and throws immediately.","triggerScenarios":"Implicit conversion scoring where either the source or target SymbolType is a StructType and the types differ (e.g. passing a struct where another struct type is expected, triggering conversion ranking).","commonSituations":"Passing one user-defined struct type where a different (though field-compatible) struct is expected; API changes where a method parameter changed struct type; generics instantiation producing two distinct struct types.","solutions":["Make the source and target struct types identical (same SymbolType)","Explicitly convert field-by-field: construct the target struct from the source struct's members","Reinterpret via a helper that builds the new struct value instead of relying on cast","If this should be supported, implement struct conversion logic in CanConvertScore instead of throwing"],"exampleFix":"// before\nTargetStruct t = sourceStruct; // cast between structures\n// after\nTargetStruct t = new TargetStruct { A = sourceStruct.A, B = sourceStruct.B };","handlingStrategy":"type-guard","validationCode":"if (valueType is StructType || castType is StructType)\n    return; // skip conversion scoring; require exact type match","typeGuard":"bool IsCastable(SymbolType v, SymbolType c) => v is not StructType && c is not StructType;","tryCatchPattern":"try { score = CanConvertScore(valueType, castType); }\ncatch (NotImplementedException ex) when (ex.Message.Contains(\"cast between structures\"))\n{ /* require exact struct type or convert field-by-field */ }","preventionTips":["Match struct types exactly in shader APIs","Avoid casts involving user-defined structs","Convert structs explicitly via member-wise construction"],"tags":["spirv","shader-compiler","casting","struct"],"backgroundTag":"incompatible-source-type","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"}