{"record":{"id":"4312dd5b5c9d3165","repo":"stride3d/stride","slug":"foreach-collection-and-variable-type-not-matching","errorCode":null,"errorMessage":"foreach: collection and variable type not matching","messagePattern":"foreach: collection and variable type not matching","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/Statements.Flow.cs","lineNumber":81,"sourceCode":"\n    public override void ProcessSymbol(SymbolTable table)\n    {\n        Collection.ProcessSymbol(table);\n        if (!(Collection.Type is PointerType p && p.BaseType is ArrayType arrayType))\n            throw new InvalidOperationException(\"foreach: Array type is expected\");\n\n\n        var variableType = new PointerType(arrayType.BaseType, Specification.StorageClass.Function);\n        Variable.Type = variableType;\n\n        if (TypeName.Name != \"var\")\n            TypeName.ProcessSymbol(table, variableType);\n        else\n            TypeName.Type = arrayType.BaseType;\n\n        // TODO: check conversions\n        if (variableType.BaseType != TypeName.Type)\n            throw new InvalidOperationException(\"foreach: collection and variable type not matching\");\n\n        table.Push();\n        var variableSymbol = new Symbol(new(Variable.Name, SymbolKind.Variable), Variable.Type, 0, OwnerType: table.CurrentShader);\n        table.CurrentFrame.Add(Variable.Name, variableSymbol);\n        Body.ProcessSymbol(table);\n        SymbolFrame = table.Pop();\n    }\n    public override void Compile(SymbolTable table, CompilerUnit compiler)\n    {\n        var (builder, context) = compiler;\n\n        var collection = Collection.Compile(table, compiler);\n        if (!(Collection.Type is PointerType p && p.BaseType is ArrayType arrayType))\n            throw new InvalidOperationException(\"foreach: Array type is expected\");\n\n        var variableType = new PointerType(arrayType.BaseType, Specification.StorageClass.Function);\n\n        // Since foreach need to be processed and expanded later, we use custom opcode","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/Statements.Flow.cs#L63-L99","documentation":"After resolving the foreach collection's element type, ProcessSymbol compares the loop variable's type (variableType.BaseType, the array's element type) with the declared TypeName's resolved type. If they differ, the foreach body would iterate with a mismatched element type, so this InvalidOperationException is thrown.","triggerScenarios":"foreach (Type v in arrayOfOtherType) where the explicit loop-variable type differs from the array's element type, e.g. foreach (int v in floatArray).","commonSituations":"Implicit-conversion expectations carried over from C# (SDSL does not convert here); arrays retyped after refactoring; generic/link substitution changing the array element type at composition time.","solutions":["Change the loop variable's declared type to exactly match the array element type.","Use 'var' as the loop variable type so it is inferred from the collection.","Change the collection's element type if the loop variable type is the intended one."],"exampleFix":"// before\nfloat arr[4];\nforeach (int v in arr) { ... }\n// after\nfloat arr[4];\nforeach (float v in arr) { ... }  // or: foreach (var v in arr)","handlingStrategy":"validation","validationCode":"if (arrayType.BaseType != declaredVariableType)\n    throw new InvalidOperationException(\"foreach variable type must equal the array element type\");","typeGuard":"bool ElementTypesMatch(ArrayType arr, SymbolType varType) => arr.BaseType == varType;","tryCatchPattern":"try { foreachStmt.ProcessSymbol(table); }\ncatch (InvalidOperationException ex) when (ex.Message == \"foreach: collection and variable type not matching\") { reportDiagnostic(foreachStmt.Info, ex.Message); }","preventionTips":["Prefer 'var' for the foreach loop variable so the type is inferred.","Avoid relying on implicit numeric conversions inside foreach in SDSL.","Recheck loop variable types after array type refactors or link substitutions."],"tags":["shader-parsing","sdsl","foreach","type-mismatch"],"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"}