diff --git a/design/knowledge/KB-060-metalama-2026-1-on-the-net-11-sdk.md b/design/knowledge/KB-060-metalama-2026-1-on-the-net-11-sdk.md new file mode 100644 index 0000000..95b8a77 --- /dev/null +++ b/design/knowledge/KB-060-metalama-2026-1-on-the-net-11-sdk.md @@ -0,0 +1,41 @@ +--- +verified: 2026-10-31 +pins: + - external .NET-SDK 11.0.100-rc.3.26522.148 + - external Metalama.Framework 2026.1.30 + - external Metalama.Framework 2027.0.5-preview +source: spikes/Sdk11Rc3Metalama, measured 2026-10-31 on macOS arm64 with the published CodoMetis.TypeKit and CodoMetis.TypeKit.Generators 2.3.1, against SDK 11.0.100-rc.3.26522.148 and 11.0.100-rc.1.26425.128, each alone in its .NET installation, and RC3 with SDK 10.0.403 beside it +turned-on: decision 120 (a net11.0 target in 2.4.0 on Metalama 2026.1, and Metalama 2027.0 in 2.5.0), and the RC3 part of issue 170 +test: none, a measurement of SDKs and compilers that CI does not install; the spike's run.sh and web-matrix.sh repeat it +--- + +# KB-060. Metalama 2026.1 weaves a `net11.0` project on SDK 11 RC3 at C# 14, and a web project fails when SDK 11 is the only SDK + +On SDK 11.0.100-rc.3, with the 2.3.1 packages (`Metalama.Framework` 2026.1.30, `Metalama.Compiler` 2026.1.20): + +- A `net11.0` console project with a value object builds, weaves and runs: `From`, `Parse` and a JSON round trip. + No warning. +- `#error version` names Metalama's compiler 2026.1.20 at language version 14.0. `Metalama.Framework` 2026.1.31 + (compiler 2026.1.21) is at 14.0 too. +- A `union` declared in the project fails with `CS0106`, `CS1001` and `CS8803`; a `switch` over a union returned by + a `net11.0`-only library fails with `CS8652` ("unions ... in Preview"); holding that union builds. Without Metalama + both compile. +- A direct `Metalama.Framework` 2027.0.5-preview reference beside the 2.3.1 packages: compiler 2027.0.5-preview at + 15.0, the value object woven, and both union cases build and run. +- One project on `net10.0;net11.0` with that 2027 reference and no `LangVersion`: `net10.0` compiles at 14.0 and + `net11.0` at 15.0. A union under `#if NET11_0_OR_GREATER`, or in a file removed from `net10.0` by a conditional + `Compile Remove`, builds on both targets, and the value object is generated and runs on both. With 2026.1 both + targets compile at 14.0 and either union fails on `net11.0`. + +The first four are the RC1 results of decision 120, unchanged; decision 120 did not measure the multi-targeted project. + +**A web project (`Microsoft.NET.Sdk.Web`) on Metalama 2026.1 fails with `LAMA0625` when SDK 11 is the only SDK in +its .NET installation**, on RC1 and on RC3, with 2026.1.31, and for a `net10.0` project as for a `net11.0` one. The SDK 11 Razor compiler needs Roslyn 5.11 (RC1) or +5.12 (RC3), Metalama 2026.1 bundles 5.9, and Metalama finds no older SDK in that installation to take a compatible +Razor compiler from ("Installed SDKs found: 11.0.100"). With SDK 10.0.403 in the same installation the build passes +with two `LAMA0617` warnings (the ASP.NET analyzers from SDK 10.0.401, the Razor compiler from SDK 10.0.403). +Metalama 2027.0.5-preview builds the web project with neither. Pinned to SDK 10.0.403, `net10.0`, both versions build +it with no warning. + +Not measured: the general availability SDK, Linux and Windows, an IDE, a Razor Pages or Blazor project, and any +2027 build without a Metalama license on the machine (this machine has a license entry for 2027.0). diff --git a/design/knowledge/README.md b/design/knowledge/README.md index e1f2250..d017164 100644 --- a/design/knowledge/README.md +++ b/design/knowledge/README.md @@ -88,3 +88,4 @@ test and later for the harness's `Baseline.Fact`. | [KB-055](KB-055-ericksonlopez-domainprimitives.md) | EricksonLopez.DomainPrimitives 3.0.0 is an attribute on a partial record struct, with a catalogue of ready-made types, re-validated on every read | EricksonLopez.DomainPrimitives 3.0.0 | prose | | [KB-057](KB-057-a-nullable-contract-has-an-element-type-and-reads-null-as-null.md) | A `Nullable` contract has `T` as its element type, and a JSON null read into it is null whatever `T`'s converter does | OpenApi 10.0.12, SDK 10.0.4xx | `KB057` | | [KB-058](KB-058-ef-orders-captured-values-in-sql-only-with-a-lambda.md) | EF orders captured values in SQL only when the chain takes a lambda: `values.Max()` runs in memory, `values.Max(v => v)` in SQL | EF Sqlite 10.0.12 | `KB058` | +| [KB-060](KB-060-metalama-2026-1-on-the-net-11-sdk.md) | Metalama 2026.1 weaves a `net11.0` project on SDK 11 RC3 at C# 14, and a web project fails with `LAMA0625` when SDK 11 is the only SDK | .NET SDK 11 RC3, Metalama 2026.1.30, 2027.0.5-preview | prose | diff --git a/spikes/Sdk11Rc3Metalama/App/App.csproj b/spikes/Sdk11Rc3Metalama/App/App.csproj new file mode 100644 index 0000000..db6ab95 --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/App/App.csproj @@ -0,0 +1,35 @@ + + + + Exe + net11.0 + enable + enable + false + + + $(DefineConstants);PROBE_VERSION + $(DefineConstants);DECLARE_UNION + $(DefineConstants);HOLD_UNION + $(DefineConstants);MATCH_UNION + $(DefineConstants);NO_GENERATORS + + + + + + + + + + + + diff --git a/spikes/Sdk11Rc3Metalama/App/Program.cs b/spikes/Sdk11Rc3Metalama/App/Program.cs new file mode 100644 index 0000000..841528d --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/App/Program.cs @@ -0,0 +1,54 @@ +#if PROBE_VERSION +#error version +#endif + +#if !NO_GENERATORS +using System.Text.Json; +using CodoMetis.TypeKit.ValueObjects; + +var id = OrderId.From(Guid.Parse("0b9f7d3a-5c1e-4f5a-9d8e-2a7c6b4e1f03")); +var parsed = OrderId.Parse("0b9f7d3a-5c1e-4f5a-9d8e-2a7c6b4e1f03", null); +var json = JsonSerializer.Serialize(id); +var read = JsonSerializer.Deserialize(json); +Console.WriteLine($"From: {id}"); +Console.WriteLine($"Parse equal: {parsed == id}"); +Console.WriteLine($"JSON: {json}, read back equal: {read == id}"); +#endif + +#if DECLARE_UNION +Shape shape = new Circle(1.5); +Console.WriteLine(shape switch +{ + Circle c => $"declared union: circle {c.Radius}", + Square s => $"declared union: square {s.Side}", +}); +#endif + +#if HOLD_UNION +var held = UnionLib.Pets.Adopt(); +Console.WriteLine($"held: {held}"); +#endif + +#if MATCH_UNION +Console.WriteLine(UnionLib.Pets.Adopt() switch +{ + UnionLib.Cat c => $"matched union: cat {c.Name}", + UnionLib.Dog d => $"matched union: dog {d.Name}", +}); +#endif + +#if NO_GENERATORS +Console.WriteLine("control: no TypeKit, no Metalama"); +#endif + +#if !NO_GENERATORS +public readonly partial record struct OrderId : IValue; +#endif + +#if DECLARE_UNION +public sealed record Circle(double Radius); + +public sealed record Square(double Side); + +public union Shape(Circle, Square); +#endif diff --git a/spikes/Sdk11Rc3Metalama/Directory.Build.props b/spikes/Sdk11Rc3Metalama/Directory.Build.props new file mode 100644 index 0000000..578e79b --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/Directory.Build.props @@ -0,0 +1,3 @@ + + + diff --git a/spikes/Sdk11Rc3Metalama/Multi/Multi.csproj b/spikes/Sdk11Rc3Metalama/Multi/Multi.csproj new file mode 100644 index 0000000..3b6501a --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/Multi/Multi.csproj @@ -0,0 +1,32 @@ + + + + Exe + net10.0;net11.0 + enable + enable + false + + + $(DefineConstants);PROBE_VERSION + $(DefineConstants);IF_UNION + $(DefineConstants);EXCLUDED_FILE + + + + + + + + + + + + + diff --git a/spikes/Sdk11Rc3Metalama/Multi/Net11Only/Shapes.cs b/spikes/Sdk11Rc3Metalama/Multi/Net11Only/Shapes.cs new file mode 100644 index 0000000..7060749 --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/Multi/Net11Only/Shapes.cs @@ -0,0 +1,14 @@ +public sealed record Circle(double Radius); + +public sealed record Square(double Side); + +public union Shape(Circle, Square); + +public static class Shapes +{ + public static string Describe(Shape shape) => shape switch + { + Circle c => $"circle {c.Radius}", + Square s => $"square {s.Side}", + }; +} diff --git a/spikes/Sdk11Rc3Metalama/Multi/Program.cs b/spikes/Sdk11Rc3Metalama/Multi/Program.cs new file mode 100644 index 0000000..2e2e7ca --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/Multi/Program.cs @@ -0,0 +1,34 @@ +#if PROBE_VERSION +#error version +#endif + +using System.Text.Json; +using CodoMetis.TypeKit.ValueObjects; + +var target = AppContext.TargetFrameworkName; +var id = OrderId.From(Guid.Parse("0b9f7d3a-5c1e-4f5a-9d8e-2a7c6b4e1f03")); +var json = JsonSerializer.Serialize(id); +Console.WriteLine($"{target}: From {id}, Parse equal {OrderId.Parse(id.ToString(), null) == id}, JSON {json} read back equal {JsonSerializer.Deserialize(json) == id}"); + +#if IF_UNION && NET11_0_OR_GREATER +Pet pet = new Cat("Tom"); +Console.WriteLine(pet switch +{ + Cat c => $"{target}: union under #if: cat {c.Name}", + Dog d => $"{target}: union under #if: dog {d.Name}", +}); +#endif + +#if EXCLUDED_FILE && NET11_0_OR_GREATER +Console.WriteLine($"{target}: union in a net11.0-only file: {Shapes.Describe(new Circle(1.5))}"); +#endif + +public readonly partial record struct OrderId : IValue; + +#if IF_UNION && NET11_0_OR_GREATER +public sealed record Cat(string Name); + +public sealed record Dog(string Name); + +public union Pet(Cat, Dog); +#endif diff --git a/spikes/Sdk11Rc3Metalama/README.md b/spikes/Sdk11Rc3Metalama/README.md new file mode 100644 index 0000000..6dba6c5 --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/README.md @@ -0,0 +1,160 @@ +# Spike: does Metalama 2026.1 still hold on the .NET 11 RC3 SDK? + +**Status: run 2026-10-31, answered.** The RC3 part of [#170](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/issues/170): +[decision 120](../../design/adr/0120-a-net11-0-target-and-documented-floor-raises-join-a-minor.md)'s Metalama +measurement, made on SDK 11.0.100-rc.1 on 2026-10-29, repeated on release candidate 3. Recorded as +[KB-060](../../design/knowledge/KB-060-metalama-2026-1-on-the-net-11-sdk.md). + +**Question.** With the published 2.3.1 packages (Metalama 2026.1) in a `net11.0` project on SDK 11.0.100-rc.3: + +1. does a value object with no union build, weave and run (`From`, `Parse`, JSON)? +2. which compiler, at which language version, does `#error version` name? +3. what does a `union` declared in the project give? +4. what does a `switch` over a union returned by a `net11.0`-only library give? +5. is LAMA0617 still reported, and is anything new? +6. what changes with a direct `Metalama.Framework` 2027 reference beside the 2.3.1 packages? +7. in one project targeting `net10.0;net11.0` with that 2027 reference and no `LangVersion`: which language version + does each target compile at, does C# 15 under `#if NET11_0_OR_GREATER` or in a file removed from `net10.0` build on + both targets, and is the value object generated on both? + +**Answer: every RC1 result holds on RC3.** Metalama 2026.1 builds, weaves and runs a `net11.0` value object, its +compiler (2026.1.20) runs the project at C# 14, a declared union fails with `CS0106`, `CS8803` and `CS1001`, and a +`switch` over a library's union with `CS8652`. With `Metalama.Framework` 2027.0.5-preview the compiler is 2027 at +C# 15 and both union rows build and run. The latest 2026.1 patch (2026.1.31, compiler 2026.1.21) is also at C# 14. +In one project on `net10.0;net11.0` with 2027.0.5-preview and no `LangVersion`, each target takes its SDK default: +`net10.0` compiles at 14.0 and `net11.0` at 15.0, with the same compiler. A union under `#if NET11_0_OR_GREATER`, or in +a file the project removes from `net10.0`, builds on both targets, and the value object is generated and runs on both. +On 2026.1 the same project compiles both targets at 14.0, and either union fails on `net11.0`. + +**One finding that the RC1 runs could not show, and that is not an RC3 change.** A web project +(`Microsoft.NET.Sdk.Web`, which loads the Razor source generator) on Metalama 2026.1 **fails** with `LAMA0625` +when SDK 11 is the only SDK in its .NET installation, on RC1 as on RC3, with 2026.1.31 too, and whether the +project targets `net11.0` or `net10.0`: a 2.x web application that moves its build to SDK 11 alone stops building. Metalama's compiler +bundles Roslyn 5.9; the SDK 11 Razor compiler needs 5.11 (RC1) or 5.12 (RC3), and Metalama looks for an older SDK to +take a compatible Razor compiler from. With SDK 10.0.403 installed beside it, that search succeeds and the build passes +with the `LAMA0617` warning decision 120 describes. Decision 120's runs had SDK 10.0.403 beside RC1, so they saw only +the warning. A console project reports neither. Metalama 2027.0.5-preview builds the web project in every cell. +Filed as [#275](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/issues/275). + +## The projects + +- `UnionLib`: a `net11.0` library with no Metalama that declares `public union Pet(Cat, Dog)` and returns one. +- `App`: a `net11.0` console project on `CodoMetis.TypeKit` and `CodoMetis.TypeKit.Generators` 2.3.1, with + `OrderId : IValue`. Properties switch the rows (`App.csproj` lists them): `ProbeVersion`, `DeclareUnion`, + `HoldUnion`, `MatchUnion`, `MetalamaFramework=` (a direct reference) and `NoGenerators` (the control). +- `Multi`: one project on `net10.0;net11.0`, no `LangVersion`, with the value object. `ProbeVersion`, + `MetalamaFramework=`, `IfUnion` (a union and a `switch` inside `#if NET11_0_OR_GREATER`) and `ExcludedFile` + (`Net11Only/Shapes.cs`, a union, under ``). +- `WebApp`: the same value object as a minimal-API route parameter, in `Microsoft.NET.Sdk.Web`. It suppresses + ASP0020, the documented false alarm on a route parameter + ([decision 12](../../design/adr/0012-asp0020-documented-suppressed.md)), which fires on SDK 10 as on SDK 11. + +`nuget.config` clears every source but nuget.org, and the runs restore into an empty `NUGET_PACKAGES` folder, so +the 2.3.1 packages are the published ones. Every build runs with `UseSharedCompilation=false` and +`-nodeReuse:false`, after `dotnet build-server shutdown` and with no compiler process left. + +## Running it + +The SDKs are installed side by side with Microsoft's script, leaving `/usr/local/share/dotnet` as it is: + +```bash +./dotnet-install.sh --version 11.0.100-rc.3.26522.148 --install-dir ~/.dotnet-sdk11-rc3 --no-path +./dotnet-install.sh --version 11.0.100-rc.3.26522.148 --install-dir ~/.dotnet-sdk11-rc3-sdk10 --no-path +./dotnet-install.sh --version 10.0.403 --install-dir ~/.dotnet-sdk11-rc3-sdk10 --no-path +./dotnet-install.sh --version 11.0.100-rc.1.26425.128 --install-dir ~/.dotnet-sdk11-rc1 --no-path +``` + +```bash +DOTNET=~/.dotnet-sdk11-rc3/dotnet DOTNET10=~/.dotnet-sdk11-rc3-sdk10/dotnet NUGET_PACKAGES= \ + spikes/Sdk11Rc3Metalama/run.sh +RC3_ALONE=~/.dotnet-sdk11-rc3/dotnet RC3_BESIDE=~/.dotnet-sdk11-rc3-sdk10/dotnet RC1_ALONE=~/.dotnet-sdk11-rc1/dotnet \ + NUGET_PACKAGES= spikes/Sdk11Rc3Metalama/web-matrix.sh +``` + +`run.sh` builds `App` or `Multi` once per row on RC3 alone and runs what builds (`Multi`'s `net10.0` output on the +`DOTNET10` host, since RC3 alone has no .NET 10 runtime); `web-matrix.sh` builds `WebApp` under each installation, +the SDK 10, RC1 and `net10.0` cells from a copy whose `global.json` pins that SDK. Each writes a log per row and `summary.txt`. + +## Evidence + +SDK 11.0.100-rc.3.26522.148 (runtime 11.0.0-rc.3.26522.148), macOS 27.0.1 on arm64. `CodoMetis.TypeKit` and +`CodoMetis.TypeKit.Generators` 2.3.1, which restore `Metalama.Framework` 2026.1.30 and `Metalama.Compiler` +2026.1.20; `Metalama.Framework` 2026.1.31 restores `Metalama.Compiler` 2026.1.21. + +### The rows, console project, RC3 the only SDK + +| Row | Build | Diagnostics | Run | RC1 (decision 120) | +|---|---|---|---|---| +| control: no TypeKit, no Metalama, a declared union and a library union matched | passes | none | `declared union: circle 1,5`, `matched union: cat Tom` | same | +| 1. value object, no union | passes | none | `From` prints the `Guid`, `Parse` equal, JSON `"0b9f7d3a-..."` read back equal | builds and weaves | +| 2. `#error version` | fails, as meant | `CS8304`: Compiler version '2026.1.20 (4a1b04c1...)'. Language version: 14.0 | | 2026.1.20 at 14.0 | +| 2b. `#error version`, `Metalama.Framework` 2026.1.31 | fails, as meant | `CS8304`: '2026.1.21 (c1b05ff9...)'. Language version: 14.0 | | not measured | +| 3. `public union Shape(Circle, Square)` in the project | fails | `CS0106` the modifier 'public' is not valid; `CS1001` identifier expected; `CS8803` top-level statements must precede namespace and type declarations | | `CS0106`, `CS8803`, `CS1001` | +| 4a. library union held in a `var` and printed | passes | none | `held: UnionLib.Pet` | builds | +| 4b. `switch` over the library union | fails | `CS8652`: The feature 'unions' is currently in Preview and *unsupported* | | `CS8652` | +| 5. warnings in rows 1 to 4 | | none: no `LAMA0617`, no other warning | | `LAMA0617` reported on a web project | +| 6. row 1, `Metalama.Framework` 2027.0.5-preview | passes | none | as row 1 | builds and weaves (2027.0.4-preview) | +| 6. row 2, 2027.0.5-preview | fails, as meant | `CS8304`: '2027.0.5-preview (dc7c9a1c...)'. Language version: 15.0 | | 2027.0.4-preview at 15.0 | +| 6. row 3, 2027.0.5-preview | passes | none | as row 1, then `declared union: circle 1,5` | builds and runs | +| 6. row 4b, 2027.0.5-preview | passes | none | as row 1, then `matched union: cat Tom` | not measured | + +### Row 7: one project on `net10.0;net11.0`, RC3 the only SDK + +Diagnostics carry their target in braces. The 2026.1 rows are the contrast, with no direct Metalama reference. + +| Row | Build | Diagnostics | Run | +|---|---|---|---| +| `#error version`, 2027.0.5-preview | fails, as meant | `CS8304`: '2027.0.5-preview (dc7c9a1c...)'. Language version: 14.0 {net10.0}; the same compiler at 15.0 {net11.0} | | +| value object, 2027.0.5-preview | passes | none | both targets: `From`, `Parse` equal, JSON read back equal | +| union and `switch` under `#if NET11_0_OR_GREATER`, 2027.0.5-preview | passes | none | both targets as above, then `union under #if: cat Tom` {net11.0} | +| union in `Net11Only/Shapes.cs`, removed on `net10.0`, 2027.0.5-preview | passes | none | both targets as above, then `union in a net11.0-only file: circle 1,5` {net11.0} | +| `#error version`, 2026.1 | fails, as meant | `CS8304`: '2026.1.20 (4a1b04c1...)'. Language version: 14.0, on both targets | | +| union under `#if`, 2026.1 | fails | `CS0106`, `CS1001`, `CS8803` {net11.0} | | +| union in the `net11.0`-only file, 2026.1 | fails | `CS0106`, `CS1001`, `CS8803` {net11.0} | | + +### Row 5 again: the web project, by installation + +| Installation | Metalama 2026.1 (2.3.1's) | `Metalama.Framework` 2026.1.31 | `Metalama.Framework` 2027.0.5-preview | +|---|---|---|---| +| RC3 alone | **fails**: `LAMA0625`, plus `LAMA0617` and `CS8034` | **fails**: the same | passes, no warning | +| RC3 with SDK 10.0.403 beside | passes: `LAMA0617` twice | not run | passes, no warning | +| RC3 alone, `net10.0` | **fails**: `LAMA0625` | not run | passes, no warning | +| RC1 alone | **fails**: `LAMA0625` | not run | passes, no warning | +| SDK 10.0.403, `net10.0` (today) | passes, no warning | not run | passes, no warning | + +The diagnostics, as reported on RC3 alone: + +- `error LAMA0625`: Analyzer 'Microsoft.CodeAnalysis.Razor.Compiler.dll' from .NET SDK 11.0.100-rc.3.26522.148 + requires Roslyn 5.12.0.0, newer than the Roslyn 5.9.0.0 bundled with Metalama Compiler. Metalama searched all .NET + SDKs installed on this machine for a compatible older version of 'Microsoft.CodeAnalysis.Razor.Compiler.dll', but + none qualifies. To fix, install a .NET SDK whose 'Microsoft.CodeAnalysis.Razor.Compiler.dll' references Roslyn + 5.9.0.0 or earlier and pin it in global.json, or upgrade Metalama Compiler to a version supporting Roslyn 5.12.0.0. + Installed SDKs found: 11.0.100. +- `warning LAMA0617`: Analyzer 'Microsoft.AspNetCore.App.Analyzers.dll' from .NET SDK (unknown) requires Roslyn + 5.11.0.0, newer than the Roslyn 5.9.0.0 bundled with Metalama Compiler. Metalama supplied a compatible version of + 'Microsoft.AspNetCore.App.Analyzers.dll' from .NET SDK 10.0.401 instead. +- `warning CS8034`: Unable to load Analyzer assembly + `metalama.compiler/2026.1.20/sdkAnalyzers/Microsoft.AspNetCore.Razor.Utilities.Shared.dll`: Could not load file or + assembly 'Microsoft.AspNetCore.Razor.Utilities.Shared, Version=10.4.0.0'. + +On RC1 alone the Razor compiler needs Roslyn 5.11.0.0 and `LAMA0625` is the only diagnostic. With SDK 10.0.403 +beside RC3, the two `LAMA0617` warnings name the ASP.NET analyzers taken from SDK 10.0.401 and the Razor compiler +taken from the SDK 10.0.403 beside it. + +`Metalama.Compiler` 2026.1.20 carries copies of the SDK's analyzers and generators in its `sdkAnalyzers` folder, +`Microsoft.CodeAnalysis.Razor.Compiler.dll` among them; the `CS8034` above is the load of one of them failing. Whether +that failure is what leaves `LAMA0625` without a fallback is not established here. + +"Installed SDKs found: 11.0.100" while this machine has SDK 10.0.403 in `/usr/local/share/dotnet` and 10.0.303 in +`~/.dotnet`: the search covers the .NET installation the build runs from, not the machine. + +## Limits + +- This machine has a Metalama licensing file with an entry for 2027.0, so the 2027 cells say nothing about a build + without a license. The file was not changed by these runs. #170 keeps the license-free CI job. +- macOS arm64 only, the command line only (no IDE), and console and minimal-API projects only. The general + availability SDK, Linux, Windows and a Razor Pages or Blazor project are not measured. +- An SDK 11 container image (`mcr.microsoft.com/dotnet/sdk:11.0`) holds one SDK, so it is the "RC3 alone" cell by + construction; it was not run. +- Not repeated here: the repository's own build on SDK 11, the woven `net10.0` assets compared, the analyzers on the + SDK 11 compiler, and the NU1605 measurement. They remain #170's. diff --git a/spikes/Sdk11Rc3Metalama/UnionLib/Pets.cs b/spikes/Sdk11Rc3Metalama/UnionLib/Pets.cs new file mode 100644 index 0000000..e338c6a --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/UnionLib/Pets.cs @@ -0,0 +1,12 @@ +namespace UnionLib; + +public sealed record Cat(string Name); + +public sealed record Dog(string Name); + +public union Pet(Cat, Dog); + +public static class Pets +{ + public static Pet Adopt() => new Cat("Tom"); +} diff --git a/spikes/Sdk11Rc3Metalama/UnionLib/UnionLib.csproj b/spikes/Sdk11Rc3Metalama/UnionLib/UnionLib.csproj new file mode 100644 index 0000000..907d78c --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/UnionLib/UnionLib.csproj @@ -0,0 +1,7 @@ + + + + net11.0 + enable + + diff --git a/spikes/Sdk11Rc3Metalama/WebApp/Program.cs b/spikes/Sdk11Rc3Metalama/WebApp/Program.cs new file mode 100644 index 0000000..da23d07 --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/WebApp/Program.cs @@ -0,0 +1,7 @@ +using CodoMetis.TypeKit.ValueObjects; + +var app = WebApplication.CreateBuilder(args).Build(); +app.MapGet("/orders/{id}", (OrderId id) => id); +app.Run(); + +public readonly partial record struct OrderId : IValue; diff --git a/spikes/Sdk11Rc3Metalama/WebApp/WebApp.csproj b/spikes/Sdk11Rc3Metalama/WebApp/WebApp.csproj new file mode 100644 index 0000000..6a4c097 --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/WebApp/WebApp.csproj @@ -0,0 +1,21 @@ + + + + net11.0 + enable + enable + false + + $(NoWarn);ASP0020 + + + + + + + + + diff --git a/spikes/Sdk11Rc3Metalama/global.json b/spikes/Sdk11Rc3Metalama/global.json new file mode 100644 index 0000000..9146b73 --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/global.json @@ -0,0 +1,11 @@ +{ + "//": [ + "The .NET 11 release candidate 3 SDK, exactly: the measurement is of this build and no other.", + "It is installed side by side (README, \"Running it\"), so the machine's own SDKs stay as they are." + ], + "sdk": { + "version": "11.0.100-rc.3.26522.148", + "rollForward": "disable", + "allowPrerelease": true + } +} diff --git a/spikes/Sdk11Rc3Metalama/nuget.config b/spikes/Sdk11Rc3Metalama/nuget.config new file mode 100644 index 0000000..613f1b9 --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/nuget.config @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/spikes/Sdk11Rc3Metalama/run.sh b/spikes/Sdk11Rc3Metalama/run.sh new file mode 100755 index 0000000..109e876 --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/run.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# Runs every row of the README's table on the RC3 SDK and writes one log per row to $1. +# Usage: DOTNET=~/.dotnet-sdk11-rc3/dotnet DOTNET10=~/.dotnet-sdk11-rc3-sdk10/dotnet \ +# NUGET_PACKAGES= ./run.sh +# DOTNET10 is a host with the .NET 10 runtime, to run Multi's net10.0 output; RC3 alone has none. +set -u +here="$(cd "$(dirname "$0")" && pwd)" +out="${1:?out-dir}" +dotnet="${DOTNET:?the RC3 dotnet}" +export DOTNET_ROOT="$(dirname "$dotnet")" +export DOTNET_CLI_TELEMETRY_OPTOUT=1 +export DOTNET_CLI_UI_LANGUAGE=en +mkdir -p "$out" +cd "$here" + +row() { + local name="$1" project="$2"; shift 2 + rm -rf App/bin App/obj UnionLib/bin UnionLib/obj Multi/bin Multi/obj WebApp/bin WebApp/obj + "$dotnet" build-server shutdown > /dev/null 2>&1 + pkill -f VBCSCompiler 2> /dev/null; pkill -f -i 'metalama' 2> /dev/null + "$dotnet" build "$project/$project.csproj" -p:UseSharedCompilation=false -nodeReuse:false "$@" > "$out/$name.log" 2>&1 + local code=$? + { + echo "== $name: $project $* -> build exit $code" + # A multi-targeted project's diagnostic keeps its target as {net10.0}; the project path is dropped. + grep -E '(error|warning) [A-Z]+[0-9]+: ' "$out/$name.log" \ + | sed -E 's/^.*((error|warning) [A-Z]+[0-9]+: )/\1/; s/ \[[^]]*::TargetFramework=([^]]+)\]$/ {\1}/; s/ \[[^]]*\]$//' \ + | sort -u + if [ $code -eq 0 ] && [ "$project" = App ]; then + echo "-- run" + "$dotnet" App/bin/Debug/net11.0/App.dll 2>&1 + fi + if [ $code -eq 0 ] && [ "$project" = Multi ]; then + echo "-- run" + DOTNET_ROOT="$(dirname "${DOTNET10:?a host with the .NET 10 runtime}")" "$DOTNET10" Multi/bin/Debug/net10.0/Multi.dll 2>&1 + "$dotnet" Multi/bin/Debug/net11.0/Multi.dll 2>&1 + fi + } | tee -a "$out/summary.txt" +} + +"$dotnet" --version | tee "$out/summary.txt" +row control-no-metalama App -p:NoGenerators=true -p:DeclareUnion=true -p:MatchUnion=true +row 1-plain App +row 2-version App -p:ProbeVersion=true +row 2b-version-2026.1.31 App -p:MetalamaFramework=2026.1.31 -p:ProbeVersion=true +row 3-declare-union App -p:DeclareUnion=true +row 4a-hold-library-union App -p:HoldUnion=true +row 4b-match-library-union App -p:MatchUnion=true +row 6-2027-plain App -p:MetalamaFramework=2027.0.5-preview +row 6-2027-version App -p:MetalamaFramework=2027.0.5-preview -p:ProbeVersion=true +row 6-2027-declare-union App -p:MetalamaFramework=2027.0.5-preview -p:DeclareUnion=true +row 6-2027-match-union App -p:MetalamaFramework=2027.0.5-preview -p:MatchUnion=true +row 7-multi-2027-version Multi -p:MetalamaFramework=2027.0.5-preview -p:ProbeVersion=true +row 7-multi-2027-plain Multi -p:MetalamaFramework=2027.0.5-preview +row 7-multi-2027-if-union Multi -p:MetalamaFramework=2027.0.5-preview -p:IfUnion=true +row 7-multi-2027-excluded-file Multi -p:MetalamaFramework=2027.0.5-preview -p:ExcludedFile=true +row 7-multi-2026-version Multi -p:ProbeVersion=true +row 7-multi-2026-if-union Multi -p:IfUnion=true +row 7-multi-2026-excluded-file Multi -p:ExcludedFile=true diff --git a/spikes/Sdk11Rc3Metalama/web-matrix.sh b/spikes/Sdk11Rc3Metalama/web-matrix.sh new file mode 100755 index 0000000..9db464a --- /dev/null +++ b/spikes/Sdk11Rc3Metalama/web-matrix.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# Builds WebApp, with Metalama 2026.1 and with 2027, under three .NET installations, one log per cell in $1: +# rc3-alone RC3 the only SDK in its dotnet root ($RC3_ALONE) +# rc3-beside RC3 with SDK 10.0.403 installed in the same dotnet root ($RC3_BESIDE) +# sdk10 SDK 10.0.403 from that root, net10.0 (today's consumer), in a copy pinned to it +# rc1-alone RC1 the only SDK in its dotnet root ($RC1_ALONE), in a copy pinned to it +# rc3-net10 RC3 alone again, building net10.0: today's 2.x consumer once it moves to SDK 11 +# Usage: RC3_ALONE=~/.dotnet-sdk11-rc3/dotnet RC3_BESIDE=~/.dotnet-sdk11-rc3-sdk10/dotnet \ +# RC1_ALONE=~/.dotnet-sdk11-rc1/dotnet NUGET_PACKAGES= ./web-matrix.sh +set -u +here="$(cd "$(dirname "$0")" && pwd)" +out="${1:?out-dir}" +mkdir -p "$out" +export DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_CLI_UI_LANGUAGE=en + +# The SDK 10 and RC1 cells: the same project, in a copy whose global.json pins that SDK. +pinned() { + local dir="$out/$1-copy" + rm -rf "$dir"; mkdir -p "$dir" + cp -R "$here/WebApp" "$here/Directory.Build.props" "$here/nuget.config" "$dir/" + printf '{ "sdk": { "version": "%s", "rollForward": "disable", "allowPrerelease": true } }\n' "$2" > "$dir/global.json" + echo "$dir" +} +copy="$(pinned sdk10 10.0.403)" +sed -i.bak 's|net11.0|net10.0|' "$copy/WebApp/WebApp.csproj" +rc1="$(pinned rc1 11.0.100-rc.1.26425.128)" +net10="$(pinned rc3-net10 11.0.100-rc.3.26522.148)" +sed -i.bak 's|net11.0|net10.0|' "$net10/WebApp/WebApp.csproj" + +cell() { + local name="$1" dotnet="$2" dir="$3"; shift 3 + export DOTNET_ROOT="$(dirname "$dotnet")" + rm -rf "$dir/WebApp/bin" "$dir/WebApp/obj" + "$dotnet" build-server shutdown > /dev/null 2>&1 + pkill -f VBCSCompiler 2> /dev/null; pkill -f -i 'metalama' 2> /dev/null + (cd "$dir" && "$dotnet" build WebApp/WebApp.csproj -p:UseSharedCompilation=false -nodeReuse:false "$@") > "$out/$name.log" 2>&1 + local code=$? + { + echo "== $name: $(cd "$dir" && "$dotnet" --version) in $DOTNET_ROOT $* -> build exit $code" + grep -oE '(error|warning) [A-Z]+[0-9]+: [^[]*' "$out/$name.log" | sort -u + } | tee -a "$out/summary.txt" +} + +: > "$out/summary.txt" +cell rc3-alone-2026 "${RC3_ALONE:?}" "$here" +cell rc3-alone-2027 "$RC3_ALONE" "$here" -p:MetalamaFramework=2027.0.5-preview +cell rc3-alone-2026.1.31 "$RC3_ALONE" "$here" -p:MetalamaFramework=2026.1.31 +cell rc3-beside-2026 "${RC3_BESIDE:?}" "$here" +cell rc3-beside-2027 "$RC3_BESIDE" "$here" -p:MetalamaFramework=2027.0.5-preview +cell sdk10-2026 "$RC3_BESIDE" "$copy" +cell sdk10-2027 "$RC3_BESIDE" "$copy" -p:MetalamaFramework=2027.0.5-preview +cell rc1-alone-2026 "${RC1_ALONE:?}" "$rc1" +cell rc1-alone-2027 "$RC1_ALONE" "$rc1" -p:MetalamaFramework=2027.0.5-preview +cell rc3-net10-2026 "$RC3_ALONE" "$net10" +cell rc3-net10-2027 "$RC3_ALONE" "$net10" -p:MetalamaFramework=2027.0.5-preview