Address PR #52 review: IsComponent gate + inout cast

- inout ternary cast to int16_t (flecs field type; WERROR-safe).
- TickParameterSnapshot gains IsComponent (unmanaged + implements
  IComponent via existing helper); IsRunnable rejects non-components
  (BadParam fixture proves Register -> -2).
This commit is contained in:
hermes-agent committed 2026-10-30 10:05:31 -09:00
1 parent 7fe0d6c90e
commit 6f4abe31ab
4 files changed
+35 -5

No files matched your search

@@ -242,7 +242,8 @@ public sealed class ComponentSystemGenerator : IIncrementalGenerator
pars.Add(new TickParameterSnapshot(
kind,
p.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
p.Name));
p.Name,
kind != TickRefKind.None && IsUnmanagedComponent(p.Type, iComponent)));
}
ticks.Add(new TickSignatureSnapshot(
@@ -378,6 +379,16 @@ public sealed class ComponentSystemGenerator : IIncrementalGenerator
return false;
}
// A Tick component parameter must be usable as a native column: an
// unmanaged value type implementing IComponent. Checked with the
// existing Implements helper; anything else is not a component.
private static bool IsUnmanagedComponent(ITypeSymbol type, INamedTypeSymbol iComponent)
{
return type.IsUnmanagedType
&& type is INamedTypeSymbol named
&& Implements(named, iComponent);
}
private static ImmutableArray<string> ReadPhases(ISymbol sym)
{
var builder = ImmutableArray.CreateBuilder<string>();
@@ -714,6 +725,11 @@ public sealed class ComponentSystemGenerator : IIncrementalGenerator
return false;
}
if (!p.IsComponent)
{
return false;
}
components.Add(p);
}
+2 -1
View File
@@ -29,7 +29,8 @@ internal enum TickRefKind
internal sealed record TickParameterSnapshot(
TickRefKind RefKind,
string TypeName,
string Name);
string Name,
bool IsComponent);
/// <summary>One user Tick overload: parameters + UpdateInPhase phases.</summary>
internal sealed record TickSignatureSnapshot(
+14 -1
View File
@@ -80,6 +80,19 @@ public static unsafe class GeneratorDriverTests
public void Tick(ref DupTerm self, in Health a, in Health b) => self.V++;
}
// Non-component ref parameter: Register must return -2.
public struct PlainData
{
public int V;
}
public partial struct BadParam : IComponent
{
public int V;
public void Tick(ref BadParam self, ref PlainData other) => self.V++;
}
""";
public static int Run()
@@ -99,7 +112,7 @@ public static unsafe class GeneratorDriverTests
failures += CheckMover(asm);
failures += CheckBomb(asm);
foreach (var name in new[] { "Fx.ByValue", "Fx.DoubleDt", "Fx.DupTerm" })
foreach (var name in new[] { "Fx.ByValue", "Fx.DoubleDt", "Fx.DupTerm", "Fx.BadParam" })
{
failures += Check(CallRegister(asm, name) == -2, $"{name}.Register -> -2 (unrunnable shape)");
}
+2 -2
View File
@@ -169,8 +169,8 @@ auto GenericSystems::register_system(ecs_world_t* world, const char* name,
// Owned components only: every field is then a real column array
// (an inherited/shared match would be a single pointer, not an array).
qd.terms[i].src.id = EcsSelf;
qd.terms[i].inout =
(access[i] == ENGINE_ABI_ACCESS_IN) ? EcsIn : EcsInOut;
qd.terms[i].inout = static_cast<int16_t>(
(access[i] == ENGINE_ABI_ACCESS_IN) ? EcsIn : EcsInOut);
sys.sizes[i] = static_cast<int32_t>(ti->size);
}
qd.cache_kind = EcsQueryCacheAuto;