{"record":{"id":"b32d990ca93574cc","repo":"stride3d/stride","slug":"multiple-matrix-with-different-generators","errorCode":null,"errorMessage":"Multiple matrix with different generators","messagePattern":"Multiple matrix with different generators","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/IntrinsicTemplateExpander.cs","lineNumber":349,"sourceCode":"                        firstIteration = false;\n\n                        SizePermutationGenerator? autoMatrixLoop = null;\n                        int autoMatrixLoopSize = 0;\n\n                        // Generate real types using sizes\n                        for (var index = 0; index < intrinsicDefinition.Parameters.Length + 1; index++)\n                        {\n                            ref var resolvedBaseType = ref parameterTypeHelper[index];\n\n                            if (resolvedBaseType.Size1.Value > 1 && resolvedBaseType.Size2.Value > 1)\n                            {\n                                if (resolvedBaseType.Size1.Generator is { } gen1 && (gen1.Name == null || gen1.Name.StartsWith(\"__any\")))\n                                {\n                                    // If matrix types are generated from a <> size generator (without a specific row/column pattern like in mul()),\n                                    // we can automatically convert a call to multiple calls on each inner vector.\n                                    // So we try to remember this info here\n                                    if (autoMatrixLoop != null && autoMatrixLoop != gen1)\n                                        throw new InvalidOperationException(\"Multiple matrix with different generators\");\n                                    autoMatrixLoop = gen1;\n                                    autoMatrixLoopSize = resolvedBaseType.Size1.Value;\n                                }\n                                parameterTypes[index] = new MatrixType((ScalarType)resolvedBaseType.BaseType, resolvedBaseType.Size2.Value, resolvedBaseType.Size1.Value);\n                            }\n                            // Note: since in HLSL float4x1 and float1x4 maps to SPIR-V float4, we will have duplicates (but not a big deal)\n                            else if (resolvedBaseType.Size1.Value > 1 || resolvedBaseType.Size2.Value > 1)\n                            {\n                                parameterTypes[index] = new VectorType((ScalarType)resolvedBaseType.BaseType, Math.Max(resolvedBaseType.Size1.Value, resolvedBaseType.Size2.Value));\n                            }\n                            else\n                            {\n                                parameterTypes[index] = resolvedBaseType.BaseType;\n                            }\n                        }\n\n                        // Note: we remove auto matrix loop if result type is not either void or matrix of the desired size\n                        if (autoMatrixLoop != null)","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/IntrinsicTemplateExpander.cs#L331-L367","documentation":"When a matrix-typed parameter is generated from a size generator (e.g. __any row/column patterns used by mul()), the expander remembers one generator in autoMatrixLoop so it can lower the call into per-vector calls. If a second, different generator appears for another parameter of the same intrinsic, the expansion would be ambiguous, so it throws.","triggerScenarios":"An intrinsic (typically mul or similar) whose matrix parameters resolve to different size generators (e.g. one __anyVM and one __anyVC pattern, or one anonymous and one named) in a single call.","commonSituations":"Multiplying matrices with incompatible wildcard size patterns; mixing a fully-specified matrix with a generator-based one in a way the expander cannot loop over uniformly.","solutions":["Make the matrix operand types consistent (same generator pattern) at the call site","Annotate the matrix types with explicit dimensions instead of relying on __any generators","Verify the intrinsic's declared matrix type match() chain so all operands derive from the same generator"],"exampleFix":"// before\nfloat2x3 r = mul(anyMatrix, float3x2(...)); // conflicting generators\n// after\nfloat3x3 r = mul(float3x3(a), float3x3(b)); // consistent types","handlingStrategy":"validation","validationCode":"// Verify all matrix operands share the same size generator before expansion\nvar gens = paramTypes.OfType<MatrixType>()\n    .Select(m => m.Size1.Generator).Where(g => g != null).Distinct().ToList();\nif (gens.Count > 1) throw new InvalidOperationException(\"Operands use different matrix generators\");","typeGuard":"bool SameGenerator(MatrixType a, MatrixType b) => Equals(a.Size1.Generator, b.Size1.Generator);","tryCatchPattern":"try { Expand(intrinsic, args); }\ncatch (InvalidOperationException ex) when (ex.Message == \"Multiple matrix with different generators\") { /* report mismatched operand types */ }","preventionTips":["Use explicitly sized matrix types in calls to generator-based intrinsics like mul","Keep operand matrix dimensions consistent within one intrinsic call","Avoid mixing __any-generated matrices with concrete dimensions"],"tags":["sdsl","shaders","matrix","generators"],"backgroundTag":"conflicting-type-generators","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"}