stride3d/stride · error · NotImplementedException
Can't have member variables with generic shader types
Error message
Can't have member variables with generic shader types
What it means
During member-variable symbol processing, if a generic type name (containing '<') cannot be resolved to a known shader type, the compiler cannot instantiate it and throws. Member variables with generic shader types are not supported by the SPIR-V backend, so it fails fast with NotImplementedException.
Solutions
- Replace the generic member type with a fully resolved concrete shader type.
- Express the generic instantiation via shader composition/inherit syntax rather than a member variable.
- Check spelling and that the referenced shader module exists so it resolves before the generic check.
Example fix
// before ShaderBase<MyEffect> effectMember; // after MyEffect effectMember; // concrete instantiated type
Defensive patterns
Strategy: type-guard
Validate before calling
if (typeName.Contains('<') && !table.TryResolveType(typeName, out _))
throw new InvalidOperationException("Resolve generic shader types before declaring them as members"); Type guard
static bool IsResolvedMemberType(TypeName tn, SymbolTable table) =>
!tn.Name.Contains('<') || tn.TryResolveType(table, null, out _); Try / catch
try { shaderClass.ProcessSymbol(table, context); }
catch (NotImplementedException ex) when (ex.Message.Contains("generic shader types"))
{
// replace the generic member with a concrete instantiated type
} Prevention
- Never declare member fields with uninstantiated generic shader types.
- Use composition/inherit syntax for generic shader combinations instead of fields.
When it happens
Trigger: Declaring a member variable whose TypeName contains '<' and does not resolve via TryResolveType, e.g. an uninstantiated generic shader class as a field.
Common situations: Using generic composition types like ShaderBase<T> as member fields instead of concrete instantiated types in a shader class.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Struct not found in shader
- Could not find compositions for expression
- External variable not found
- Can't find function in current mixin
- Can't find method group info for
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/aa1da89268e94a3d.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/ShaderElements.MethodOrMember.cs:192
public StreamKind StreamKind { get; set; } = streamKind;
public bool IsCompose { get; set; }
public bool IsArray => TypeName?.IsArray ?? false;
public Expression? Value { get; set; } = initialValue;
public TypeModifier TypeModifier { get; set; } = typeModifier;
public StorageClass StorageClass { get; set; } = storageClass;
public InterpolationModifier Interpolation { get; set; } = interpolation;
public Symbol? Symbol { get; private set; }
public override void ProcessSymbol(SymbolTable table, SpirvContext context)
{
base.ProcessSymbol(table, context);
foreach (var generic in TypeName.Generics)
generic.ProcessSymbol(table);
if (!TypeName.TryResolveType(table, context, out var memberType))
{
if (TypeName.Name.Contains("<"))
throw new NotImplementedException("Can't have member variables with generic shader types");
var classSource = new ShaderClassInstantiation(TypeName.Name, []);
var shader = SpirvBuilder.GetOrLoadShader(table.ShaderLoader, classSource, table.CurrentMacros.AsSpan(), ResolveStep.Compile, context);
classSource.Buffer = shader;
var shaderType = ShaderClass.LoadAndCacheExternalShaderDefinition(table, context, classSource);
// Resolve again (we don't use shaderType directly, because it might lack info such as ArrayType)
TypeName.ProcessSymbol(table);
memberType = TypeName.Type!;
}
if (memberType is AppendStructuredBufferType or ConsumeStructuredBufferType)
{
var bufTypeName = memberType is AppendStructuredBufferType ? "AppendStructuredBuffer" : "ConsumeStructuredBuffer";
table.AddError(new(TypeName.Info, $"{bufTypeName} is not supported. Use RWStructuredBuffer with a separate counter buffer instead (variable '{Name}')."));
return;
}
var storageClass = (memberType, StorageClass, StreamKind) switchView on GitHub (pinned to 96fad776d2)