Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,14 @@ dotnet run -c Release --project benchmarks/DotMaybe.Benchmarks -- --filter '*Cha
- **CodeQL** (workflow *CodeQL*): static analysis on pull requests, on `main` and weekly; findings are listed under
*Security > Code scanning*.

## Updating the .NET SDK (RC1 → RC2 → GA)
## Updating the .NET SDK

1. Bump `sdk.version` in `global.json` to the exact SDK version.
2. Read the C# release notes for changes to unions.
3. Run the compiler contract tests first. They are the ones that notice changes in union behavior.
4. Update test dependencies if needed.
4. Refresh the lock files (`dotnet restore dotMaybe.slnx --force-evaluate`): the SDK's implicit packages, such as
`Microsoft.NET.ILLink.Tasks`, follow its version.
5. Update test dependencies if needed.

## One-time repository setup

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ var number = answer.OrDefault(0);
var lazy = answer.OrDefault(() => ExpensiveFallback());
```

In generic code use `Match`: C# does not allow `maybe is T value` when `T` is a type parameter.
Pattern matching works in generic code too: `maybe is T value` reads the value when `T` is a type parameter.

### Transforming and chaining

Expand Down
4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"sdk": {
"version": "11.0.100-rc.3.26522.148",
"version": "11.0.100",
"rollForward": "latestFeature",
"allowPrerelease": true
"allowPrerelease": false
},
"test": {
"runner": "Microsoft.Testing.Platform"
Expand Down
1 change: 0 additions & 1 deletion src/DotMaybe/DotMaybe.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<LangVersion>preview</LangVersion>
<AssemblyName>DotMaybe</AssemblyName>
<RootNamespace>DotMaybe</RootNamespace>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
2 changes: 1 addition & 1 deletion src/DotMaybe/Maybe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ bool IUnionMembers.TryGetValue(out None value)
/// <paramref name="none"/> runs when there is none. Exactly one of them runs, exactly once.
/// </summary>
/// <remarks>
/// This is the way to read a value in generic code, where <c>maybe is T value</c> does not compile.
/// The expression form of <c>maybe switch { T value => ..., None => ... }</c>, convenient in lambdas and chains.
/// </remarks>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="some">Produces the result from the value.</param>
Expand Down
6 changes: 3 additions & 3 deletions src/DotMaybe/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
},
"Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[11.0.0-rc.3.26522.148, )",
"resolved": "11.0.0-rc.3.26522.148",
"contentHash": "SWnTMx96mhBr9LCOySJg1ETlEFFHVsPGdVT02JnYhtqk1+Vke1J7RU3VkKwEiErBr4FJ42Uu4k7GdOtkRuvs/Q=="
"requested": "[11.0.0, )",
"resolved": "11.0.0",
"contentHash": "gK2aq4XvChj5kvozpPHrkfKkr7zc5Z4xoTrJb4GPZzDEPMlCk0TX632bwY3LsWcX2UVcVRQBBGzsBGC2lq6YhA=="
},
"MinVer": {
"type": "Direct",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<!--
The contracts compile snippets with the very compiler this SDK builds with (sdk/<version>/Roslyn/bincore),
so bumping global.json (RC1 -> RC2 -> GA) re-checks every contract against the new compiler.
so bumping global.json re-checks every contract against the new compiler.
RoslynCoreAssembliesPath is set by the .NET SDK when it uses its own (Core) compiler, which is the default
for `dotnet build` / `dotnet test`.
-->
Expand Down
13 changes: 13 additions & 0 deletions tests/DotMaybe.CompilerContractTests/PatternMatchingContracts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ public static string Describe<T>(Maybe<T> maybe)
ContractAssert.CompilesCleanly(result);
}

[Fact]
public void A_type_parameter_pattern_declares_a_variable()
{
// The RC1 compiler rejected `T value` in generic code (CS8780), because T could itself be a union.
// The .NET 11 GA compiler (SDK 11.0.100) accepts it and matches the content, as for a concrete type.
var result = Snippet.Compile(Consumer.File("""
public static string Describe<T>(Maybe<T> maybe)
where T : notnull => maybe is T value ? $"some {value}" : "none";
"""));

ContractAssert.CompilesCleanly(result);
}

[Fact]
public void A_concrete_type_pattern_declares_a_variable()
{
Expand Down
6 changes: 3 additions & 3 deletions tests/DotMaybe.PropertyTests/Maybes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ namespace DotMaybe.PropertyTests;
/// </summary>
/// <remarks>
/// Building goes through the union conversions, which are never ambiguous in generic code
/// (e.g. for <c>Maybe&lt;Maybe&lt;int&gt;&gt;</c>). Reading goes through the union members, because C# 15 rejects
/// <c>maybe is T value</c> when <c>T</c> is a type parameter (CS8780, see the compiler contracts).
/// Tests on concrete types read values with pattern matching instead.
/// (e.g. for <c>Maybe&lt;Maybe&lt;int&gt;&gt;</c>). Reading goes through the union members. It predates the .NET 11
/// GA compiler, which accepts <c>maybe is T value</c> for a type parameter (see the compiler contracts); the RC1
/// compiler rejected it with CS8780. Tests on concrete types read values with pattern matching.
/// </remarks>
internal static class Maybes
{
Expand Down
Loading