Skip to main content
Version: Next

Diagnostics reference

This page mirrors the authoritative diagnostic catalogue in docs/diagnostics.md. Preserve these GS#### meanings when configuring suppressions, warning promotion, or tooling.

Every diagnostic emitted by gsc carries a stable GS#### identifier, a severity level, a human-readable message, and a source location (file, line, column). This document enumerates all identifiers so that project files can suppress or promote them using standard MSBuild properties.

Severity levels

LevelMeaning
ErrorCompilation cannot succeed; gsc exits with code 1.
WarningCompilation succeeds; gsc exits with code 0 unless /warnaserror is in effect.
InfoInformational; never affects the exit code.

Suppressing and promoting diagnostics

gsc accepts the following command-line flags (all also available via the Gsharp.NET.Sdk MSBuild SDK through the matching MSBuild properties):

FlagMSBuild propertyEffect
/nowarn:<ids><NoWarn>Suppress the listed warning IDs. Errors cannot be suppressed.
/warnaserror<TreatWarningsAsErrors>true</TreatWarningsAsErrors>Promote every warning to an error.
/warnaserror+:<ids><WarningsAsErrors>Promote only the listed IDs to errors.
/warnaserror-:<ids>Exempt the listed IDs from a global /warnaserror.

IDs may be given as GS0001, 0001, or the bare integer 1; all three forms are equivalent.

Example .gsproj snippet:

<PropertyGroup>
<!-- suppress a noisy warning -->
<NoWarn>GS0168</NoWarn>
<!-- treat a specific warning as an error -->
<WarningsAsErrors>GS0176</WarningsAsErrors>
</PropertyGroup>

Diagnostic catalogue

Lexer diagnostics (GS0001–GS0005)

IDSeverityDescriptionExample trigger
GS0001ErrorBad character input.Source contains a character that is not part of the GSharp alphabet (e.g. `).
GS0002ErrorUnterminated comment.A /* that has no matching */.
GS0003ErrorUnterminated string literal.A " that has no closing " before end-of-line or end-of-file.
GS0004ErrorInvalid number literal.9999999999999999999 is out of range for int.
GS0005ErrorUnexpected token.Parser expected one token kind but found another (e.g. missing ) or ;).

Binder / semantic diagnostics (GS0100–GS0189)

IDSeverityDescriptionExample trigger
GS0100ErrorNot all code paths return a value.A non-void function is missing a return on some branch.
GS0101ErrorParameter already declared.Two parameters share the same name.
GS0102ErrorSymbol already declared.A variable or function name is used twice in the same scope.
GS0103ErrorMethod receiver must be a struct or class declared in the same package.Receiver type is a built-in or external type.
GS0104ErrorReserved; not currently emitted. Zero-field data class/data struct declarations are supported (issue #2363, ADR-0029) with trivial equality/hash/ToString/copy semantics and no synthesized Deconstruct.
GS0105Errorinline struct requires exactly one field.inline struct Foo { a int; b int } has two fields.
GS0106Errorinline cannot be combined with data.inline data struct Foo { … } is not legal. (Historical: the record keyword was removed by; pre-removal this diagnostic also covered inline record.)
GS0107Errorinline struct cannot be combined with open.open inline struct Foo { … } is not legal.
GS0108ErrorInline struct synthesised member conflicts with an explicit declaration.An inline struct auto-generates certain member names that cannot be re-declared.
GS0109Errorrecord was an alias for data struct and could not be combined with data. GS0307 replaces this on legacy sources.data record Foo { … } — use data struct Foo or data class Foo.
GS0110ErrorEmpty enum declaration.enum Color {} — an enum must have at least one member.
GS0111ErrorDuplicate enum member.Two members in the same enum share a name.
GS0112ErrorUndefined enum member.Color.Purple where Purple is not a declared member of Color.
GS0113ErrorUndefined type.A type name referenced in code does not exist.
GS0114ErrorInvalid array length.Array length must be a non-negative integer literal.
GS0115ErrorArray literal length mismatch.[3]int{1, 2} — literal has 2 elements but length is 3.
GS0116ErrorType is not indexable.x[0] where x is bool or another type with no array/slice/map element access and no CLR indexer. Arrays, slices, maps, CLR indexers, and Span[T] / ReadOnlySpan[T] are all indexable.
GS0117ErrorInvalid argument type for a built-in function.len(42)len cannot be applied to an int.
GS0118ErrorA try statement requires at least one catch or finally clause.try { f() } with no catch or finally.
GS0119ErrorType is not disposable.using x = Foo() where Foo provides no public Dispose() method.
GS0120ErrorInvalid break or continue.break used outside of a loop.
GS0121ErrorInvalid return.return used outside of a function.
GS0122ErrorVoid function cannot return an expression.return 42 inside a function declared without a return type.
GS0123ErrorMissing return expression.return with no value inside a function that returns int.
GS0124ErrorExpression must have a value.A void call used in a value position (e.g. x = fmt.Println()).
GS0125ErrorVariable not defined.x referenced before being declared.
GS0126ErrorName is not a variable.len = 5len is a function, not a variable.
GS0127ErrorVariable is read-only.Assignment to a const or let-bound name.
GS0128ErrorUnary operator not defined for type.!42! is not defined for int.
GS0129ErrorBinary operator not defined for types.true + 1+ is not defined for (bool, int).
GS0130ErrorUndefined function.A call to a function name that was never declared.
GS0131ErrorName is not a function.x() where x is an int variable.
GS0132Errorawait outside an async func.await someTask in a regular (non-async) function.
GS0133ErrorExpression is not awaitable.await 42int is not a Task or Task[T].
GS0134ErrorExpression is not async-enumerable.await for x in 42int does not implement IAsyncEnumerable[T].
GS0135Errorasync modifier in a type clause is only valid before sequence[T], (T) -> R, or func(...).async int in a type position.
GS0136Erroryield outside an iterator function.yield return 1 in a function that returns int, not sequence[int].
GS0137Errorgo operand is not a call expression.go x + 1 — only function calls may follow go.
GS0138Errordefer operand is not a call expression.defer x + 1.
GS0139ErrorReceive operator <- requires a channel.<-42.
GS0140ErrorSend operator <- requires a channel on the left.42 <- x.
GS0141Errorclose requires a channel operand.close(42).
GS0142Errorselect with no cases.select {} is unreachable.
GS0143Errorselect has more than one default arm.Two default: arms inside one select.
GS0144ErrorWrong number of arguments to function.f(1, 2) when f requires three arguments.
GS0145ErrorVariadic parameter is not the last parameter.func f(a ...int, b string).
GS0146ErrorVariadic parameter only allowed on top-level function declarations.Variadic parameter on a closure or method.
GS0147ErrorToo few arguments for variadic function.Calling a variadic function with fewer than the minimum required arguments.
GS0148ErrorGeneric function has wrong number of type arguments.f[int, string]() when f takes only one type parameter.
GS0149ErrorType is not generic.int[string]int accepts no type arguments.
GS0150ErrorType-parameter variance position violation.A covariant type parameter used in a contravariant position.
GS0151ErrorType argument inference failed.The compiler could not infer a type argument from the call arguments.
GS0152ErrorType argument does not satisfy constraint.f[MyStruct]() where MyStruct does not implement the required interface constraint.
GS0153ErrorConstraint is neither an interface nor a class.A generic type-parameter constraint must be an interface (any interface — sealed or not, generic or not;) or a base class; a value type such as a struct or enum is rejected.
GS0154ErrorWrong argument type.A positional argument's type does not match the parameter type.
GS0155ErrorCannot convert type.An explicit cast between incompatible types.
GS0156ErrorCannot convert implicitly; explicit conversion exists.int x = 3.14 — an explicit cast is available but was not written.
GS0157ErrorCannot find type (possibly missing import).A package-qualified type name that resolves to nothing.
GS0158ErrorCannot find member.A field or property access that does not resolve.
GS0159ErrorCannot find function.A package-qualified function name that resolves to nothing.
GS0160ErrorAmbiguous overload.A call that matches more than one overload equally well. Generic candidates are filtered against their where-constraints; the constraint-disjoint case usually resolves to one candidate, but two candidates with mutually-incomparable constraint specificity remain ambiguous and report this code.
GS0161Errorcopy/with receiver is not a data struct..copy(…) used on a plain struct.
GS0162ErrorNamed arguments only supported for data struct .copy(…).Named arguments passed to a regular function.
GS0163ErrorDeconstruction field count mismatch.let (a, b) = p where p is a data struct with three fields.
GS0164ErrorDeconstruction requires a tuple or data struct initializer.Deconstruction attempted on a plain struct.
GS0165ErrorMultiple top-level files.More than one source file contains top-level statements.
GS0166ErrorTop-level statements conflict with an explicit Main function.Both top-level statements and a func Main() are present.
GS0167ErrorMulti-assignment target/value count mismatch.a, b = 1, 2, 3 — three values for two targets.
GS0168Errorfallthrough is not supported.fallthrough keyword used in a switch case body.
GS0169ErrorDuplicate default arm in switch.Two default: arms inside one switch statement.
GS0170ErrorSwitch case value is not a constant expression.case x: where x is a mutable variable.
GS0171ErrorSwitch case type is incompatible with the switch expression.switch (s) { case 42: } where s is string.
GS0172ErrorProperty pattern requires a struct or class value.A property pattern { Field: value } applied to a non-struct/class type.
GS0173ErrorUndefined field on type.Accessing a struct field that was never declared.
GS0174ErrorRelational pattern operator not defined for type.case > 5: where the switched type doesn't support >.
GS0175ErrorList pattern requires an array or slice.List pattern [a, b] applied to a non-array/slice value.
GS0176ErrorSwitch expression is missing a default arm.A switch expression that cannot be proven exhaustive and has no default.
GS0177ErrorSwitch expression on enum is not exhaustive.One or more enum members not covered and no default arm.
GS0178ErrorSwitch statement on enum is not exhaustive.One or more enum members not covered and no default arm.
GS0179ErrorSwitch expression arm type mismatch.Different arms of a switch expression produce incompatible types.
GS0180ErrorAccessibility modifier not allowed here.pub or priv used on a local variable or inside a function body.
GS0181ErrorBase class is not open.Inheriting from a class that was not declared open.
GS0182ErrorMethod is overridable; override required.Redefining an open method without the override keyword.
GS0183ErrorNo matching open base method for override.override keyword present but no base class defines a matching open method.
GS0184ErrorCannot override a non-open base method.override targets a method that was not declared open.
GS0185ErrorOverride signature mismatch.An override method has different parameter types or return type than the base.
GS0186ErrorInterface method may not have a body.Default-interface methods are now supported (see GS0318–GS0321).
GS0187ErrorClass does not implement interface method.A class claims to implement an interface but a required method is absent.
GS0188ErrorClass cannot implement a sealed interface from a different package.Implementing a sealed interface defined outside the current package.
GS0189ErrorThe return type of an async func(...) type clause is implicitly wrapped in Task; do not write Task[…] explicitly.async func(int) Task[int] in a type position.

Async state-machine diagnostics (GS0190)

IDSeverityDescriptionExample trigger
GS0190ErrorAsync state machine unavailable for this function.An async func uses a language feature that the GSharp async emitter does not yet support (e.g. await inside a nested try block).

Character literal diagnostics (GS0191–GS0195)

IDSeverityDescriptionExample trigger
GS0191ErrorUnterminated character literal.A ' that has no closing ' before end-of-line.
GS0192ErrorEmpty character literal; a character literal must contain exactly one code unit or escape.'' with nothing inside.
GS0193ErrorCharacter literal contains more than one code unit; use a string literal instead.'ab'.
GS0194ErrorUnrecognised escape sequence in character literal.'\q'.
GS0195ErrorMalformed Unicode escape in character literal.'\u00G0'.

Attribute / annotation diagnostics (GS0196–GS0211)

Kotlin-style attribute syntax (@Foo(...)) and the @Attribute declaration sugar. The following diagnostics cover parsing, resolution, use-site validation, and the compiler-recognised attribute set.

IDSeverityDescriptionExample trigger
GS0196ErrorAnnotation name expected after @.@ func Foo() {} — bare @ with no identifier.
GS0197ErrorAnnotation target is not a recognized use-site kind.@bogus:Foo func Bar() {} — must be one of field, param, return, type, method, property, event, module, assembly, genericparam.
GS0198ErrorAttribute type could not be found.@DoesNotExist func Foo() {} — neither DoesNotExist nor DoesNotExistAttribute resolves to a type.
GS0199ErrorAttribute name is ambiguous between Foo and FooAttribute.Both types are in scope; qualify to disambiguate.
GS0200ErrorType is not an attribute class (it does not derive from System.Attribute).@int func Foo() {}.
GS0201ErrorAttribute target is not valid at this position.@field:Obsolete func Foo() {}field is not allowed on a function.
GS0202ErrorAttribute arguments must be compile-time constants.@Trace(myVar) — argument is not a primitive, string, typeof, enum, or 1-D array thereof.
GS0203ErrorClass tagged @Attribute cannot also declare an explicit base class.@Attribute class Trace : Other {} — the @Attribute sugar implies : System.Attribute.
GS0204Warning (Error if IsError=true)Reference to a symbol marked [Obsolete].Calling a function, instantiating a class (Old(5)), writing a struct literal (Old{}), naming a struct/class/interface/enum in a type clause, reading an obsolete parameter, reading/writing an obsolete var/let/const, reading an obsolete enum member (Color.Red), or reading/writing an obsolete struct/class field (p.Old) — all declared with @Obsolete("use Bar"). Severity is promoted to error when the attribute's second argument is true.
GS0205ErrorAttribute is reserved for compiler synthesis.@CompilerGenerated, @Extension, @AsyncStateMachine, @Nullable, or @NullableContext written in user source.
GS0206ErrorAnnotations are only allowed on variable declarations, not on this statement.@Obsolete\nreturn inside a function body — annotations may precede var/let/const but no other statement kind.
GS0207ErrorParameter {name} is annotated @EnumeratorCancellation but has type {type}; only System.Threading.CancellationToken parameters can carry this annotation.@EnumeratorCancellation placed on a string parameter.
GS0208ErrorParameter {name} is annotated @EnumeratorCancellation but its enclosing function is not an async sequence (does not return IAsyncEnumerable[T]).@EnumeratorCancellation on a sync function or a non-sequence async function.
GS0209ErrorAttribute {name} is not valid on this position; its [AttributeUsage] permits only: {targets}.Applying a @field-targeted attribute to a method.
GS0210ErrorDuplicate attribute {name}; this attribute type does not allow multiple applications (AllowMultiple = false).Two @Trace(...) annotations on the same declaration.
GS0211ErrorAttribute [DllImport] was historically rejected wholesale; well-formed @DllImport-annotated P/Invoke declarations are now accepted (see GS0322–GS0329 for shape-specific diagnostics). The slot is reserved for any future blanket-rejection use.n/a — no longer fired.
GS0212ErrorFunction {name} is marked @Conditional but does not return void; conditional methods must return void because calls may be elided at the call site.@Conditional("DEBUG") func Probe() int32 { return 0 }.

Class / constructor diagnostics (GS0213–GS0217)

User class constructor flow — explicit init(...) constructors, primary constructors, and base(...) initializers.

IDSeverityDescriptionExample trigger
GS0213ErrorA base-constructor argument list requires an explicit base class.init() : base(1) { } written on a class with no : BaseType clause.
GS0214ErrorClass {base} has no accessible constructor that takes {N} argument(s).init() : base(1, 2) when the base only declares init().
GS0215ErrorClass {name} cannot declare both a primary constructor and an explicit init constructor.class Customer(id int32) { init(name string) { } }.
GS0216ErrorClass {name} declares multiple init constructors; only a single explicit constructor is supported.Two init(...) declarations in the same class body.
GS0217ErrorGeneric class {name} with an explicit init constructor cannot be constructed; generic explicit constructors are not supported.class Box[T] { init(x T) { } } then Box[int32](42).

Delegate conversion diagnostics (GS0218)

IDSeverityDescriptionExample trigger
GS0218ErrorCannot convert method group {name} to {type}. No overload matches the target delegate signature.var a Action = SomeOverloaded where no overload of SomeOverloaded has signature () -> void.

String interpolation diagnostics (GS0220–GS0225)

Interpolation holes (${expr,alignment:format}) and the interpolated-string-handler pattern report the following.

IDSeverityDescriptionExample trigger
GS0220ErrorInterpolation alignment clause is not a constant integer."${x,abc}" — the value after the , in ${expr,alignment[:format]} must be a constant integer (e.g. ${x,5} or ${x,-8:X4}).
GS0221ErrorAn interpolated string passed to an [InterpolatedStringHandler] parameter could not satisfy [InterpolatedStringHandlerArgument] forwarding.The forwarded argument names an unknown parameter, the receiver cannot be forwarded, or no handler constructor matches (int, int, …forwarded[, out bool]).
GS0222ErrorUnterminated interpolation hole; expected a closing }."v=${a + b" — the ${ opens a hole that the delimiter-aware scanner never closes before end of file.
GS0223ErrorEmpty interpolation hole; expected an expression between ${ and }."x=${}" — a hole must contain an expression.
GS0224ErrorEmpty format specifier; expected a format string after :."${n:}" — a : clause must be followed by a non-empty format string.
GS0225ErrorNewline in the literal portion of an interpolated string; only ${ … } holes may span lines.A raw newline appears outside a hole, e.g. a "… opened on one line with no closing " before the line break. (Multiline holes themselves are legal.)

Note: originally proposed GS0212–GS0216 for the malformed-hole diagnostics, but those codes were already taken; the implemented codes are GS0222–GS0225.

By-ref-like (ref struct) diagnostics (GS0219)

A by-ref-like type — a CLR ref struct carrying System.Runtime.CompilerServices.IsByRefLikeAttribute, such as System.Span[T], System.ReadOnlySpan[T], or System.Runtime.CompilerServices.DefaultInterpolatedStringHandler — is stack-only. G# permits declaring and using such a value as an ordinary local, but the CLR forbids any use that would let it reach the heap. Those escapes are rejected with GS0219.

G# can also declare its own by-ref-like value types with a ref modifier on a struct declaration:

ref struct Window {
Items ReadOnlySpan[int32] // a ref struct may hold by-ref-like fields
Label string
}

Such a type is emitted with System.Runtime.CompilerServices.IsByRefLikeAttribute (and the C# compiler's [Obsolete] guard marker), so the CLR treats it as stack-only. The same escape rules below apply to user-declared ref struct types exactly as they do to imported ones. The only relaxation is that a ref struct may itself hold by-ref-like fields (it is stack-only too); a static field of a ref struct is still rejected.

IDSeverityDescriptionExample trigger
GS0219ErrorA by-ref-like (ref struct) value is used in a position that would let it escape the stack: boxing / converting it to a reference type (object, an interface, a delegate base), storing it in a field of a non-ref-struct (instance, primary-constructor, or static), capturing it in a closure, declaring it as a local in an async function or an iterator (where it would be hoisted into the heap-allocated state machine), using it as a generic type argument, or returning it from a function when the parameter is annotated scoped.var o object = span (box); a class/struct field typed Span[int32]; capturing a ReadOnlySpan[char] local inside func() { ... }; declaring a Span[int32] local in an async function; List[ReadOnlySpan[int32]]; func f(scoped s Span[int32]) Span[int32] { return s }.

The scoped modifier can be placed on a parameter to indicate that the ref struct (or managed-pointer) value must not be returned or stored beyond the call site:

import System
// `scoped` means `s` cannot be returned or escape.
func firstElement(scoped s ReadOnlySpan[int32]) int32 {
return s[0]
}

Span element access diagnostics (GS0226)

/§2 makes spans indexable: a Span[T] / ReadOnlySpan[T] indexer returns a managed pointer (ref T / ref readonly T), and a read in rvalue position auto-dereferences to the pointee T (§1). A Span[T] element write span[i] = v stores through the ref T. A ReadOnlySpan[T] element is ref readonly T, so writing through it is a hard error (GS0226); reading it is always permitted.

IDSeverityDescriptionExample trigger
GS0226ErrorCannot assign through a read-only span element (ReadOnlySpan[T] is read-only).var s ReadOnlySpan[int32] = arr then s[0] = 1 — a ReadOnlySpan[T] indexer is ref readonly T; use Span[T] to write.

Pointer / by-ref diagnostics (GS9001–GS9006)

IDSeverityDescriptionExample trigger
GS9001ErrorCannot take the address of a non-lvalue.&(1 + 2) — the operand is a temporary expression.
GS9002ErrorArgument must be passed by ref.A ref parameter called without the ref modifier.
GS9003ErrorVariable not definitely assigned before ref use.ref x where x has not been assigned.
GS9004ErrorBy-ref value cannot escape its declaration scope.Returning a *T (managed-pointer) value from a function, capturing a *T local in a closure, hoisting a *T local into an async/iterator state machine, or using a *T return type in a function literal. Also raised when returning a ref struct parameter annotated as scoped.
GS9005ErrorCannot take the address of a constant.&myConst where myConst is declared const.
GS9006ErrorPointer type cannot be a field type.A struct or class field (including static shared fields and top-level globals) declared with a *T (managed-pointer) type outside an unsafe context. Inside an unsafe context *T is an unmanaged pointer and IS legal as a field type.
GS0398ErrorUnmanaged pointer to a non-blittable pointee.An unsafe-context *T whose pointee T is a managed reference type or otherwise non-blittable (e.g. *string, or a struct with a managed field); only blittable primitives, pointers-to-pointers, and blittable user/value structs are legal pointees.
GS0399Errorstackalloc element type must be a blittable (unmanaged) type.A stackalloc [n]T whose element type T is a managed reference type or otherwise non-blittable (e.g. stackalloc [4]string); only blittable primitives and pointers are legal stackalloc element types.
GS0400ErrorA fixed statement requires an unsafe context.A fixed <name> *T = <source> {... } statement used outside an unsafe context (function, unsafe {... } block, or unsafe type). Because it binds a raw unmanaged pointer, fixed is legal only inside unsafe, consistent with *T pointer gating.
GS0401ErrorA fixed statement source is not pinnable, or the pointer's element type does not match.The source of a fixed statement must be a managed array/slice ([]T), a string, or a span-like type exposing a public instance ref T GetPinnableReference() (e.g. System.Span[T] / System.ReadOnlySpan[T]), and the bound pointer's pointee type must match the buffer's element type (uint16/char interchangeable for string). Reported for a non-pinnable source (e.g. a scalar, or a type without GetPinnableReference) or a pointee/element-type mismatch.
GS0402ErrorThe operand of an increment/decrement operator must be an assignable variable, field, or indexed element.A prefix or postfix ++/-- applied to something that is not a writable lvalue, e.g. 5++, (a + b)--, or a function-call result. The operand must be a mutable variable, field, array element, or indexer target.
GS0403ErrorCannot dereference, index, or perform arithmetic on a void pointer *void.A true void-element pointer *void (C# void*) carries no element type, so *p, p[i], p + i, p - i, and p - q are rejected; cast it to a typed pointer *T (e.g. *int32(p)) first. Casts to/from typed pointers and nint, and comparison/equality, are allowed.
GS0404ErrorA managed function-pointer type *func(...) R requires an unsafe context.A managed function-pointer type clause *func(T1, T2) R used outside an unsafe context; like the raw pointer *T, a function pointer is only legal inside unsafe.
GS0405ErrorCannot take the address of this method as a function pointer.&Method where the operand is not a single static/free, non-generic method (e.g. an instance method, an overloaded method group, or a generic method), or it is used outside an unsafe context.
GS0406ErrorA fixed-size buffer field fixed name [N]T requires an unsafe context.A fixed name [N]T buffer field declared in a non-unsafe struct; declare it inside an unsafe struct.
GS0407ErrorA fixed-size buffer field must have a fixed-length array element type [N]T.A fixed name <T> field whose type clause is not a fixed-length array [N]T.
GS0408ErrorA fixed-size buffer field must have a positive length.A fixed name [N]T field with N <= 0.
GS0409ErrorFixed-size buffer element type is not supported.A fixed name [N]T field whose element type is not a blittable primitive (bool, int8…int64, uint8…uint64, char, float32, float64).
GS0411ErrorA count-inferred stackalloc []T requires an initializer.A count-inferred stackalloc []T written without a brace-delimited initializer, so its length is undeterminable (e.g. stackalloc []int32). Supply an initializer (stackalloc []int32{1, 2, 3}) or spell the count explicitly (stackalloc [n]T).
GS0412ErrorA stackalloc [n]T{…} initializer length must match the explicit count.A stackalloc [n]T{…} whose explicit constant count n disagrees with the number of initializer elements (e.g. stackalloc [2]int32{1, 2, 3}). As in C#, the two must match; use the count-inferred stackalloc []T{…} to avoid repeating the length.
GS9007ErrorA type may contain at most one shared block.A class or struct with two shared { ... } blocks; merge them into one.

Reference closure diagnostics (GS9100)

IDSeverityDescriptionExample trigger
GS9100WarningOne or more assemblies supplied via /r: depend (transitively) on assemblies that were not also supplied, so the reference set is not a complete transitive closure. The compiler degrades gracefully — members whose signatures live in the missing assemblies are skipped rather than aborting the build — but the affected members become invisible. The message names the missing assemblies. Add the missing package/project reference (the SDK passes @(ReferencePathWithRefAssemblies), MSBuild's full transitive closure, so this normally only appears with a hand-rolled /r: set). Suppress with /nowarn:GS9100.gsc /r:LibAsmA.dll app.gs where LibAsmA.dll references DepAsmB.dll and DepAsmB.dll is not also passed.

Internal / emit diagnostics (GS9998–GS9999)

These diagnostics indicate an internal compiler problem. If you encounter them, please file an issue.

IDSeverityDescription
GS9998ErrorAn unexpected NotSupportedException or InvalidOperationException was raised during IL emission. The message text contains the original exception message.
GS9999ErrorAn unexpected exception was caught by the evaluator. The message text contains the original exception message.

Documentation diagnostics (GS0227–GS0231)

CodeSeverityMessage
GS0227WarningDocumentation comment is not attached to a declaration.
GS0228WarningMissing documentation comment on public member {name}. (opt-in)
GS0229WarningDocumentation @param {name} does not match any parameter of {symbol}.
GS0230WarningUnsupported documentation Markdown: {detail}.
GS0231WarningUnknown documentation tag {tag}. Valid tags are: @param, @typeparam, @returns, @remarks, @value, @exception, @seealso.

Data struct diagnostics (GS0232)

Every data struct synthesizes a fixed contract of value-semantics members — Equals(object), Equals(Name), GetHashCode(), ToString(), op_Equality(Name, Name), op_Inequality(Name, Name), and Deconstruct(out T1, out T2, …). Hand-written versions are rejected so the contract stays predictable and so consumers (G# and external.NET) can rely on the synthesized IL.

CodeSeverityMessage
GS0232ErrorData struct {type} synthesizes member {member}; it cannot be declared explicitly.

Named delegate type diagnostics (GS0233)

type Name = delegate func(...) declares a real CLR MulticastDelegate-derived named delegate type so C# consumers see a conventional handler type (and so G# events can carry first-class custom delegate types). Anything other than a function signature on the right-hand side is rejected. Generic delegate declarations such as type Predicate[T any] = delegate func(value T) bool now bind and emit a verifiable generic delegate TypeDef (one GenericParam row per type parameter, threaded through the Invoke/.ctor signatures), so the former GS0234 ("generic delegate declaration not yet supported") has been retired.

CodeSeverityMessage
GS0233ErrorNamed delegate declaration requires 'func(...)' after 'delegate' (e.g. 'type Name = delegate func(sender Object, e EventArgs)').

Ref-kind parameter diagnostics (GS0235–GS0243)

G# supports explicit ref, out, and in parameter passing modes at both call sites and method-definition sites. These diagnostics cover modifier mismatches, assignment requirements, and invalid parameter shapes. The async/iterator ban reuses the existing GS0226 family.

CodeSeverityMessage
GS0235ErrorArgument {index} (parameter {name}) passes with ref-kind {actual} but the parameter is declared {expected}.
GS0236ErrorAn 'out var/let/_' inline declaration is only valid on an 'out' argument.
GS0237ErrorCannot assign to 'in' parameter {name} — it is read-only.
GS0238ErrorThe 'out' parameter {name} must be assigned on every path before the function returns.
GS0239ErrorThe variable {name} must be definitely assigned before it can be passed by 'ref'.
GS0240ErrorOverride of {name} must match the base ref-kind on parameter {parameter} ({baseKind} vs {overrideKind}).
GS0241ErrorA variadic parameter cannot carry a ref-kind modifier ('ref'/'out'/'in').
GS0242WarningArgument {index} (parameter {name}) is passed by 'in' implicitly; add 'in' at the call site to make the read-only pass explicit.
GS0243ErrorA pointer type '*T' is not a valid parameter type; use the appropriate ref-kind modifier instead (e.g. 'ref T', 'out T', 'in T').

Cause/fix examples:

  • GS0235 — fire when the call-site modifier doesn't match the declaration: f(x) where f(ref x int32) requires f(&x) or f(ref x). Fix: add the matching modifier; if the parameter is by-value, drop any unwanted ref/out/in.
  • GS0236out var n outside an out argument: e.g. func g(int32) {} then g(out var n). Fix: only use the inline declaration when the parameter is declared out.
  • GS0237 — assignment to an in parameter inside the body: func h(in p int32) { p = 0 }. Fix: copy to a local for any mutation, or change the parameter to ref.
  • GS0238 — a missing write before return on an out parameter: func k(out r int32) bool { if cond { r = 1; return true } return false } — the false branch fails to assign r. Fix: assign on every path.
  • GS0239 — passing an uninitialized variable by ref: var x int32; f(ref x) with no prior assignment. Fix: assign before the call (e.g. var x = 0).
  • GS0240 — override changes the ref-kind of an inherited parameter: func override f(in p int32) { … } when the base declares f(ref p int32). Fix: match the base declaration.
  • GS0241 — variadic combined with ref-kind: func g(ref values ...int32) {}. Fix: remove the modifier or remove the variadic decoration.
  • GS0242 (warning) — passing a plain identifier to an in parameter without writing in: f(x) where f(in x int32). Fix: write f(in x) to make the pass-by-readonly-ref explicit. The compiler does NOT silently spill the value (a deliberate departure from C#).
  • GS0243 — declaring a parameter whose type is the raw pointer *T: func f(p *int32). Fix: use a ref-kind modifier instead — func f(ref p int32) (or in/out).

Named-argument diagnostics (GS0244–GS0247)

Named arguments at call sites — Foo(timeout: 30, retries: 3) — for free functions, user methods, user constructors, user extension functions, imported CLR methods and constructors, imported extension methods, and inherited CLR instance methods (including delegate Invoke). Indirect calls through a function-typed or delegate-typed variable, and variadic call sites, intentionally do not accept named arguments because the call target does not preserve parameter names. The diagnostics below flag malformed or unresolvable named-argument call sites.

CodeSeverityMessage
GS0244ErrorPositional argument cannot follow a named argument.
GS0245ErrorNamed argument {name} is specified more than once.
GS0246ErrorThe best overload of {callee} does not have a parameter named {name}.
GS0247ErrorNamed argument {name} specifies a parameter for which a positional argument has already been given.

Cause/fix examples:

  • GS0244Foo(1, name: "a", 2). Fix: move every named argument to the trailing positions, or pass the named one positionally.
  • GS0245Foo(timeout: 1, timeout: 2). Fix: remove the duplicate.
  • GS0246Foo(qty: 3) when Foo has no parameter named qty. Fix: use the correct parameter name. Also fires when calling through a function-typed/delegate variable, or when targeting a variadic parameter list (parameter names are not addressable in those cases).
  • GS0247Foo(1, x: 2) when Foo(x int32, y int32) is bound — the positional 1 already filled x. Fix: drop one or the other.

Ref-aliasing local diagnostics (GS0256–GS0258)

let ref / var ref declarations create aliasing locals — locals whose IL slots are managed pointers T& and alias another lvalue (let ref m = arr[i], var ref v = c.Field). The diagnostics below flag malformed or illegal ref-alias declarations.

CodeSeverityMessage
GS0256ErrorThe right-hand side of a 'ref' local declaration must be an lvalue (variable, field, indexer, or dereference).
GS0257ErrorA 'ref' local cannot be initialized from an expression with a narrower escape scope than the local itself.
GS0258ErrorA 'ref' local cannot be declared here — only inside non-async, non-iterator function bodies (no top-level, no const).

Cause/fix examples:

  • GS0256let ref m = 1 + 2 or let ref m = foo(). The RHS must denote storage you can take the address of. Fix: alias an addressable expression (let ref m = arr[0], let ref m = c.Value, let ref m = *p), or drop ref and copy the value.
  • GS0257 — Reserved for the full ref-safety analysis. Will fire when the RHS storage cannot live as long as the alias (e.g. a ref returned from a callee that captured a shorter-lived local). V1 has no ref returns, so this code is defined for forward compatibility and currently does not fire.
  • GS0258let ref m = n at top level, inside async func, inside an iterator (yield-returning) function, or written as const ref. Fix: move the declaration into a synchronous, non-iterator function body and use let ref / var ref (not const ref). Top-level ref locals would require a static field of T&, which the CLR forbids; async / iterator bodies would lift the slot onto a state-machine field, which the CLR likewise forbids.

Conditional expression diagnostics (GS0259–GS0263)

The conditional expression cond ? a : b is available in value contexts and in ref/out/in argument payloads. GS0259 is retired for ordinary value-context conditionals; the remaining diagnostics still fire in their byref contexts, and GS0263 covers the value-context "no common type" failure.

CodeSeverityMessage
GS0259Error (retired)Conditional lvalue expression (cond ? a : b) is only legal as the payload of a 'ref'/'out'/'in' argument modifier or as the operand of '&'. Now only fires for the legacy inner-ref-modifier shape outside ref context.
GS0260ErrorBoth branches of a conditional ref-argument must produce lvalues of the same type, but the true branch is {trueType} and the false branch is {falseType}.
GS0261ErrorAn 'out var'/'out let'/'out _' inline declaration cannot appear inside a branch of a conditional ref-argument (the new local would only conditionally exist). Declare the local before the call instead.
GS0262ErrorInner ref-kind modifier {innerModifier} on a conditional ref-argument branch must match the outer modifier {outerModifier}.
GS0263ErrorConditional expression branches have no common result type — the true branch is {trueType} and the false branch is {falseType}. Add an explicit conversion to align the two arms.

Cause/fix examples:

  • GS0260bump(ref true ? a32 : b64) where a32 int32 and b64 int64. Fix: align the branch types (e.g. introduce a local of the wider type or use a value ternary outside the ref).
  • GS0261produce(out true ? a : out var n) — the inline out var n would declare a local that only exists on one branch. Fix: declare var n int32 before the call.
  • GS0262bump(ref true ? in a : ref b) — the inner in does not match the outer ref. Fix: use bump(ref true ? a : b) (the generalized form requires no inner modifiers).
  • GS0263var x = pick ? true : "no"bool and string have no common type. Fix: explicitly convert one arm (e.g. pick ? "yes" : "no").

Ref-return diagnostics (GS0248–GS0255)

ref-returning functions use declarations of the form func f(...) ref T { ... } and return a managed pointer T& rather than a copied value, paired with the return ref <expr> statement form. The diagnostics below guard the declaration and return-site rules.

CodeSeverityMessage
GS0248ErrorA 'ref' return modifier requires an explicit return type clause (e.g. 'ref int32').
GS0249Error'ref' return is not legal on an {async/iterator} function; the state-machine rewriter cannot hoist a managed pointer.
GS0250Error'ref' return modifier is redundant when the declared return type is already a managed pointer ('*T'); write 'ref T' instead.
GS0251Error'return ref' is not allowed in {functionName} because its declaration does not specify a 'ref' return type.
GS0252ErrorFunction {functionName} returns by reference; use return ref <expr> instead of a plain 'return'.
GS0253ErrorThe operand of 'return ref' must be an lvalue (variable, field, array element, or '*p').
GS0254ErrorCannot return a managed pointer to function-local storage; the reference would dangle once the function returns.
GS0255ErrorOverride of {memberName} must match the base return ref-kind: base returns {expected}, this declaration returns {actual}.

Cause/fix examples:

  • GS0248func f(x int32) ref { return ref x }ref requires the element type. Fix: func f(x int32) ref int32.
  • GS0249async func f() ref int32 { ... } or a yield-iterator body. Fix: drop ref from the return — async / iterator state-machine fields cannot hold managed pointers.
  • GS0250func f(p *int32) ref *int32 { return p }. Fix: write ref int32 (or drop ref and return the pointer).
  • GS0251 — a return ref x statement in a function whose declaration is func f() int32. Fix: add ref to the return type, or drop ref from the return statement.
  • GS0252 — a plain return x in a ref-returning function. Fix: write return ref x.
  • GS0253return ref (a + b) or return ref Foo(). Fix: alias an addressable expression first (let ref t = arr[i]; return ref t) or restructure to return a pointer to durable storage.
  • GS0254func f() ref int32 { var x = 0; return ref x }. Fix: do not return references to function locals; consume the value by copy or alias storage that outlives the call.
  • GS0255 — overriding a base method declared int32 with a ref int32 override (or vice versa). Fix: match the base return ref-kind exactly.

Method-overloading and optional-parameter diagnostics (GS0264–GS0267)

The v0 "one declaration per name" rule, so G# user functions can carry overload sets (differing by parameter types or ref-kinds) and optional parameters with default values. The diagnostics below cover overload-set construction and overload resolution.

CodeSeverityMessage
GS0264ErrorAn overload of {name} with signature {signature} is already declared. Two overloads must differ by parameter types or ref-kinds.
GS0265ErrorOptional parameter {parameterName} is invalid: {reason}.
GS0266ErrorCall to {name} is ambiguous between multiple overloads. Disambiguate with explicit types or named arguments.
GS0267ErrorNo overload of {name} is applicable to the given argument list.

Cause/fix examples:

  • GS0264 — two func F(x int32) {} declarations, or two declarations that differ only in return type. Fix: change the parameter list (different types, arity, or ref-kinds); return type alone is not a distinguishing signature.
  • GS0265 — a default-value expression that is not constant, a parameter whose default depends on another parameter, an optional parameter preceding a required one without all trailing parameters also optional, or an optional ref/out parameter. Fix: use a compile-time-constant default, place optional parameters at the end of the list, and avoid combining ref/out with defaults.
  • GS0266Greet("ada") when both Greet(string) and Greet(name string) are visible via different paths. Fix: rename one, change one signature, or use a named argument that only one overload accepts.
  • GS0267Greet(42) when only Greet(string) is declared. Fix: pass a value of the expected type, or add an overload covering the new argument shape.

if let and guard let binding diagnostics (GS0296–GS0297)

The if let and guard let binding forms. The diagnostics below cover the two misuse paths that the binder rejects up front.

CodeSeverityMessage
GS0296ErrorThe right-hand side of an if let / guard let binding must be of nullable type; non-nullable initializers have nothing to strip.
GS0297ErrorThe else block of guard let must unconditionally exit the enclosing scope (return, throw, break, or continue).

Cause/fix examples:

  • GS0296let s = "hi"; if let v = s { ... }. Fix: either use a plain let v = s (no narrowing) or pass a nullable value. The binding only makes sense when the RHS has type T?.
  • GS0297guard let v = s else { var x = 1 }. Fix: make the else block exit the enclosing scope — return, throw, break, or continue. The binding is only in scope after the guard precisely because the else cannot fall through.

Top-level-statement diagnostics (GS0285–GS0287)

The three diagnostics below cover the project-shape / placement / return-shape rules that the synthesized entry point depends on.

CodeSeverityMessage
GS0285ErrorTop-level statements are not allowed in a library project. Set <OutputType>Exe</OutputType> on the project, or move the statements into an explicit func Main().
GS0286WarningTop-level statements should form a single contiguous block within a file — interleaving them with type or function declarations is hard to read.
GS0287ErrorTop-level statements mix bare return; and return <expr>;. Choose one return shape so the synthesized entry point has a single return type.

Field declaration var / let requirement (GS0288)

Field declarations inside a struct, class, or shared block must carry a leading var (mutable) or let (read-only) keyword. The keyword distinguishes mutable from read-only storage and keeps type bodies visually consistent with property, event, and method members.

CodeSeverityMessage
GS0288ErrorField declarations require a var (mutable), let (read-only), or const (compile-time constant) keyword.

Cause/fix — struct Point { x int32; y int32 }struct Point { var x int32; var y int32 } (or let for read-only, const for a compile-time constant). The parser recovers by treating the field as var, but the error still fires.

Inline field initializer diagnostics (GS0375–GS0377)

const/let/var fields in a type body may carry an inline = expr initializer. Instance initializers run before each constructor body in declaration order; const fields fold to compile-time literal fields; static (shared) initializers run in the static constructor.

CodeSeverityMessage
GS0375ErrorA const field requires an initializer.
GS0376ErrorA const field initializer must be a compile-time constant expression.
GS0377ErrorA field initializer cannot reference the instance member or constructor parameter {name} (field initializers run before the constructor body, so this is not available). Assign it in an init(...) constructor instead.

protected accessibility diagnostics (GS0379–GS0380)

The protected access modifier (CIL family) makes a member accessible within its declaring type and the bodies of derived types only. Because protection is only meaningful where a derived type can exist, protected is restricted to members of an inheritable open class.

CodeSeverityMessage
GS0379Error'{Type}.{member}' is inaccessible due to its protection level: a 'protected' member is only accessible within '{Type}' and types derived from it.
GS0380Error'protected' is only allowed on members of an 'open class' (a type that can be inherited). Mark the enclosing class 'open', or use a different accessibility.

deinit (finalizer) diagnostics (GS0289–GS0292)

deinit { … } declares a CLR finalizer on a class. The diagnostics below cover the placement and shape rules.

CodeSeverityMessage
GS0289Errordeinit is only valid on a class type — <type> is a <kind>.
GS0290ErrorClass <name> declares more than one deinit; only the first declaration emits a finalizer.
GS0291Errordeinit may not declare parameters — the CLR invokes the destructor with no arguments.
GS0292Errordeinit may not declare a return type — the CLR finalizer always returns void.

Labeled break / continue diagnostics (GS0293–GS0295)

Labeled loops and break label / continue label targeting an enclosing loop by name.

CodeSeverityMessage
GS0293ErrorNo enclosing loop is labeled <label> (in break <label> / continue <label>).
GS0294ErrorLabel <label> can only be applied to a loop statement (for / while / do-while).
GS0295WarningLabel <label> shadows an enclosing loop label of the same name; the inner label wins for nested break / continue.

Cause/fix:

  • GS0293 — typo or stale name; spell the label exactly as it appears on the enclosing loop.
  • GS0294 — label-prefixes only attach to the three loop forms; remove the prefix on if/switch/etc.
  • GS0295 — rename the inner label so the two are distinguishable, or accept the inner-wins semantics.

If-expression diagnostics (GS0276–GS0277)

if so that it can sit in value position (let x = if cond { a } else { b }). The diagnostics below guard the two binder rejection paths that are unique to the expression form; the branch-type-mismatch case reuses GS0263 (shared with the ternary).

CodeSeverityMessage
GS0276ErrorAn if-expression in value position must have an else branch so that all code paths produce a value.
GS0277ErrorA block in an if-expression value position must end with a value-producing expression.

Cause/fix examples:

  • GS0276let x = if cond { 1 } — the if has no else, so when cond is false there is no value to bind. Add a terminal else { … }, or use the statement form (if cond { x = 1 }). The same rule applies to chained else if shapes: every chain must end in a terminal else.
  • GS0277let x = if cond { } else { 1 } — the then-block is empty. Replace the empty block with { <expr> }, or fall through with an explicit value ({ 0 }). Also fires when the block's last statement is a non-expression form (for, while, etc.) and there is no trailing expression to lift out.
  • GS0263 also covers if-expression branches with no common result type (e.g. if cond { true } else { "no" }). Mirrors the ternary diagnostic since both forms share ComputeConditionalCommonType.

Null-coalescing compound assignment diagnostics (GS0298–GS0299)

The ??= null-coalescing compound assignment statement. The diagnostics below cover the two shapes the binder rejects up front.

CodeSeverityMessage
GS0298ErrorThe left-hand side of ??= must be of nullable type. The operator only fills the slot when the current value reads as nil, so a non-nullable target is a no-op (and almost always a programmer error).
GS0299ErrorThe left-hand side of ??= must be assignable: a variable, parameter, field, property, or indexer. Method-call results, parenthesized expressions, and literals are not accepted.

Cause/fix examples:

  • GS0298var s = "hi"; s ??= "x". Fix: declare the variable as string? if you intend to default a possibly-missing value; otherwise use a plain =. The compiler will not silently insert a no-op on a non-nullable target.
  • GS0299compute() ??= "v". Fix: store the call result in a variable first and ??= into the variable, or write the conditional store by hand. ??= requires an lvalue.
  • A read-only lvalue (let x string? = nil; x ??= "v") reports the existing GS0127 for parity with the simple-assignment path.

Null-conditional indexing diagnostics (GS0300–GS0301)

The a?[i] null-conditional indexing operator. The diagnostics below cover the two shapes the binder rejects or warns up front.

CodeSeverityMessage
GS0300WarningThe receiver of ?[] is non-nullable, so the null check is dead. Use [] instead.
GS0301ErrorNull-conditional indexing ?[] is not allowed on the left-hand side of an assignment. Use a plain [] after a nil-check, an if let binding, or the ??= compound assignment instead.

Cause/fix examples:

  • GS0300var a = []int32{1,2}; var x = a?[0]. Fix: the receiver type []int32 is non-nullable, so write a[0] directly. ?[] is intended for receivers whose static type permits nil.
  • GS0301dict?["k"] = 1. Fix: nullable receivers do not have an addressable indexed slot when the receiver is nil; check first (if dict != nil { dict["k"] = 1 }) or use a non-nullable local that you've already narrowed.

Switch-expression arm separator deprecation (GS0302)

-> the lambda operator and migrates switch-expression arms to use : as the pattern/value separator. The legacy -> arm form remains accepted for one release to ease migration, but every legacy arm produces a warning.

CodeSeverityMessage
GS0302Warning-> in a switch-expression arm is deprecated; use : instead (ADR-0074).

Cause/fix:

  • GS0302let label = switch x { case 0 -> "zero"; default -> "other" }. Fix: replace each -> between the pattern and the arm value with :, e.g. case 0: "zero"; default: "other". The behaviour is otherwise identical. A future release will remove the legacy form and turn it into a parse error.

Function-type clause func(...) deprecation (GS0303)

(T1, T2,...) -> R the canonical function-type clause spelling — the type spelling now matches the lambda expression form introduced in. The legacy func(...) R and async func(...) R type-clause spellings remain accepted for one release to ease migration, but every legacy occurrence produces a warning.

CodeSeverityMessage
GS0303Warningfunc(...) function-type clauses are deprecated; use (T) -> R instead (ADR-0075).

Cause/fix:

  • GS0303var f func(int32) int32 = (x int32) -> x + 1. Fix: rewrite the type clause as var f (int32) -> int32 = (x int32) -> x + 1. Async variant: async func(int32) int32async (int32) -> int32. The deprecation applies only to func in type-clause positions; function declarations (func name(...) R { … }), function literals (func(...) R { … } expressions), and delegate func(...) named-delegate declarations all keep func. A future release will remove the legacy type-clause spelling and turn it into a parse error.

Lambda binding type-inference diagnostics (GS0304)

Type inference for let / var bindings whose initializer is a lambda. When the lambda's parameters are fully typed, the binding's type is inferred to the lambda's (T1,...) -> R function type and the user does not need to repeat the function-type clause. If neither side resolves to a concrete type — the binding has no explicit type clause AND the lambda's parameter types are not spelled — the binder reports GS0304.

CodeSeverityMessage
GS0304ErrorCannot infer the type of <name> from a lambda with untyped parameters; supply a function-type clause on the binding or annotate the lambda parameters.

Cause/fix:

  • GS0304let f = (x) -> x + 1. Either side may carry the types. Spell the lambda parameters: let f = (x int32) -> x + 1, or spell the binding: let f (int32) -> int32 = (x) -> x + 1. Generic method calls that take a lambda (for example xs.Where(x -> x > 0)) still use the existing method-type-inference path and are unaffected.

:= short variable declaration removal (GS0305)

The Go-style := short variable declaration from the language. The lexer still tokenizes := so the parser can produce a targeted, span-accurate diagnostic with a context-sensitive migration suggestion instead of cascading parse errors. Every occurrence of := — at statement scope, in multi-target assignment, in for / await for range and ellipsis loops, in if / for simple-statement initialisers, and in select case bindings — emits GS0305.

IDSeverityMessage
GS0305Error':=' short variable declaration has been removed; use 'let' (immutable) or 'var' (mutable) instead (e.g. '<migration>') (ADR-0077).

Cause/fix:

  • GS0305x := 1. Use let x = 1 when the binding is never rebound, or var x = 1 when it is. For looping forms: for i := 0 ... 10for i in 0 ... 10, for v := range xsfor v in xs, for k, v := range dictfor k, v in dict, await for x := range seqawait for x in seq, case v := <-ch { … }case let v = <-ch { … }. The three-part for init slot accepts a var/let declaration, e.g. for var i = 0; i < n; i++ (previously written as `for i := 0;

Kotlin/Swift-style type-declaration head (GS0306–GS0313)

The legacy type Name <kind>... aggregate head and the record keyword. The aggregate keyword (class, struct, enum, interface) is the declaration keyword. These diagnostics catalogue the invalid combinations and the legacy migrations. See for the full grammar and rationale.

IDSeverityMessage
GS0306ErrorLegacy type Name <kind> aggregate declaration — drop type; the kind keyword is now the head (ADR-0078).
GS0307ErrorThe record keyword has been removed (ADR-0078); use data struct Name (value-typed) or data class Name (reference-typed).
GS0308Errorinline is only legal on struct declarations (ADR-0078).
GS0309Erroropen is only legal on class declarations (ADR-0078).
GS0310Errorsealed is only legal on class and interface declarations (ADR-0078).
GS0311Errordata and inline are mutually exclusive (ADR-0078).
GS0312Erroropen and sealed are mutually exclusive (ADR-0078).
GS0313WarningNon-exhaustive switch over a sealed-hierarchy base or discriminated-union enum (ADR-0078).

Cause/fix:

  • GS0306type Foo class { … }class Foo { … }. Same for struct, enum, interface. Type aliases (type Count = int32) and named delegates (type Greeter = delegate func(name string)) are unaffected.
  • GS0307record Point { x int32; y int32 }data struct Point(x int32, y int32) (preserves value semantics) or data class Point(x int32, y int32) if reference semantics are desired.
  • GS0308inline class Fooinline struct Foo. Inline classes do not exist; the wrapper must be a value type.
  • GS0309open struct Foo, open enum Foo, open interface Foo → drop open. Structs cannot be inherited from, enums and interfaces are open by default.
  • GS0310sealed struct Foo → drop sealed. sealed enum Foo → use a discriminated-union enum (enum Foo { … } with payload-bearing cases) or drop sealed.
  • GS0311data inline struct Foo → choose one (data struct for the record contract, inline struct for the newtype wrapper).
  • GS0312open sealed class Foo → choose one. open admits cross-package subclasses; sealed is the closed Kotlin hierarchy.
  • GS0313 — Add missing cases to the switch, or add a default arm. For sealed class Shape with subclasses Circle, Square, write switch s { case c is Circle: ... case sq is Square: ... }.

Owned-receiver method warning (GS0314)

Go-style receiver-clause methods are restricted to types this package does not own. Same-package owned-type instance methods should be declared inside the type body; the receiver-clause form is reserved for non-owned types (imported CLR types, BCL primitives, and types declared by referenced packages).

IDSeverityMessage
GS0314WarningReceiver-clause methods are reserved for types this package does not own; declare '<MethodName>' as a member of '<TypeName>' instead (ADR-0079).

Cause/fix:

  • GS0314func (p Point) Distance() int32 { ... } where Point is declared in the same package. Move the declaration into the class body (class Point { ... func Distance() int32 { ... } }) and drop the receiver clause. Cross-package and CLR receivers (func (sb StringBuilder) Reset() ...) are unaffected. Operator overloads (func (a Vector2) operator +(b Vector2) Vector2 { ... }) are exempt because operators have no in-body form today. Suppress per-project via <NoWarn>GS0314</NoWarn> if migration must be deferred — but note this is a one-release grace period; a future release may escalate to error.

Named-argument = separator deprecation (GS0315)

The legacy name = value named-argument spelling is deprecated. The canonical spelling is name: value. The = form remains accepted for .copy(field = value) sugar and attribute named arguments this release; a warning fires so existing source can be migrated before the = branch is removed in a later release.

IDSeverityMessage
GS0315WarningNamed argument '<name>' uses the deprecated '=' separator; use '<name>: value' instead (ADR-0080).

Cause/fix:

  • GS0315Foo(timeout = 30) — rewrite the named-argument separator as : (Foo(timeout: 30)). Migrate .copy(...) and attribute argument lists alongside ordinary call sites: p.copy(x = 10)p.copy(x: 10), @AttributeUsage(All, AllowMultiple = true)@AttributeUsage(All, AllowMultiple: true). Plain assignment expressions (x = 1), optional parameter defaults (func f(x int32 = 0)), and with-expression field initializers (p with { x = 10 }) parse on separate paths and are unaffected. Suppress per-project via <NoWarn>GS0315</NoWarn> if migration must be deferred — but note this is a one-release grace period; the = branch is removed in a later release.

null identifier "did you mean nil?" diagnostic (GS0273)

The contract for the C# spelling null used In a G# source where the canonical null literal is nil. null is not a keyword in G# — it parses as an ordinary identifier and resolves through normal symbol lookup. When the identifier null is used in a value-expression position and no symbol named null is in scope, the binder emits GS0273 and recovers by treating the identifier as nil so target-type contexts (e.g. let x string? = null, Foo(null) where Foo takes T?, or x == null) continue to typecheck without cascading errors.

IDSeverityMessage
GS0273Error'null' is not a literal in G#. Did you mean 'nil'?

Cause/fix:

  • GS0273let x string? = null, Foo(null) where Foo takes T?, x == null. Replace null with nil (let x string? = nil, Foo(nil), x == nil). The diagnostic is anchored at the null token. GS0273 does not fire when a symbol named null is in scope — let null = "hi"; let s = null and func null() int32 { return 42 }; let v = null() both resolve normally with no diagnostic. See for the full rule, scope, and recovery rationale.

Go-flavored concurrency requires import Gsharp.Extensions.Go (GS0316)

The per-file gate on the Go-flavored concurrency surface. The production concurrency surface is scope + async/await; the Go-flavored shapes (go, chan T, <- send, <- receive, select, close(ch), make(chan T[, cap])) remain available but are opt-in. The binder checks for import Gsharp.Extensions.Go in the current compilation unit (not the project) before binding any of the gated forms and emits GS0316 when the import is absent. The triggering form is named in the message so users see exactly what to add.

IDSeverityMessage
GS0316Error'<form>' is provided by 'Gsharp.Extensions.Go'. Add 'import Gsharp.Extensions.Go' or use 'scope' + 'async'/'await' instead (ADR-0082).

Cause/fix:

  • GS0316 — any use of go, chan (in a type clause or inside make), <- (send or receive), select, or close(ch) in a source file that does not contain import Gsharp.Extensions.Go. Add the import at the top of the file (right after the package declaration is canonical), or rewrite the code on the scope + async/await surface. The diagnostic is anchored at the offending keyword/operator (go, chan, <-, select, close); each make(chan T) site is reported once at its inner chan keyword. The gate is always opt-in: /noimplicitimports does not interact with it, and the implicit System import toggle has no effect on whether Gsharp.Extensions.Go is in scope. See for the full rule, recovery strategy, and packaging rationale.

Go-style built-ins require import Gsharp.Extensions.Go (GS0317)

The per-file gate from to the Go-style built-in functions len, cap, append, and delete. The binder checks for import Gsharp.Extensions.Go in the current compilation unit before resolving any of these identifiers as built-ins and emits GS0317 when the import is absent. The message names the offending built-in and, when there is a clean .NET-idiomatic replacement, names the replacement too — so users can fix the call site either by adding the import or by switching to the BCL equivalent.

IDSeverityMessage
GS0317Error'<name>' is provided by 'Gsharp.Extensions.Go'. Add 'import Gsharp.Extensions.Go' or call '<suggestion>' directly (ADR-0083).

<suggestion> is selected from the following table based on the built-in identifier and the bound type of its primary receiver:

Built-inReceiver<suggestion>
lenarray / slice / string.Length
lenmap.Count
deletemap.Remove(k)
appendsliceList[T].Add
capany— (import-only variant: "Add 'import Gsharp.Extensions.Go'.")

The diagnostic is anchored at the built-in identifier token. The close(ch) and make(chan T) shapes are part of the channel Cluster and keep firing GS0316 rather than GS0317 — the suggested fix is the same import, but the message frames the scope + async/await alternative for the channel surface. The two diagnostics share the same BinderContext.IsGoExtensionsImported predicate, so a single import Gsharp.Extensions.Go unlocks both clusters at once.

Recovery is identical to GS0316: the binder reports GS0317 and continues binding the call as if the import were present, so subsequent shape diagnostics (e.g. GS0117 for a wrong-typed argument) still surface in the same pass.

Cause/fix:

  • GS0317 — any call to len, cap, append, or delete in a source file that does not contain import Gsharp.Extensions.Go. Add the import at the top of the file (right after the package declaration is canonical), or switch to the .NET-idiomatic alternative named in the message: array.Length / slice.Length / string.Length for len on length-bearing values, map.Count for len on maps, map.Remove(k) for delete, and List[T].Add for The mutable-list shape of append. See for the full rule and the deconfliction note with GS0316.

Default-interface-method diagnostics (GS0318–GS0321)

Interfaces may now expose default-method bodies; classes that implement the interface inherit the default unless they declare their own override. The four diagnostics below cover the conflict, dropped-default, missing-implementer, and deferred-modifier cases.

IDSeverityDescription
GS0318ErrorClass '<C>' inherits conflicting default implementations of '<Name>' from interfaces '<IA>' and '<IB>'. Declare '<C>.<Name>' explicitly to disambiguate.
GS0319ErrorOverride targets default-interface method '<Name>' that was removed in interface '<I>'.
GS0320ErrorClass '<C>' does not implement interface method '<I>.<Name>' and the interface does not provide a default.
GS0321ErrorModifier '<modifier>' on interface method '<Name>' is not yet supported. ADR-0085 explicitly defers 'open', 'override', and 'sealed override' interface members.
GS0368ErrorInterface method '<Name>' has no body and must be terminated with ';' (ADR-0085); a bodyless 'func' uses ';' as its no-body marker, mirroring P/Invoke.

Note: as of the private modifier on an interface method is no longer deferred and no longer fires GS0321. See the "Private interface helper diagnostics" section below for the GS0334–GS0337 codes that govern private-helper visibility and override-clash detection. Interface static-virtual members no longer use a static modifier — they are declared inside a shared { … } block on the interface — so static is no longer recognised on interface methods at all (the old static func … shape now produces a generic parser error). GS0321 therefore only fires today for open, override, and sealed override on interface methods.

Default-interface methods (DIM) emit standard CLR DIM metadata: the interface's method table carries a .method virtual slot whose body lives on the interface TypeDef. Implementers inherit the default through normal virtual dispatch; an explicit override on the class replaces it. Cross-language consumers (C# / VB / F#) see the DIM as a regular C# 8+ default interface method.

The historical GS0186 diagnostic ("Interface method may not have a body.") is no longer emitted; default-interface methods. The slot is preserved for back-compat but the binder no longer fires it.

Cause/fix:

  • GS0318 — declare an explicit override on the class to pick which inherited default wins, or call the desired interface's default by qualifying the call site. The explicit-base call syntax (base<IFoo>.Method()) is deferred.
  • GS0319 — reserved for the version-skew scenario where a consumer's referenced library has been upgraded to drop a default. Restore the default or supply a class-level override.
  • GS0320 — provide a method body on the implementing class with the matching signature, or add a default body to the interface declaration.
  • GS0368 — terminate the body-less interface method (or abstract shared { … } static slot) with ;, the universal no-body marker for func declarations. A method with a { … } body takes no ;.
  • GS0321 — remove the deferred modifier. Static interface members, private helper methods, and sealed override are not supported in this release; instance-virtual default-interface methods are the only DIM shape supported in this release.

P/Invoke diagnostics (GS0322–GS0329)

G# accepts a function whose body is a single ; token as a P/Invoke declaration when the function is annotated with @DllImport("libname", ...). The compiler emits CLR PinvokeImpl metadata (ImplMap + ModuleRef) for these declarations; the runtime resolves the call at first invocation. The historical blanket-rejection at GS0211 has been retired.

IDSeverityDescription
GS0322Error@DllImport requires a non-empty library name as its first positional argument.
GS0323ErrorP/Invoke parameter or return type <type> is not in the supported marshalling table (ADR-0086 §2).
GS0324ErrorFunction <name> is annotated @DllImport but has a managed body; P/Invoke declarations must use a ; body.
GS0325ErrorFunction <name> has no body; only @DllImport-annotated functions may use a ; body marker.
GS0326Error@DllImport is not supported on this function shape (<reason>).
GS0327Error@DllImport CharSet value <value> is not recognised.
GS0328Error@DllImport CallingConvention value <value> is not recognised.
GS0329Error@DllImport EntryPoint must be a non-empty string.

The codes above also fire for the modern @LibraryImport attribute wherever they apply (@LibraryImport reuses the same library-name, body-shape, unsupported-type, and EntryPoint checks). CharSet (GS0327) and CallingConvention (GS0328) cannot fire under @LibraryImport because those knobs do not exist on the attribute — use StringMarshalling: (GS0343 / GS0344) and [UnmanagedCallConv] instead.

The supported v1 marshalling table is: every primitive integer (int8/16/32/64, uint8/16/32/64), nint/nuint, float32/float64, bool, char, string (governed by CharSet), single-element-typed *T byref-style pointers (*T where T is primitive), and slices of primitives. Anything else surfaces as GS0323.

Cause/fix:

  • GS0322 — supply the library name: @DllImport("libc").
  • GS0323 — change the parameter or return to a supported marshalling type; struct marshalling, function-pointer marshalling, and custom marshallers are not supported in this release.
  • GS0324 — drop the function body and replace it with ;, or remove the @DllImport annotation.
  • GS0325 — add @DllImport("libname") above the declaration, or replace the ; with a managed body { ... }.
  • GS0326 — make the function a plain top-level func: not async, not generic, no receiver, no ref return, no shared block. These shapes are not supported in this release.
  • GS0327 / GS0328 — use one of the documented enum members (e.g. CharSet.Ansi, CallingConvention.Cdecl).
  • GS0329EntryPoint must be a non-empty literal string; omit the argument to default to the G# function's identifier.

See for the worked example, the attribute-knob table (EntryPoint, CharSet, SetLastError, CallingConvention, ExactSpelling, PreserveSig, BestFitMapping, ThrowOnUnmappableChar), and the deferred-features list.

Static-virtual interface-member diagnostics (GS0330–GS0333, GS0396–GS0397)

See and its revision. The DIM family Lands in; interfaces with C# 11-style static-virtual members. Per, these members are declared inside a shared { … } block on the interface — the same shared { … } Block that hosts static members on classes and structs. A body-less func inside that block is an abstract static-virtual slot; a func carrying a body is a default static-virtual member. Implementers supply the static via their own shared { ... } block; generic methods can dispatch through T.M(...) and the call site resolves to the implementer's static method (constrained. !!T call <iface>::<method> at the CLR level — ECMA-335 II.15.4.2.4 and III.2.1).

IDSeverityDescription
GS0330ErrorOnly 'func' members are allowed inside the 'shared' block of interface '<Name>'; interface static state is not supported in this release (ADR-0089). Raised for an event member in any interface shared block. Interface static var/let/const state is supported on both non-generic and generic interfaces.
GS0331Error<Kind> '<C>' does not implement static-virtual interface method '<I>.<Name>', and the interface provides no default body (ADR-0089).
GS0332Error<Kind> '<C>' declares instance method '<Name>' but interface '<I>.<Name>' is static-virtual; declare it inside a 'shared { … }' block (ADR-0089).
GS0333ErrorType parameter '<T>' has no constraint that declares a static-virtual member '<Name>' (ADR-0089).
GS0396Retired. Default-bodied static-virtual interface properties (prop Name T { get { … } }) are now supported, so this diagnostic is no longer raised.
GS0397ErrorType '<C>' does not implement static-virtual interface property '<I>.<Name>' (<detail>) (ADR-0089). Not raised for a fully default-bodied static property (the interface supplies the body).

Static-virtual interface members emit the standard CLR shape: the interface's MethodDef carries Static | Virtual | Abstract | NewSlot (no body, RVA = 0) for the abstract case, or Static | Virtual | NewSlot (with a body) for the default case. The implementer declares the method as Static (no Virtual / NewSlot) and is paired to the interface slot via a MethodImpl row (ECMA-335 II.22.27).

Cause/fix:

  • GS0330func members, prop (static-virtual property) declarations, and var / let / const static state fields — on both non-generic and generic interfaces — may appear inside an interface's shared { … } block. The diagnostic now fires only for an event member. Move an event out of the shared block.
  • GS0331 — add the missing static override inside the implementer's shared { … } block: class Adder : IAdd { shared { func Add(a int32, b int32) int32 { return a + b } } }, or give the interface method a default body so implementers may omit it.
  • GS0332 — move the method into the implementer's shared { … } block. An instance method cannot satisfy a static-virtual slot because the CLR routes the call through the type, not through an instance receiver.
  • GS0333 — change the receiver to a type parameter whose constraint actually declares the slot. For example, func Sum[T IAdd](xs sequence[T]) T { … T.Add(a, b) … } requires T to be constrained by IAdd — the interface that declares the static-virtual Add.
  • GS0396 — retired by. A static-virtual interface property may now carry an accessor body (prop Name T { get { … } }), declaring a non-abstract default static slot; no diagnostic is raised.
  • GS0397 — add the missing static property inside the implementer's shared { … } block with a matching name, type, and accessor set: struct AppleData : IData { shared { prop Name string { get { return "apple" } } } }.

Private interface helper diagnostics (GS0334–GS0337)

The DIM family lands in; It with C# 8-style private helper methods inside an interface body. A private helper is part of the interface's own implementation — only sibling members of the same interface may call it. Implementers cannot see the helper and cannot supply an override; the helper is non-virtual and not part of the interface's v-table.

IDSeverityDescription
GS0334ErrorPrivate interface member '<I>.<Name>' is not accessible from this context; private helpers are visible only to sibling members of the same interface (ADR-0090).
GS0335ErrorPrivate interface method '<I>.<Name>' must declare a body; abstract private helpers are not allowed (ADR-0090).
GS0336Error<Kind> '<C>' declares method '<Name>' that clashes with private interface helper '<I>.<Name>'; private interface helpers are interface-internal and cannot be overridden by implementers (ADR-0090).
GS0337ErrorModifier 'private' on interface member '<Name>' of kind '<Kind>' is not supported by ADR-0090. The v1 surface accepts 'private' only on instance / static methods.

Private interface helpers emit the standard CLR shape: MethodAttributes.Private | HideBySig (instance), plus MethodAttributes.Static when combined with's static form. The helper is not stamped Virtual / NewSlot / Abstract and carries an IL body on the interface TypeDef. Sibling default bodies dispatch to the helper via implicit this (instance) or implicit static-self (static).

Cause/fix:

  • GS0334 — remove the call site outside the interface, or expose the helper functionality by adding a public default method on the interface that wraps it. Implementers cannot invoke private helpers because they were never part of the contract; the helper is an implementation detail.
  • GS0335 — supply a body for the helper: private func Helper(x int32) int32 { return x + 1 }. Abstract private helpers do not make sense — implementers cannot satisfy them.
  • GS0336 — rename the implementer's method, or fold the logic into a public method on the interface. The CLR slot the implementer was trying to override is private to the interface and not part of the public contract.
  • GS0337 — restrict private to method members. The v1 surface supports private only on methods.

Explicit-base interface call diagnostics (GS0338–GS0341)

The explicit-base call syntax base[IFoo].Method(args) for disambiguating default-interface-method (DIM) diamonds. The override may delegate to one — or both — of the inherited defaults rather than re-implement them. The emit shape is a non-virtual call instance R IFoo::Method(...) so the inherited body is invoked directly rather than re-dispatched through the v-table.

IDSeverityDescription
GS0338Error'base[<I>]' is not allowed here; the enclosing type does not implement '<I>'.
GS0339ErrorInterface '<I>' does not declare a member named '<Name>' reachable via 'base[<I>]'.
GS0340ErrorInterface member '<I>.<Name>' is abstract; there is no default implementation to delegate to via 'base[<I>]'.
GS0341ErrorInterface member '<I>.<Name>' is a private helper (ADR-0090) and is not reachable via 'base[<I>]'.

base[IFoo] may be used inside any instance member (public, private, override, or non-conflicting) of a class that implements IFoo. It is not a statement and never appears outside an instance-member body. Private interface helpers are interface-internal and never exposed through base[IFoo]; that boundary is enforced by GS0341 rather than the helper visibility diagnostic GS0334.

Cause/fix:

  • GS0338 — either add the interface to the enclosing type's implementation set (class C : IFoo { ... }) or remove the base[IFoo] call. A top-level function has no enclosing type and cannot use the syntax.
  • GS0339 — check the spelling, arity, or visibility of the member. base[IFoo] reaches only members declared on IFoo itself (not inherited from another interface and not on a base class).
  • GS0340 — the interface declares the slot but did not supply a default body. There is nothing to delegate to. Either supply a default body on the interface, or implement the body inline in the class.
  • GS0341 — private interface helpers are an internal interface Detail. They are not part of the contract that implementers see and cannot be invoked across the implementer / interface boundary, even via base[IFoo]. Add a public default on the interface that wraps the helper if you need to expose the functionality.

Base-class call diagnostics (GS0383–GS0385, GS0413)

G# can call the base class implementation of a virtual/overridable member non-virtually from within a derived type using base.Member(args) — the faithful mapping of C# base.M(...) — or the bracketed base[BaseClass].Member(args) form. Both emit ldarg.0 followed by a non-virtual call instance R BaseClass::Member(...), so the nearest base implementation runs without re-dispatching through the v-table (no infinite recursion when called from the override that shadows it). The bracketed selector names the immediate base class; the member is resolved by walking the base chain, so a grandparent's implementation is reached when the immediate base does not declare its own override.

The base class may also be an imported / BCL type. A G# class deriving from a CLR base (e.g. System.IO.Stream, System.IO.MemoryStream, or simply System.Object) can delegate to an inherited virtual member via base.Dispose(disposing), base.ToString(), base.Position, etc. The inherited member is resolved against the class's CLR base type (honoring protected/public accessibility and walking a user → user → BCL chain), and emits the same non-virtual call. A base call into an abstract BCL member that has no implementation to delegate to (e.g. base.Read(...) where System.IO.Stream.Read(byte[],int,int) is abstract) is rejected with GS0413, matching C#'s CS0205.

IDSeverityDescription
GS0383Error'base' is not valid here: '<T>' must be an instance member of a class that has a base class to use 'base.Member(...)'.
GS0384ErrorBase class '<Base>' does not declare an accessible method named '<Name>' to call via 'base'.
GS0385Error'base[<Type>]' is not valid: '<Type>' is not a base class of '<T>'. Use the immediate base class name, or the plain 'base.Member(...)' form.
GS0413ErrorCannot call the abstract base member '<Base>.<Name>' via 'base'; it has no base implementation to delegate to.

Cause/fix:

  • GS0383base.Member(...) is only valid inside an instance member of a class. It fires for top-level functions, shared statics, and structs (no base class). A class deriving only from System.Object (or any imported/BCL base) does have a base, so base.ToString() and other inherited members are reachable — a missing member there reports GS0384. Move the call into an instance member of a class, or call the member directly.
  • GS0384 — the named member does not exist on any base class (user or BCL). Check the spelling, arity, or accessibility of the member. base reaches only members inherited from a base class.
  • GS0385 — the type named in the brackets is not a base class of the enclosing type. Use the immediate base class name, or prefer the plain base.Member(...) form, which resolves the base chain automatically.
  • GS0413 — the inherited BCL member named is abstract (it declares a virtual slot with no body), so there is no base implementation to call. As in C#, override the member with a concrete body instead of delegating to base.

Abstract member diagnostics (GS0386–GS0388)

A no-body open func F() R; declared inside an open class is the canonical G# spelling of a C# abstract method: it declares a virtual slot with no implementation. A class that declares (or inherits without overriding) an abstract method is itself abstract — it is emitted with TypeAttributes.Abstract and cannot be instantiated. Concrete (non-open) subclasses must override every inherited abstract member; an open subclass may leave them abstract and remain abstract itself.

open class Shape {
open func Area() float64; // abstract member — no body, just ';'
}

class Circle(R float64) : Shape {
override func Area() float64 { return 3.14159 * R * R }
}

let s Shape = Circle(2.0) // OK — Circle is concrete
Console.WriteLine(s.Area().ToString()) // 12.566… via virtual dispatch
IDSeverityDescription
GS0386ErrorCannot create an instance of the abstract type '<T>'.
GS0387Error'<Derived>' does not implement inherited abstract member '<Base>.<Member>'.
GS0388ErrorAbstract method '<M>' must be declared 'open' inside an 'open class'; '<T>' is not open or the method omits 'open'.

Cause/fix:

  • GS0386 — an abstract class cannot be constructed (Shape() / new Shape()). Construct a concrete subclass that overrides every abstract member instead. Mirrors C# CS0144.
  • GS0387 — a concrete (non-open) class derives from an abstract base but does not override one of the inherited abstract members. Either provide an override func for the member, or declare the subclass open (it then stays abstract itself). Mirrors C# CS0534.
  • GS0388 — a no-body (abstract) method appeared where it is not permitted. An abstract member must be declared open and may only live inside an open class. Add the open modifier and/or make the enclosing class open, or give the method a { … } body. Mirrors C# CS0513/CS0500.

init() constraint construction diagnostic (GS0389)

For class / struct / init() constraints and reified generics, a type parameter that carries an init() default-constructor constraint ([T init()]) may be constructed inside the generic body with the call-like spelling T(). The construction lowers to a reified System.Activator.CreateInstance<T>(), which yields a real instance for both reference types with a public parameterless constructor and value types.

IDSeverityDescription
GS0389ErrorCannot construct '<T>()' because type parameter '<T>' has no 'init()' constraint; add an 'init()' constraint (e.g. '[<T> init()]') to allow construction.

Cause/fix:

  • GS0389 — the body constructs a type parameter (T()) that does not declare an init() constraint, so the compiler cannot guarantee an accessible parameterless constructor exists for every instantiation. Add an init() constraint to the type parameter (e.g. class Factory[T init()] or func make[T init()]()). Mirrors C# CS0304. Note that a type argument that cannot satisfy the init() constraint (e.g. a class whose only constructor takes parameters) is reported separately as GS0152 at the instantiation site.

and/or/not pattern combinator diagnostic (GS0390)

Switch patterns may be combined with the contextual keywords and, or, and not (precedence: not > and > or; parentheses override). A type pattern that introduces a binding variable (<ident> is T) is not allowed under an or or not combinator, because the variable would not be definitely assigned when the arm runs (mirrors C# CS8780).

IDSeverityDescription
GS0390ErrorA pattern variable ('<name>') may not be declared under an 'or' or 'not' pattern; it would not be definitely assigned. Use '_' instead.

Cause/fix:

  • GS0390 — a binding type pattern (d is Dog) appears under or or not. Replace the binding identifier with the discard _ (e.g. _ is Dog or _ is Cat) or restructure the pattern so the binding sits under and (or at the top level), where it is definitely assigned.

Interface base-clause diagnostic (GS0391)

An interface may extend one or more base interfaces via a : A, B clause (mirroring C# interface B : A). Every entry must resolve to an interface — a G# interface or an imported CLR interface.

IDSeverityMessage
GS0391ErrorInterface '<interfaceName>' cannot declare base type '<baseTypeName>'; an interface may only extend other interfaces.

Cause/fix:

  • GS0391 — an interface's base clause names a class or struct. Remove the offending entry; an interface may only extend other interfaces.

User-defined conversion operator diagnostics (GS0393–GS0395)

Conversion operators are declared with func operator implicit (x T) U or func operator explicit (x T) U and emit CLR op_Implicit/op_Explicit.

IDSeverityMessage
GS0393ErrorA user-defined '<implicit/explicit>' conversion operator must take exactly one by-value parameter (the source operand).
GS0394ErrorA user-defined conversion operator must convert to or from a user type declared in the same package, and its source and target types must differ.
GS0395ErrorDuplicate user-defined conversion operator: a conversion from '<source>' to '<target>' is already declared on this type.

Cause/fix:

  • GS0393 — the operator declared more or fewer than one parameter. Declare exactly one by-value parameter (the source operand type).
  • GS0394 — neither the source nor the target type is a struct owned by the current package, or the source and target types are the same. Make at least one side an owned struct and ensure the two types differ.
  • GS0395 — a conversion with the same source/target pair already exists. Remove the duplicate (a source/target pair may have only one conversion, implicit or explicit).

@LibraryImport P/Invoke diagnostics (GS0342–GS0344)

G# accepts the modern source-generator-shaped @LibraryImport(...) attribute on ;-bodied func declarations. The compiler emits an explicit managed marshalling stub (outer wrapper) that calls a hidden blittable inner P/Invoke, so the runtime never auto-marshals at the unmanaged boundary. The attribute reuses the same library-name, body-shape, unsupported-type, and EntryPoint checks as @DllImport (GS0322–GS0329); the codes below cover the surface that is unique to @LibraryImport.

IDSeverityDescription
GS0342ErrorFunction <name> is annotated with both @DllImport and @LibraryImport; choose one.
GS0343ErrorStringMarshalling value <value> is not a valid StringMarshalling member; use Utf8 or Utf16.
GS0344Error@LibraryImport function <name> has a string surface (parameter or return) and must specify StringMarshalling: StringMarshalling.Utf8 or StringMarshalling.Utf16.

Cause/fix:

  • GS0342 — pick exactly one P/Invoke attribute per declaration. @DllImport and @LibraryImport express the same intent through two different emit pipelines; mixing them is ambiguous.
  • GS0343 — only StringMarshalling.Utf8 and StringMarshalling.Utf16 are accepted in v1. Custom (and StringMarshallingCustomType) is reserved for future custom-marshaller support.
  • GS0344 — supply an explicit StringMarshalling argument whenever any string parameter or a string return is present. Unlike @DllImport, the modern attribute does not assume a default encoding.

string return types are supported: the inner P/Invoke returns the raw native pointer and the outer stub materializes the managed string via Marshal.PtrToStringUTF8/PtrToStringUni per StringMarshalling. The returned native buffer is treated as non-owning (e.g. getenv, whose result points into the process environ) and is never freed; a callee with caller-frees semantics should return nint and free explicitly. The retired GS0345 code (which used to reject a string return) is no longer emitted and is not reused.

Struct / class P/Invoke marshalling diagnostics (GS0346–GS0351)

G# accepts @StructLayout(LayoutKind.…) on struct and class declarations, and @FieldOffset(N) on the fields of an Explicit-layout type. Both attributes are CLR pseudo-custom attributes — the runtime reconstructs them at reflection time from the ClassLayout and FieldLayout metadata-table rows, so the emitter writes those rows directly and skips the normal CustomAttribute round-trip. The diagnostics below cover the surface unique to struct / class marshalling; existing P/Invoke type-check codes (GS0322–GS0329 for @DllImport, GS0342–GS0344 for @LibraryImport) continue to apply for the surrounding signature.

IDSeverityDescription
GS0346Error@StructLayout(LayoutKind.<value>) is not supported; v1 P/Invoke marshalling accepts only LayoutKind.Sequential and LayoutKind.Explicit.
GS0347ErrorField <field> of explicit-layout struct <type> is missing a @FieldOffset(N) annotation; every field of an Explicit-layout type must carry one.
GS0348Error@FieldOffset on field <field> of <type> is only valid inside an Explicit-layout type; declare @StructLayout(LayoutKind.Explicit) on the enclosing struct or drop the annotation.
GS0349ErrorType <type> is not blittable and cannot appear in a P/Invoke signature without per-field @MarshalAs (deferred); rewrite the type to use blittable fields only.
GS0350Error@FieldOffset(<value>) value is not a valid non-negative int32.
GS0351ErrorClass <type> cannot be used as the return type of a P/Invoke function; return a struct or nint instead.

Cause/fix:

  • GS0346LayoutKind.Auto is rejected because the CLR is free to reorder fields, which breaks the bit-for-bit ABI contract the native side relies on. Pick Sequential for "matches the C declaration order" or Explicit for "I'm describing a union or padded layout".
  • GS0347 — Explicit layout means every field's offset is your responsibility; an unannotated field would land at offset 0 by default and silently alias the first explicitly-placed field. Add the intended @FieldOffset(N).
  • GS0348@FieldOffset only has a defined meaning inside an Explicit-layout type. On a Sequential-layout type the CLR computes offsets from the declaration order and Pack setting; carrying the attribute would be misleading.
  • GS0349 — blittability is checked recursively: a type is blittable iff every field is a primitive integer / float, a pointer (*T), or a blittable nested struct. bool, char, string, decimal, slices, sequences, and unannotated classes are non-blittable in v1. Per-field [MarshalAs] is not supported in this release.
  • GS0350@FieldOffset accepts a non-negative int32 literal (typically 0, 4, 8, …); other forms (negative, non-integer, expression) are rejected.
  • GS0351 — classes can only be marshalled by reference across the P/Invoke boundary; returning a managed object reference from a native function requires a deallocator contract that v1 does not surface. Return a struct or pass an nint and reconstruct the object on the managed side.

P/Invoke ref / out / in parameter diagnostic (GS0352)

G# now accepts ref T, out T, and in T parameters on a @DllImport or @LibraryImport declaration, provided the pointee type T is blittable. The runtime marshals the byref slot as T* to the unmanaged callee, which is the canonical shape for libc APIs like time(time_t *), clock_gettime(int, struct timespec *), and pipe(int [2]).

IDSeverityDescription
GS0352Error'ref'/'out'/'in' parameter <name> requires a blittable pointee; <T> is not blittable. Use a blittable primitive (int8int64, nint/nuint, float32/float64), or a struct annotated with @StructLayout(LayoutKind.Sequential).

Cause/fix:

  • ref bool / ref char is rejected. The unmanaged width of BOOL is 4 bytes on Windows and 1 byte on POSIX; char is 1 byte natively but 2 in the CLR. There is no portable byref encoding without an explicit @MarshalAs. Declare the parameter as ref uint8 (POSIX) or ref int32 (Windows) and widen in user code.
  • ref string is rejected. Strings need an explicit CoTaskMem allocate-before / free-after round trip; the byref slot would carry ownership ambiguity. Use ref nint together with Marshal.StringToCoTaskMemUTF8 and Marshal.PtrToStringUTF8.
  • ref T? (nullable) is rejected. The Nullable<T> layout ({ T value; bool hasValue }) is not blittable; passing the address would expose the hasValue byte to the unmanaged side, which has no contract for it.
  • ref C for a class C is rejected. Classes already flow as Pointers when annotated with @StructLayout. Adding a ref-kind on top produces a double indirection (<TypeDef>**) that the runtime marshaller cannot handle. Drop the ref-kind on a class parameter.

When the pointee is a struct, blittability is checked by the same BlittableDetector used for the by-value struct path and the diagnostic falls through to GS0349 instead — the remediation is identical (add @StructLayout(LayoutKind.Sequential) and confirm every field is blittable).

The historical GS0326 ("ref/out/in parameter is not supported") path for ref-kind parameters is retired. GS0326 still fires for the remaining function-shape constraints (async / generic / instance / extension / shared / ref-return).

P/Invoke function-pointer marshalling diagnostics (GS0353 – GS0356)

G# now supports passing managed callbacks and raw unmanaged function pointers across the P/Invoke boundary via two complementary shapes:

  • Shape A — delegate types annotated with @UnmanagedFunctionPointer(CallingConvention.Cdecl). Pass an instance of the delegate as a parameter; the runtime synthesizes a stable C-ABI thunk and keeps the delegate alive for the duration of Marshal.GetFunctionPointerForDelegate + the inner native call.
  • Shape B — raw function pointers spelled unmanaged[Cdecl] (T1, T2, ...) -> R. Encoded as ELEMENT_TYPE_FNPTR in the metadata blob; the runtime value is an address-sized integer (interconvertible with nint).
IDSeverityDescription
GS0353ErrorDelegate-typed P/Invoke parameter <name> of type <T> requires the delegate declaration to be annotated with @UnmanagedFunctionPointer(CallingConvention.Cdecl) (or a matching calling convention).
GS0354ErrorUnknown calling convention <name> on an unmanaged function-pointer type clause. Use one of: Cdecl, Stdcall, Thiscall, Fastcall.
GS0355ErrorReturning a managed delegate <T> from a P/Invoke declaration is not supported. Declare the return as unmanaged[CC] (...) -> R (a raw function pointer) or nint and wrap manually with Marshal.GetDelegateForFunctionPointer.
GS0356ErrorRaw function-pointer type clause is missing its calling-convention slot. Expected `unmanaged[Cdecl

Cause/fix:

  • GS0353 — missing @UnmanagedFunctionPointer. A G# delegate passed to a native callback parameter is marshalled through a runtime-synthesized thunk that needs an explicit calling convention. Add @UnmanagedFunctionPointer(CallingConvention.Cdecl) on the type Name = delegate func(...) R declaration.
  • GS0354 — unknown calling convention. Only the four CLR-defined unmanaged conventions are accepted. Cdecl is the right choice for almost all libc-style APIs; pick Stdcall only for the legacy Win32 ABI.
  • GS0355 — delegate-typed return. The runtime cannot conjure a managed wrapper for an arbitrary native function pointer because it has no contract for who owns the pointer's lifetime. Switch the return to unmanaged[CC] (...) -> R for a raw FNPTR, or to nint if the caller will wrap manually.
  • GS0356 — missing [CC] slot. The unmanaged contextual keyword always requires an immediate [Convention] bracket list. This makes the calling convention syntactically explicit at every declaration site so the metadata FNPTR signature is unambiguous.

GC lifetime contract (Shape A): the CLR keeps the delegate rooted for the duration of Marshal.GetFunctionPointerForDelegate + the inner native call. The caller is responsible for holding an explicit reference to the delegate for as long as the native side may call back. The canonical pattern is to assign the delegate to a local or field and call GC.KeepAlive(<delegate>) at the end of the scope.

P/Invoke @MarshalAs parameter override diagnostics (GS0357 – GS0360)

G# now honours @MarshalAs(UnmanagedType.…) on a P/Invoke parameter (@DllImport or @LibraryImport), emitting a CLR FieldMarshal table row per ECMA-335 II.23.4 so the runtime marshaller picks up the explicit override at the unmanaged boundary. The v1 supported UnmanagedType set is: LPStr, LPWStr, LPUTF8Str, BStr, LPArray, SafeArray, I1, U1, I2, U2, I4, U4, I8, U8, Bool, VariantBool, SysInt, SysUInt, Struct, ByValTStr, ByValArray. Anything else (CustomMarshaler, IUnknown, IDispatch, FunctionPtr, Currency, LPStruct) is rejected.

IDSeverityDescription
GS0357Error@MarshalAs UnmanagedType <value> is not in the v1 supported set. Use one of: LPStr, LPWStr, LPUTF8Str, BStr, LPArray, SafeArray, I1, U1, I2, U2, I4, U4, I8, U8, Bool, VariantBool, SysInt, SysUInt, Struct, ByValTStr, ByValArray.
GS0358Error@MarshalAs(UnmanagedType.<X>) is not valid on parameter <name> of type <T>. The per-UnmanagedType type-compatibility table (ADR-0096 §3) defines which G# types each marshaller accepts.
GS0359Error@MarshalAs(UnmanagedType.<X>) on parameter <name> requires the <arg> named argument. ByValTStr and ByValArray require SizeConst:; LPArray requires SizeConst: and/or SizeParamIndex:.
GS0360Error@MarshalAs on parameter <name> is not supported: <reason>. Two reasons fire today — the enclosing function is not a P/Invoke declaration, or the parameter is a string on a @LibraryImport.

Cause/fix:

  • GS0357 — unsupported UnmanagedType. Pick a value from the v1 supported set above. CustomMarshaler and IUnknown-style COM interop are deliberately deferred; raw function pointers already Have first-class syntax (unmanaged[CC] (...) -> R,).
  • GS0358 — type mismatch. Each UnmanagedType only accepts a narrow set of G# parameter types — strings for LPStr / LPWStr / LPUTF8Str / BStr / ByValTStr; integers (or bool / char) for I1U8; slices for LPArray / SafeArray / ByValArray; struct values for Struct. Either change the parameter type to match the marshaller, or drop the @MarshalAs and let the default marshalling rule apply.
  • GS0359 — missing required knob. Inline / sized forms need a compile-time element count. ByValTStr(SizeConst: N), ByValArray(SizeConst: N), LPArray(SizeConst: N) or LPArray(SizeParamIndex: i).
  • GS0360 — rejected combination. @MarshalAs has no meaning on a managed (non-P/Invoke) function — the runtime never reads FieldMarshal rows for managed methods. On @LibraryImport string parameters, the function-wide StringMarshalling: knob is the only lever — @LibraryImport(StringMarshalling: StringMarshalling.Utf8) (or Utf16) replaces a per-parameter @MarshalAs(UnmanagedType.LPUTF8Str) / LPWStr.

Pseudo-custom attribute: @MarshalAs is encoded exclusively as a FieldMarshal table row + the HasFieldMarshal flag on the Param row. The emitter does not also write a CustomAttribute row for it — this matches C#'s [MarshalAs] treatment and keeps the metadata byte-for-byte interoperable with ildasm, ILSpy, and decompilers.

Type-parameter class / struct / init() constraint diagnostic (GS0361)

(the default-constructor flag constraint was renamed from new() to init() by). The bracket-position flag-style constraints ([T class], [T struct], [T init()], plus combinations like [T class init()] and [T IFoo class]) compose freely with each other and with the legacy single-slot any / comparable / sealed-interface bound — except for two combinations that are rejected as mutually exclusive:

CodeSeverityMessage
GS0361ErrorType parameter <T> carries the mutually exclusive constraints <first> and <second>. The two combinations that fire today are class struct (a type cannot simultaneously be a reference type and a value type) and struct init() (the init() flag is redundant because the CLR's NotNullableValueTypeConstraint already implies DefaultConstructorConstraint per ECMA-335 II.10.1.7).

Cause/fix:

  • class struct combo. Pick one. Reference-type-only callers want [T class]; value-type-only callers want [T struct]. If you really want "any type", drop both and use [T] (or [T any]).
  • struct init() combo. Drop the explicit init()struct already requires every type argument to expose a public parameterless constructor at the CLR level. The emitter sets both flag bits whenever it sees struct, so the explicit init() adds nothing.

Target-typed bare default literal diagnostic (GS0362)

. The bare default literal (without an accompanying (T) type clause) takes its type from the surrounding target-typed position: the initializer of let/var with an explicit type clause, the value of return when the enclosing function has a known return type, an argument to a parameter of known type, and a conditional branch typed by its sibling. When no target type is available, GS0362 fires.

CodeSeverityMessage
GS0362ErrorThe bare default literal can only be used where its type is known from context. Use default(T) to spell the default value of an explicit type.

Cause/fix:

  • var x = default with no type clause and no initializer-typed sibling. Either add a type clause (var x int32 = default) or use the typed form (var x = default(int32)).
  • Console.WriteLine(default) against an overloaded method. Pick the overload by writing default(T), where T matches the parameter type you want, or assign the value to a typed local first.
  • return default from a function whose return type cannot be inferred. Annotate the function's return type, or use return default(T) directly.

Variadic-parameter diagnostics (GS0363, GS0364, GS0365)

(...T parameters) and (variadic slot in anonymous Function-type clauses). The canonical G# spelling for a variadic parameter is name ...T (Go-style: the ellipsis sits between the parameter identifier and the element type); inside the body the parameter has type []T. A signature may declare at most one variadic parameter and it must be the last parameter (see GS0145 above). Variadic declarations are accepted on top-level func declarations and on anonymous function-type clauses of the shape (T1, ...T2) -> R; other declaration sites report GS0146 (see above).

CodeSeverityMessage
GS0363ErrorThe C# params keyword is not supported in G#. Use the canonical variadic spelling name ...T (Go-style); inside the function body the parameter has type []T.
GS0364ErrorA function signature may declare at most one variadic parameter.
GS0365ErrorA variadic parameter slot in an anonymous function-type clause must use the slice form []T; got <typeName>.

Cause/fix:

  • GS0363 — params keyword. Replace params values []T with values...T. The lowering and call-site behaviour are identical; this is purely a spelling decision ( §"Structural rules" explains why the alias was rejected).
  • GS0364 — multiple variadic parameters. Pick the one parameter that should accept the parameter pack and drop the ... from the others. The remaining variadic must be the last parameter (GS0145).
  • GS0365 — variadic slot in (...)-> R is not a slice. In an anonymous function-type clause the ... marker turns the parameter slot into a pack/passthrough call site, so the slot's element type must be a slice. Spell it (...[]T) -> R, not (...T) -> R. The body-side spelling on a real declaration (func f(values ...T)) is unchanged.

Caller-side semantics — the binder packs trailing positional arguments into a fresh []T array; if the caller supplies exactly one trailing []T argument (after generic substitution), it is forwarded unwrapped, preserving array identity. The emitted MethodDef carries [System.ParamArrayAttribute] on the variadic parameter so C# / F# / VB consumers see it as params T[].

Map type-clause spelling removal (GS0366)

. The legacy Go-flavored map type-clause spelling map[K]V (key inside the brackets, value outside) has been removed in v0.2. The canonical G# spelling is map[K,V] with both type arguments inside the brackets, separated by a comma — the same single-bracket / comma-separated shape every other multi-argument type clause already uses (Foo[T1, T2], Dictionary[K, V], func(P1, P2) R, (K, V) tuple). There is no deprecation window; the parser emits GS0366 and the program does not compile.

CodeSeverityMessage
GS0366ErrorThe map[K]V type-clause spelling has been removed; use map[{key},{value}] instead (ADR-0104).

Cause/fix:

  • Replace every type-clause occurrence of map[K]V with map[K,V]. The migration is purely syntactic — symbol identity, binding, lowering, and emit are unaffected, and the runtime backing type remains System.Collections.Generic.Dictionary<K, V>.
- var m = map[string]int32{"a": 1}
+ var m = map[string,int32]{"a": 1}

- func makeIndex() map[string]Person { … }
+ func makeIndex() map[string,Person] { … }

- func (self map[K]V) CountKeys() int32 { … }
+ func (self map[K,V]) CountKeys() int32 { … }

Map index/use sites are unchanged — only the type-clause spelling moves. m["a"], len(m), delete(m, k), and the map literal entry form {k: v, …} are all unaffected.

The parser still recognises the legacy shape long enough to emit a span-accurate diagnostic that quotes the exact replacement, so IDE quick-fixes can patch the whole construct in one edit. Mixed-form files produce one GS0366 per legacy occurrence with no cascade errors — the parser binds the recovered shape to the same MapTypeSymbol so downstream binding proceeds unchanged.