From 67a442d907075035840e60d11a21a9ace1947922 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 26 Feb 2026 16:21:01 -0800 Subject: [PATCH 1/8] Re-adds `IEnumerable` support to Views post removal of `Query` --- crates/bindings-csharp/Codegen/Diag.cs | 5 ++-- crates/bindings-csharp/Codegen/Module.cs | 35 +++++++++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/crates/bindings-csharp/Codegen/Diag.cs b/crates/bindings-csharp/Codegen/Diag.cs index ca5b9dba923..14c568de6ac 100644 --- a/crates/bindings-csharp/Codegen/Diag.cs +++ b/crates/bindings-csharp/Codegen/Diag.cs @@ -215,8 +215,9 @@ string typeName public static readonly ErrorDescriptor ViewInvalidReturn = new( group, - "Views must return Vec or Option", - method => $"View '{method.Identifier}' must return Vec or Option.", + "Views must return Vec, Option, or IEnumerable", + method => + $"View '{method.Identifier}' must return Vec, Option, or IEnumerable.", method => method ); diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index b5bf7d9c3d7..99a107ecbe8 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -1120,6 +1120,7 @@ record ViewDeclaration public readonly bool IsAnonymous; public readonly bool IsPublic; public readonly bool ReturnsQuery; + public readonly bool ReturnsEnumerable; public readonly TypeUse ReturnType; public readonly EquatableArray Parameters; public readonly Scope Scope; @@ -1155,6 +1156,7 @@ public ViewDeclaration(GeneratorAttributeSyntaxContext context, DiagReporter dia IsAnonymous = isAnonymousContext; ReturnsQuery = false; + ReturnsEnumerable = false; INamedTypeSymbol? iquery = null; if ( method.ReturnType is INamedTypeSymbol @@ -1192,6 +1194,24 @@ method.ReturnType is INamedTypeSymbol // Match Rust semantics: Query is described as Option. ReturnType = new ReferenceUse(opt, opt); } + else if ( + method.ReturnType + is INamedTypeSymbol + { + OriginalDefinition: var originalDefinition, + TypeArguments: [var enumerableElementType] + } + && originalDefinition.ToString() == "System.Collections.Generic.IEnumerable" + ) + { + ReturnsEnumerable = true; + var elementType = TypeUse.Parse(method, enumerableElementType, diag); + var elementTypeName = SymbolToName(enumerableElementType); + var listTypeName = $"System.Collections.Generic.List<{elementTypeName}>"; + var listTypeInfo = + $"SpacetimeDB.BSATN.List<{elementTypeName}, {elementType.BSATNName}>"; + ReturnType = new ListUse(listTypeName, listTypeInfo, elementType); + } else { ReturnType = TypeUse.Parse(method, method.ReturnType, diag); @@ -1210,11 +1230,12 @@ method.ReturnType is INamedTypeSymbol diag.Report(ErrorDescriptor.ViewContextParam, methodSyntax); } - // Validate return type: must be Option or Vec + // Validate return type: must be Option, Vec, or IEnumerable if ( !ReturnType.BSATNName.Contains("SpacetimeDB.BSATN.ValueOption") && !ReturnType.BSATNName.Contains("SpacetimeDB.BSATN.RefOption") && !ReturnType.BSATNName.Contains("SpacetimeDB.BSATN.List") + && !ReturnsEnumerable ) { diag.Report(ErrorDescriptor.ViewInvalidReturn, methodSyntax); @@ -1292,6 +1313,18 @@ public string GenerateDispatcherClass(uint index) listSerializer.Write(writer, listValue); return output.ToArray(); """ + : ReturnsEnumerable + ? $$$""" + var listSerializer = new {{{ReturnType.BSATNName}}}(); + var listValue = global::System.Linq.Enumerable.ToList(returnValue); + var header = new global::SpacetimeDB.Internal.ViewResultHeader.RowData(default); + var headerRW = new global::SpacetimeDB.Internal.ViewResultHeader.BSATN(); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + headerRW.Write(writer, header); + listSerializer.Write(writer, listValue); + return output.ToArray(); + """ : $$$""" {{{ReturnType.BSATNName}}} returnRW = new(); var header = new global::SpacetimeDB.Internal.ViewResultHeader.RowData(default); From 8886dc6b0d93ced56f0726a65d1febc68b4c25a4 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 26 Feb 2026 16:21:16 -0800 Subject: [PATCH 2/8] Updates snapshots --- .../Codegen.Tests/fixtures/diag/Lib.cs | 4 +- .../diag/snapshots/Module#FFI.verified.cs | 24 +++-- .../diag/snapshots/Module.verified.txt | 94 +------------------ 3 files changed, 19 insertions(+), 103 deletions(-) diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/Lib.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/Lib.cs index 47d5cf291f5..4eac3d7645a 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/Lib.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/Lib.cs @@ -569,14 +569,14 @@ public static Player ViewDefWrongReturn(ViewContext ctx) return new Player { Identity = new() }; } - // Invalid: IEnumerable return type (from Iter()) is not List or T? + // Valid: IEnumerable return type (from Iter()) is supported [SpacetimeDB.View(Accessor = "view_def_ienumerable_return_from_iter", Public = true)] public static IEnumerable ViewDefIEnumerableReturnFromIter(ViewContext ctx) { return ctx.Db.Player.Iter(); } - // Invalid: IEnumerable return type (from Filter()) is not List or T? + // Valid: IEnumerable return type (from Filter()) is supported [SpacetimeDB.View(Accessor = "view_def_ienumerable_return_from_filter", Public = true)] public static IEnumerable ViewDefIEnumerableReturnFromFilter( ViewContext ctx diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs index e69962b169c..e36c8d3ce14 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs @@ -1819,9 +1819,10 @@ SpacetimeDB.BSATN.ITypeRegistrar registrar IsPublic: true, IsAnonymous: false, Params: [], - ReturnType: new SpacetimeDB.BSATN.Unsupported>().GetAlgebraicType( - registrar - ) + ReturnType: new SpacetimeDB.BSATN.List< + TestScheduleIssues, + TestScheduleIssues.BSATN + >().GetAlgebraicType(registrar) ); public byte[] Invoke( @@ -1834,14 +1835,17 @@ public byte[] Invoke( var returnValue = Module.ViewDefIEnumerableReturnFromFilter( (SpacetimeDB.ViewContext)ctx ); - SpacetimeDB.BSATN.Unsupported> returnRW = - new(); + var listSerializer = new SpacetimeDB.BSATN.List< + TestScheduleIssues, + TestScheduleIssues.BSATN + >(); + var listValue = global::System.Linq.Enumerable.ToList(returnValue); var header = new global::SpacetimeDB.Internal.ViewResultHeader.RowData(default); var headerRW = new global::SpacetimeDB.Internal.ViewResultHeader.BSATN(); using var output = new System.IO.MemoryStream(); using var writer = new System.IO.BinaryWriter(output); headerRW.Write(writer, header); - returnRW.Write(writer, returnValue); + listSerializer.Write(writer, listValue); return output.ToArray(); } catch (System.Exception e) @@ -1866,7 +1870,7 @@ SpacetimeDB.BSATN.ITypeRegistrar registrar IsPublic: true, IsAnonymous: false, Params: [], - ReturnType: new SpacetimeDB.BSATN.Unsupported>().GetAlgebraicType( + ReturnType: new SpacetimeDB.BSATN.List().GetAlgebraicType( registrar ) ); @@ -1879,14 +1883,14 @@ public byte[] Invoke( try { var returnValue = Module.ViewDefIEnumerableReturnFromIter((SpacetimeDB.ViewContext)ctx); - SpacetimeDB.BSATN.Unsupported> returnRW = - new(); + var listSerializer = new SpacetimeDB.BSATN.List(); + var listValue = global::System.Linq.Enumerable.ToList(returnValue); var header = new global::SpacetimeDB.Internal.ViewResultHeader.RowData(default); var headerRW = new global::SpacetimeDB.Internal.ViewResultHeader.BSATN(); using var output = new System.IO.MemoryStream(); using var writer = new System.IO.BinaryWriter(output); headerRW.Write(writer, header); - returnRW.Write(writer, returnValue); + listSerializer.Write(writer, listValue); return output.ToArray(); } catch (System.Exception e) diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt index f1a3835b97c..41b88c2039f 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt @@ -343,100 +343,12 @@ public partial struct TestScheduleIssues ^^^^^ */ - Message: View 'ViewDefWrongReturn' must return Vec or Option., + Message: View 'ViewDefWrongReturn' must return Vec, Option, or IEnumerable., Severity: Error, Descriptor: { Id: STDB0024, - Title: Views must return Vec or Option, - MessageFormat: View '{0}' must return Vec or Option., - Category: SpacetimeDB, - DefaultSeverity: Error, - IsEnabledByDefault: true - } - }, - {/* - [SpacetimeDB.View(Accessor = "view_def_ienumerable_return_from_iter", Public = true)] - public static IEnumerable ViewDefIEnumerableReturnFromIter(ViewContext ctx) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - { -*/ - Message: BSATN implementation for System.Collections.Generic.IEnumerable is not found: Unsupported system type System.Collections.Generic.IEnumerable, - Severity: Error, - Descriptor: { - Id: BSATN0001, - Title: Unsupported type, - MessageFormat: BSATN implementation for {0} is not found: {1}, - Category: SpacetimeDB.BSATN, - DefaultSeverity: Error, - IsEnabledByDefault: true - } - }, - {/* - // Invalid: IEnumerable return type (from Iter()) is not List or T? - [SpacetimeDB.View(Accessor = "view_def_ienumerable_return_from_iter", Public = true)] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - public static IEnumerable ViewDefIEnumerableReturnFromIter(ViewContext ctx) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - { -^^^^^ - return ctx.Db.Player.Iter(); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - } -^^^^^ - -*/ - Message: View 'ViewDefIEnumerableReturnFromIter' must return Vec or Option., - Severity: Error, - Descriptor: { - Id: STDB0024, - Title: Views must return Vec or Option, - MessageFormat: View '{0}' must return Vec or Option., - Category: SpacetimeDB, - DefaultSeverity: Error, - IsEnabledByDefault: true - } - }, - {/* - [SpacetimeDB.View(Accessor = "view_def_ienumerable_return_from_filter", Public = true)] - public static IEnumerable ViewDefIEnumerableReturnFromFilter( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ViewContext ctx -*/ - Message: BSATN implementation for System.Collections.Generic.IEnumerable is not found: Unsupported system type System.Collections.Generic.IEnumerable, - Severity: Error, - Descriptor: { - Id: BSATN0001, - Title: Unsupported type, - MessageFormat: BSATN implementation for {0} is not found: {1}, - Category: SpacetimeDB.BSATN, - DefaultSeverity: Error, - IsEnabledByDefault: true - } - }, - {/* - // Invalid: IEnumerable return type (from Filter()) is not List or T? - [SpacetimeDB.View(Accessor = "view_def_ienumerable_return_from_filter", Public = true)] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - public static IEnumerable ViewDefIEnumerableReturnFromFilter( -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ViewContext ctx -^^^^^^^^^^^^^^^^^^^^^^^ - ) -^^^^^ - { -^^^^^ - return ctx.Db.TestIndexIssues.TestUnexpectedColumns.Filter(0); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - } -^^^^^ - -*/ - Message: View 'ViewDefIEnumerableReturnFromFilter' must return Vec or Option., - Severity: Error, - Descriptor: { - Id: STDB0024, - Title: Views must return Vec or Option, - MessageFormat: View '{0}' must return Vec or Option., + Title: Views must return Vec, Option, or IEnumerable, + MessageFormat: View '{0}' must return Vec, Option, or IEnumerable., Category: SpacetimeDB, DefaultSeverity: Error, IsEnabledByDefault: true From 4018fa99580e5d3dac096af8e8760e5705687e96 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 26 Feb 2026 16:21:35 -0800 Subject: [PATCH 3/8] Updates docs references --- .../00100-databases/00500-cheat-sheet.md | 4 ++-- .../docs/00200-core-concepts/00200-functions/00500-views.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/docs/00200-core-concepts/00100-databases/00500-cheat-sheet.md b/docs/docs/00200-core-concepts/00100-databases/00500-cheat-sheet.md index ec05ce1fe13..f8a3f2d814f 100644 --- a/docs/docs/00200-core-concepts/00100-databases/00500-cheat-sheet.md +++ b/docs/docs/00200-core-concepts/00100-databases/00500-cheat-sheet.md @@ -631,9 +631,9 @@ public static Player? MyPlayer(ViewContext ctx) // Return potentially multiple rows [SpacetimeDB.View(Accessor = "TopPlayers", Public = true)] -public static List TopPlayers(ViewContext ctx) +public static IEnumerable TopPlayers(ViewContext ctx) { - return ctx.Db.Player.Score.Filter(1000).ToList(); + return ctx.Db.Player.Score.Filter(1000); } // Perform a generic filter using the query builder. diff --git a/docs/docs/00200-core-concepts/00200-functions/00500-views.md b/docs/docs/00200-core-concepts/00200-functions/00500-views.md index 869d63911bd..e2406ef5dd2 100644 --- a/docs/docs/00200-core-concepts/00200-functions/00500-views.md +++ b/docs/docs/00200-core-concepts/00200-functions/00500-views.md @@ -135,9 +135,9 @@ public static partial class Module return ctx.Db.Player.Identity.Find(ctx.Sender) as Player?; } - // Multiple rows: return a list + // Multiple rows: return a list or enumerable [SpacetimeDB.View(Accessor = "PlayersForLevel", Public = true)] - public static List PlayersForLevel(AnonymousViewContext ctx) + public static IEnumerable PlayersForLevel(AnonymousViewContext ctx) { var rows = new List(); foreach (var player in ctx.Db.PlayerLevel.Level.Filter(1)) @@ -159,7 +159,7 @@ public static partial class Module } ``` -Views must be static methods and can return either a single row (`T?`) or a list of rows (`List` or `T[]`) where `T` can be a table type or any product type. +Views must be static methods and can return either a single row (`T?`) or multiple rows (`IEnumerable`, `List`, or `T[]`) where `T` can be a table type or any product type. From 932e826f9a8946701076e1f117c070117b71155f Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 26 Feb 2026 16:22:07 -0800 Subject: [PATCH 4/8] Update lints --- crates/bindings-csharp/Codegen/Module.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index 99a107ecbe8..bbcac66964a 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -1196,11 +1196,11 @@ method.ReturnType is INamedTypeSymbol } else if ( method.ReturnType - is INamedTypeSymbol - { - OriginalDefinition: var originalDefinition, - TypeArguments: [var enumerableElementType] - } + is INamedTypeSymbol + { + OriginalDefinition: var originalDefinition, + TypeArguments: [var enumerableElementType] + } && originalDefinition.ToString() == "System.Collections.Generic.IEnumerable" ) { From 95f2c5fedd202b90e98ea06ccc5fe85ceca04397 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Tue, 3 Mar 2026 09:09:07 -0800 Subject: [PATCH 5/8] Updating C# `ViewDeclaration` Invalid Return check --- crates/bindings-csharp/Codegen/Module.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index 8a4bf689697..6bb726ab4fe 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -1231,12 +1231,11 @@ is INamedTypeSymbol } // Validate return type: must be List, T?, or IEnumerable - if ( - !ReturnType.BSATNName.Contains("SpacetimeDB.BSATN.ValueOption") - && !ReturnType.BSATNName.Contains("SpacetimeDB.BSATN.RefOption") - && !ReturnType.BSATNName.Contains("SpacetimeDB.BSATN.List") - && !ReturnsEnumerable - ) + var isOption = + ReturnType.BSATNName.Contains("SpacetimeDB.BSATN.ValueOption") + || ReturnType.BSATNName.Contains("SpacetimeDB.BSATN.RefOption"); + + if (!ReturnsQuery && !ReturnsEnumerable && !isOption) { diag.Report(ErrorDescriptor.ViewInvalidReturn, methodSyntax); } From 6a7e90581a564a0659f398a1cc1f82c0e70d84f3 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Tue, 3 Mar 2026 09:10:14 -0800 Subject: [PATCH 6/8] Updating `Codegen.Test` for new return results and snapshots --- crates/bindings-csharp/Codegen.Tests/Tests.cs | 7 +- .../diag/snapshots/Module.verified.txt | 87 ++++++++----------- .../snapshots/Module.verified.txt | 21 +++++ 3 files changed, 59 insertions(+), 56 deletions(-) create mode 100644 crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module.verified.txt diff --git a/crates/bindings-csharp/Codegen.Tests/Tests.cs b/crates/bindings-csharp/Codegen.Tests/Tests.cs index 8b617a161b2..9148af3f498 100644 --- a/crates/bindings-csharp/Codegen.Tests/Tests.cs +++ b/crates/bindings-csharp/Codegen.Tests/Tests.cs @@ -300,7 +300,7 @@ public static async Task ViewInvalidReturnHighlightsReturnType() Method = method, }) ) - .Single(entry => entry.Method.Identifier.Text == "ViewDefIEnumerableReturnFromIter"); + .Single(entry => entry.Method.Identifier.Text == "ViewDefWrongReturn"); var returnTypeSpan = method.Method.ReturnType.Span; var diagnostics = runResult @@ -308,8 +308,7 @@ public static async Task ViewInvalidReturnHighlightsReturnType() .Where(d => d.Id == "STDB0024") .ToList(); var diagnostic = diagnostics.FirstOrDefault(d => - d.GetMessage().Contains("ViewDefIEnumerableReturnFromIter") - && d.Location.SourceTree == method.Tree + d.GetMessage().Contains("ViewDefWrongReturn") && d.Location.SourceTree == method.Tree ); Assert.NotNull(diagnostic); @@ -319,6 +318,6 @@ public static async Task ViewInvalidReturnHighlightsReturnType() var returnTypeText = method .Root.ToFullString() .Substring(returnTypeSpan.Start, returnTypeSpan.Length); - Assert.Contains("IEnumerable", returnTypeText); + Assert.Contains("Player", returnTypeText); } } diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt index e8f10fd59c7..6f34e9bad7e 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt @@ -296,29 +296,29 @@ public partial struct TestScheduleIssues } }, {/* - [SpacetimeDB.View(Accessor = "view_def_no_context", Public = true)] - public static List ViewDefNoContext() - ^^ + [SpacetimeDB.View(Accessor = "view_def_no_public")] + public static List ViewDefNoPublic(ViewContext ctx) + ^^^^^^^^^^^^ { */ - Message: View method ViewDefNoContext must have a first parameter of type ViewContext or AnonymousViewContext., + Message: View 'ViewDefNoPublic' must return T?, List, IQuery, or IEnumerable., Severity: Error, Descriptor: { - Id: STDB0022, - Title: Views must start with ViewContext or AnonymousViewContext, - MessageFormat: View method {0} must have a first parameter of type ViewContext or AnonymousViewContext., + Id: STDB0024, + Title: Views must return T?, List, IQuery, or IEnumerable, + MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable., Category: SpacetimeDB, DefaultSeverity: Error, IsEnabledByDefault: true } }, {/* - [SpacetimeDB.View(Accessor = "view_def_wrong_context", Public = true)] - public static List ViewDefWrongContext(ReducerContext ctx) - ^^^^^^^^^^^^^^^^^^^^ + [SpacetimeDB.View(Accessor = "view_def_no_context", Public = true)] + public static List ViewDefNoContext() + ^^ { */ - Message: View method ViewDefWrongContext must have a first parameter of type ViewContext or AnonymousViewContext., + Message: View method ViewDefNoContext must have a first parameter of type ViewContext or AnonymousViewContext., Severity: Error, Descriptor: { Id: STDB0022, @@ -330,85 +330,68 @@ public partial struct TestScheduleIssues } }, {/* - [SpacetimeDB.View(Accessor = "view_def_wrong_return", Public = true)] - public static Player ViewDefWrongReturn(ViewContext ctx) - ^^^^^^ + [SpacetimeDB.View(Accessor = "view_def_no_context", Public = true)] + public static List ViewDefNoContext() + ^^^^^^^^^^^^ { */ - Message: View 'ViewDefWrongReturn' must return T?, List, IQuery, or IEnumerable, + Message: View 'ViewDefNoContext' must return T?, List, IQuery, or IEnumerable., Severity: Error, Descriptor: { Id: STDB0024, Title: Views must return T?, List, IQuery, or IEnumerable, - MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable, + MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable., Category: SpacetimeDB, DefaultSeverity: Error, IsEnabledByDefault: true } }, {/* - [SpacetimeDB.View(Accessor = "view_def_ienumerable_return_from_iter", Public = true)] - public static IEnumerable ViewDefIEnumerableReturnFromIter(ViewContext ctx) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + [SpacetimeDB.View(Accessor = "view_def_wrong_context", Public = true)] + public static List ViewDefWrongContext(ReducerContext ctx) + ^^^^^^^^^^^^^^^^^^^^ { */ - Message: BSATN implementation for System.Collections.Generic.IEnumerable is not found: Unsupported system type System.Collections.Generic.IEnumerable, + Message: View method ViewDefWrongContext must have a first parameter of type ViewContext or AnonymousViewContext., Severity: Error, Descriptor: { - Id: BSATN0001, - Title: Unsupported type, - MessageFormat: BSATN implementation for {0} is not found: {1}, - Category: SpacetimeDB.BSATN, + Id: STDB0022, + Title: Views must start with ViewContext or AnonymousViewContext, + MessageFormat: View method {0} must have a first parameter of type ViewContext or AnonymousViewContext., + Category: SpacetimeDB, DefaultSeverity: Error, IsEnabledByDefault: true } }, {/* - [SpacetimeDB.View(Accessor = "view_def_ienumerable_return_from_iter", Public = true)] - public static IEnumerable ViewDefIEnumerableReturnFromIter(ViewContext ctx) - ^^^^^^^^^^^^^^^^^^^ + [SpacetimeDB.View(Accessor = "view_def_wrong_context", Public = true)] + public static List ViewDefWrongContext(ReducerContext ctx) + ^^^^^^^^^^^^ { */ - Message: View 'ViewDefIEnumerableReturnFromIter' must return T?, List, IQuery, or IEnumerable, + Message: View 'ViewDefWrongContext' must return T?, List, IQuery, or IEnumerable., Severity: Error, Descriptor: { Id: STDB0024, Title: Views must return T?, List, IQuery, or IEnumerable, - MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable, + MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable., Category: SpacetimeDB, DefaultSeverity: Error, IsEnabledByDefault: true } }, {/* - [SpacetimeDB.View(Accessor = "view_def_ienumerable_return_from_filter", Public = true)] - public static IEnumerable ViewDefIEnumerableReturnFromFilter( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ViewContext ctx -*/ - Message: BSATN implementation for System.Collections.Generic.IEnumerable is not found: Unsupported system type System.Collections.Generic.IEnumerable, - Severity: Error, - Descriptor: { - Id: BSATN0001, - Title: Unsupported type, - MessageFormat: BSATN implementation for {0} is not found: {1}, - Category: SpacetimeDB.BSATN, - DefaultSeverity: Error, - IsEnabledByDefault: true - } - }, - {/* - [SpacetimeDB.View(Accessor = "view_def_ienumerable_return_from_filter", Public = true)] - public static IEnumerable ViewDefIEnumerableReturnFromFilter( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ViewContext ctx + [SpacetimeDB.View(Accessor = "view_def_wrong_return", Public = true)] + public static Player ViewDefWrongReturn(ViewContext ctx) + ^^^^^^ + { */ - Message: View 'ViewDefIEnumerableReturnFromFilter' must return T?, List, IQuery, or IEnumerable, + Message: View 'ViewDefWrongReturn' must return T?, List, IQuery, or IEnumerable., Severity: Error, Descriptor: { Id: STDB0024, Title: Views must return T?, List, IQuery, or IEnumerable, - MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable, + MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable., Category: SpacetimeDB, DefaultSeverity: Error, IsEnabledByDefault: true diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module.verified.txt b/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module.verified.txt new file mode 100644 index 00000000000..0ef94881e07 --- /dev/null +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module.verified.txt @@ -0,0 +1,21 @@ +{ + Diagnostics: [ + {/* + [SpacetimeDB.View(Accessor = "demo_view", Name = "canonical_view", Public = true)] + public static List DemoView(ViewContext ctx) + ^^^^^^^^^^^^^^^ + { +*/ + Message: View 'DemoView' must return T?, List, IQuery, or IEnumerable., + Severity: Error, + Descriptor: { + Id: STDB0024, + Title: Views must return T?, List, IQuery, or IEnumerable, + MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable., + Category: SpacetimeDB, + DefaultSeverity: Error, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file From ce6a045b2758c20a9737b402ab96d9219cc5f170 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Tue, 3 Mar 2026 10:34:10 -0800 Subject: [PATCH 7/8] Updated `ReturnsEnumerable` to include check for List types --- crates/bindings-csharp/Codegen/Module.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index 6bb726ab4fe..4dd95b82434 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -1215,6 +1215,19 @@ is INamedTypeSymbol else { ReturnType = TypeUse.Parse(method, method.ReturnType, diag); + + if ( + method.ReturnType + is INamedTypeSymbol + { + OriginalDefinition: var listDefinition, + TypeArguments.Length: 1, + } + && listDefinition.ToString() == "System.Collections.Generic.List" + ) + { + ReturnsEnumerable = true; + } } Scope = new Scope(methodSyntax.Parent as MemberDeclarationSyntax); From d3b9e8a5287883d5ea5c3a1a59fef9ba3d806294 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Tue, 3 Mar 2026 13:27:24 -0800 Subject: [PATCH 8/8] Updating snapshots --- .../ExtraCompilationErrors.verified.txt | 4 +- .../diag/snapshots/Module#FFI.verified.cs | 15 +++--- .../diag/snapshots/Module.verified.txt | 51 ------------------- .../snapshots/Module#FFI.verified.cs | 5 +- .../snapshots/Module.verified.txt | 21 -------- 5 files changed, 14 insertions(+), 82 deletions(-) delete mode 100644 crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module.verified.txt diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/ExtraCompilationErrors.verified.txt b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/ExtraCompilationErrors.verified.txt index 8e960c9f38a..c732156f772 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/ExtraCompilationErrors.verified.txt +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/ExtraCompilationErrors.verified.txt @@ -256,7 +256,7 @@ public partial struct TestDefaultFieldValues var returnValue = Module.ViewDefWrongContext((SpacetimeDB.ViewContext)ctx); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - SpacetimeDB.BSATN.List returnRW = new(); + var listSerializer = new SpacetimeDB.BSATN.List(); */ Message: Argument 1: cannot convert from 'SpacetimeDB.ViewContext' to 'SpacetimeDB.ReducerContext', Severity: Error, @@ -325,7 +325,7 @@ SpacetimeDB.Internal.Module.RegisterClientVisibilityFilter(global::Module.MY_THI var returnValue = Module.ViewDefNoContext((SpacetimeDB.ViewContext)ctx); ^^^^^^^^^^^^^^^^ - SpacetimeDB.BSATN.List returnRW = new(); + var listSerializer = new SpacetimeDB.BSATN.List(); */ Message: No overload for method 'ViewDefNoContext' takes 1 arguments, Severity: Error, diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs index e36c8d3ce14..679dbcb6c70 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs @@ -1927,13 +1927,14 @@ public byte[] Invoke( try { var returnValue = Module.ViewDefNoContext((SpacetimeDB.ViewContext)ctx); - SpacetimeDB.BSATN.List returnRW = new(); + var listSerializer = new SpacetimeDB.BSATN.List(); + var listValue = global::System.Linq.Enumerable.ToList(returnValue); var header = new global::SpacetimeDB.Internal.ViewResultHeader.RowData(default); var headerRW = new global::SpacetimeDB.Internal.ViewResultHeader.BSATN(); using var output = new System.IO.MemoryStream(); using var writer = new System.IO.BinaryWriter(output); headerRW.Write(writer, header); - returnRW.Write(writer, returnValue); + listSerializer.Write(writer, listValue); return output.ToArray(); } catch (System.Exception e) @@ -1968,13 +1969,14 @@ public byte[] Invoke( try { var returnValue = Module.ViewDefNoPublic((SpacetimeDB.ViewContext)ctx); - SpacetimeDB.BSATN.List returnRW = new(); + var listSerializer = new SpacetimeDB.BSATN.List(); + var listValue = global::System.Linq.Enumerable.ToList(returnValue); var header = new global::SpacetimeDB.Internal.ViewResultHeader.RowData(default); var headerRW = new global::SpacetimeDB.Internal.ViewResultHeader.BSATN(); using var output = new System.IO.MemoryStream(); using var writer = new System.IO.BinaryWriter(output); headerRW.Write(writer, header); - returnRW.Write(writer, returnValue); + listSerializer.Write(writer, listValue); return output.ToArray(); } catch (System.Exception e) @@ -2009,13 +2011,14 @@ public byte[] Invoke( try { var returnValue = Module.ViewDefWrongContext((SpacetimeDB.ViewContext)ctx); - SpacetimeDB.BSATN.List returnRW = new(); + var listSerializer = new SpacetimeDB.BSATN.List(); + var listValue = global::System.Linq.Enumerable.ToList(returnValue); var header = new global::SpacetimeDB.Internal.ViewResultHeader.RowData(default); var headerRW = new global::SpacetimeDB.Internal.ViewResultHeader.BSATN(); using var output = new System.IO.MemoryStream(); using var writer = new System.IO.BinaryWriter(output); headerRW.Write(writer, header); - returnRW.Write(writer, returnValue); + listSerializer.Write(writer, listValue); return output.ToArray(); } catch (System.Exception e) diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt index 6f34e9bad7e..645e102d204 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt @@ -296,23 +296,6 @@ public partial struct TestScheduleIssues } }, {/* - [SpacetimeDB.View(Accessor = "view_def_no_public")] - public static List ViewDefNoPublic(ViewContext ctx) - ^^^^^^^^^^^^ - { -*/ - Message: View 'ViewDefNoPublic' must return T?, List, IQuery, or IEnumerable., - Severity: Error, - Descriptor: { - Id: STDB0024, - Title: Views must return T?, List, IQuery, or IEnumerable, - MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable., - Category: SpacetimeDB, - DefaultSeverity: Error, - IsEnabledByDefault: true - } - }, - {/* [SpacetimeDB.View(Accessor = "view_def_no_context", Public = true)] public static List ViewDefNoContext() ^^ @@ -330,23 +313,6 @@ public partial struct TestScheduleIssues } }, {/* - [SpacetimeDB.View(Accessor = "view_def_no_context", Public = true)] - public static List ViewDefNoContext() - ^^^^^^^^^^^^ - { -*/ - Message: View 'ViewDefNoContext' must return T?, List, IQuery, or IEnumerable., - Severity: Error, - Descriptor: { - Id: STDB0024, - Title: Views must return T?, List, IQuery, or IEnumerable, - MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable., - Category: SpacetimeDB, - DefaultSeverity: Error, - IsEnabledByDefault: true - } - }, - {/* [SpacetimeDB.View(Accessor = "view_def_wrong_context", Public = true)] public static List ViewDefWrongContext(ReducerContext ctx) ^^^^^^^^^^^^^^^^^^^^ @@ -364,23 +330,6 @@ public partial struct TestScheduleIssues } }, {/* - [SpacetimeDB.View(Accessor = "view_def_wrong_context", Public = true)] - public static List ViewDefWrongContext(ReducerContext ctx) - ^^^^^^^^^^^^ - { -*/ - Message: View 'ViewDefWrongContext' must return T?, List, IQuery, or IEnumerable., - Severity: Error, - Descriptor: { - Id: STDB0024, - Title: Views must return T?, List, IQuery, or IEnumerable, - MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable., - Category: SpacetimeDB, - DefaultSeverity: Error, - IsEnabledByDefault: true - } - }, - {/* [SpacetimeDB.View(Accessor = "view_def_wrong_return", Public = true)] public static Player ViewDefWrongReturn(ViewContext ctx) ^^^^^^ diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module#FFI.verified.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module#FFI.verified.cs index 82127603515..b620e8d37c9 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module#FFI.verified.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module#FFI.verified.cs @@ -366,13 +366,14 @@ public byte[] Invoke( try { var returnValue = Reducers.DemoView((SpacetimeDB.ViewContext)ctx); - SpacetimeDB.BSATN.List returnRW = new(); + var listSerializer = new SpacetimeDB.BSATN.List(); + var listValue = global::System.Linq.Enumerable.ToList(returnValue); var header = new global::SpacetimeDB.Internal.ViewResultHeader.RowData(default); var headerRW = new global::SpacetimeDB.Internal.ViewResultHeader.BSATN(); using var output = new System.IO.MemoryStream(); using var writer = new System.IO.BinaryWriter(output); headerRW.Write(writer, header); - returnRW.Write(writer, returnValue); + listSerializer.Write(writer, listValue); return output.ToArray(); } catch (System.Exception e) diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module.verified.txt b/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module.verified.txt deleted file mode 100644 index 0ef94881e07..00000000000 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module.verified.txt +++ /dev/null @@ -1,21 +0,0 @@ -{ - Diagnostics: [ - {/* - [SpacetimeDB.View(Accessor = "demo_view", Name = "canonical_view", Public = true)] - public static List DemoView(ViewContext ctx) - ^^^^^^^^^^^^^^^ - { -*/ - Message: View 'DemoView' must return T?, List, IQuery, or IEnumerable., - Severity: Error, - Descriptor: { - Id: STDB0024, - Title: Views must return T?, List, IQuery, or IEnumerable, - MessageFormat: View '{0}' must return T?, List, IQuery, or IEnumerable., - Category: SpacetimeDB, - DefaultSeverity: Error, - IsEnabledByDefault: true - } - } - ] -} \ No newline at end of file