Repository navigation
Description
What's wrong
Since #55 / PR #57, WriteFileHeader writes #nullable enable into every generated file, whatever the consuming project's language version is:
SourceGeneratorToolkit/SourceGeneratorToolkit/GeneratorBase.cs
Lines 141 to 156 in 8a5bbf1
| protected static void WriteFileHeader(CodeBlocker codeBlocker, string? copyright) | |
| { | |
| Ensure.NotNull(codeBlocker); | |
| if (!string.IsNullOrEmpty(copyright)) | |
| { | |
| foreach (string line in copyright!.Split(CopyrightLineBreaks, StringSplitOptions.None)) | |
| { | |
| codeBlocker.WriteLine(line.Length == 0 ? "//" : $"// {line}"); | |
| } | |
| } | |
| codeBlocker.WriteLine("// <auto-generated />"); | |
| codeBlocker.WriteLine("#nullable enable"); | |
| codeBlocker.NewLine(); | |
| } |
#nullable needs C# 8. A project on C# 7.3 now fails to build with:
error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
The error is reported at line 3 of every generated file. C# 7.3 is the default for netstandard2.0 and .NET Framework targets when LangVersion isn't set.
Failure scenario
- A generator built on the toolkit calls
WriteFileHeader(cb, copyright)and writes the rest of the file by hand, the way thePairGeneratorfixture does. It emits only C# 7.3-compatible code. - A consumer project targets
netstandard2.0(ornet48) and doesn't setLangVersion. - Before Enable nullable in every generated file's header [patch] #57 that output compiled. Since Enable nullable in every generated file's header [patch] #57 every generated file fails with CS8370, so the consumer's build is broken.
I reproduced this by running such a generator through CSharpGeneratorDriver with new CSharpParseOptions(LanguageVersion.CSharp7_3). The result was CS8370 at Things.g.cs(3,2).
WriteSourceFile output already needs C# 10, because CodeBlocker's SourceFileTemplate emits a file-scoped namespace. So the regression only hits the WriteFileHeader + hand-written-body path, which is exactly the path generator authors use when they need to support older consumers.
Suggested fix
Emit #nullable enable only when the consuming compilation's language version is 8 or later. For example, GeneratorBase.Initialize can combine context.ParseOptionsProvider into the pipeline and pass ((CSharpParseOptions)options).LanguageVersion through to WriteFileHeader / WriteSourceFile. That could be an overload, or a protected property set before Generate runs.
If supporting C# < 8 consumers is out of scope, document a minimum consumer language version in the README instead (the WriteFileHeader row, README.md:258). That way the break is a documented contract rather than a surprise.
Acceptance criteria
- A generator that uses
WriteFileHeader+ C# 7.3-compatible body compiles in a C# 7.3 consumer, with a test covering it inGeneratorHarness. - Files generated for C# 8+ consumers still carry
#nullable enable(Code written by WriteSourceFile has nullable disabled: everystring?it emits raises CS8669, and non-annotated members are null-oblivious to consumers #55 stays fixed).
Activity
matt-edmondson commentedon Nov 2, 2026
Triage
Category: Bug (regression)
Priority: High
Suggested area:
GeneratorBasefile-header emission, owned by the maintainerChecked against HEAD: confirmed.
GeneratorBase.WriteFileHeaderalways writes#nullable enable(GeneratorBase.cs:154). That line came in with #57, the fix for #55.Why High: this regression breaks the consumer's build, not only the generator's output. C# 7.3 is the default language version for
netstandard2.0and .NET Framework consumers whenLangVersionisn't set, and theWriteFileHeader+ hand-written-body path is exactly how authors support those older consumers.Duplicates: none. It is a regression of #55 / #57 (both closed). It is distinct from #42, which is about the Roslyn version floor rather than the consumer's language version.
Related work: not in progress. Open PR #43 (Roslyn compatibility floor) does not touch
GeneratorBase.Next step: read
LanguageVersionfromParseOptionsProviderinInitialize, and emit#nullable enableonly for C# 8 and later. Add a C# 7.3 consumer case toGeneratorHarness. If older consumers are deliberately unsupported, state the minimum version in the README'sWriteFileHeaderrow instead.Generated by Claude Code