Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 17, 2025

This PR adds a regression test to verify that Interlocked.Exchange correctly handles nullable reference types without requiring explicit type parameters.

Background

Previously, the compiler would incorrectly report CS8625 ("Cannot convert null literal to non-nullable reference type") when using Interlocked.Exchange with nullable custom types:

#nullable enable
using System.Threading;

class2? c = new class2();
var c1 = Interlocked.Exchange(ref c, null); // Previously: CS8625 error

However, the same code worked fine with object?:

object? o = new object();
var o1 = Interlocked.Exchange(ref o, null); // Always worked correctly

The issue has since been fixed (likely as part of improvements to null literal type inference for generic methods mentioned in #43536), but there was no test coverage to prevent regression.

Changes

This PR adds a comprehensive test InterlockedExchangeWithNullableTypes in MethodTypeInferenceTests.cs that:

  • Verifies Interlocked.Exchange works correctly with both object? and custom nullable types
  • Confirms the inferred types have the correct nullable annotations
  • Ensures no compilation errors occur
  • Uses raw string literals as per coding standards
  • Includes a WorkItem attribute linking to the original issue

The test validates that all three scenarios work correctly:

  1. Interlocked.Exchange(ref object?, null)
  2. Interlocked.Exchange(ref class2?, null) (the previously broken case)
  3. Interlocked.Exchange<class2?>(ref class2?, null) (explicit type parameter workaround)

This test will prevent any future regressions and can be used to close the original issue.

Original prompt

This section details on the original issue you should resolve

<issue_title>Interlocked.Exchange: compiler choses wrong Exchange with nullable types</issue_title>
<issue_description>This issue has been moved from a ticket on Developer Community.


[severity:It's more difficult to complete my work] [regression] [worked-in:.NET core 3.1]

#nullable enable
using System.Threading;

namespace InterlockedExchangeNullProblem {
  public class Class1 {
    public Class1() {
      object? o = new object();
      var o1 = Interlocked.Exchange(ref o, null); //1) ok
      class2? c = new class2();
      var c1 = Interlocked.Exchange(ref c, null); //2) error CS8625 Cannot convert null literal to non-nullable reference type.
      var c2 = Interlocked.Exchange<class2?>(ref c, null); //3) ok
    }
  }
  public class class2{}
}

The compiler works as expected in 1):

But in 2), the compiler creates wrongly the error message

CS8625 Cannot convert null literal to non-nullable reference type.

Furthermore, c1 gets the wrong type class2, instead class2? like the type of variable c.

Once <class2?> gets added to Interlocked.Exchange(), the compilation works properly again:

var c2 = Interlocked.Exchange<class2?>(ref c, null);

It really doesn't make sense when Interlocked.Exchange() works for <object?> but not for <class2?> !


Original Comments

Feedback Bot on 11/18/2020, 07:08 PM:

We have directed your feedback to the appropriate engineering team for further evaluation. The team will review the feedback and notify you about the next steps.


Original Solutions

(no solutions)</issue_description>

<agent_instructions>@copilot When i try the users code example out, i get no error. Indicating that this was an issue that has since been fixed. Can you create an appropriate compiler test here that demonstrates that there is no error. We can use that test to close out this issue. Please use raw string literals in the test, and have an appropriate WorkItem("url") attribute on it. </agent_instructions>

Comments on the Issue (you are @copilot in this section)

@RikkiGibson This may be an instance of #43536 (`null` fails to contribute its nullability to method type argument inference). Will need investigation. /cc @jcouv

Fixes #49525


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix Interlocked.Exchange handling of nullable types Add regression test for Interlocked.Exchange with nullable types Oct 17, 2025
Copilot AI requested a review from CyrusNajmabadi October 17, 2025 12:32
Copilot finished work on behalf of CyrusNajmabadi October 17, 2025 12:32
@CyrusNajmabadi CyrusNajmabadi force-pushed the copilot/fix-interlocked-exchange-nullability branch from 01afe51 to ef679f4 Compare October 20, 2025 15:41
@CyrusNajmabadi
Copy link
Member

@dotnet/roslyn-compiler ptal

@CyrusNajmabadi CyrusNajmabadi marked this pull request as ready for review October 23, 2025 14:22
@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner October 23, 2025 14:22
…ceTests.cs

Co-authored-by: Jan Jones <janjones@microsoft.com>
@CyrusNajmabadi CyrusNajmabadi enabled auto-merge (squash) October 23, 2025 14:26
@CyrusNajmabadi CyrusNajmabadi merged commit d1039fd into main Oct 23, 2025
23 of 24 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Oct 23, 2025
@CyrusNajmabadi CyrusNajmabadi deleted the copilot/fix-interlocked-exchange-nullability branch October 23, 2025 16:18
333fred added a commit to 333fred/roslyn that referenced this pull request Oct 24, 2025
* upstream/main: (332 commits)
  Cache lambdas in analyzer driver (dotnet#80759)
  Add information for NuGet package version 4.14 (dotnet#80870)
  Add missing search keywords to VB Advanced options page
  Fix IDE0031 false positive when preprocessor directives are used in if statements (dotnet#80878)
  Use core compiler on netfx hosts with toolset package (dotnet#80631)
  Make string concat assert more precise (dotnet#80619)
  Extensions: address some diagnostic quality issues (dotnet#80827)
  Add note on traversal order for bound nodes (dotnet#80872)
  Ensure that locals at the top level of a constructor have the same safe-context as parameters (dotnet#80807)
  Fix handling of SymbolDisplayCompilerInternalOptions.UseArityForGenericTypes option for non-native symbol implementations (dotnet#80826)
  Update src/Analyzers/CSharp/Tests/UseCollectionInitializer/UseCollectionInitializerTests.cs
  Add IsValidContainingStatement check to prevent collection initializers in using declarations
  Add back old DocumentSpan constructor (dotnet#80864)
  Add tests verifying pointer types in type parameters require unsafe context (dotnet#80776)
  Add regression test for Interlocked.Exchange with nullable types (dotnet#80796)
  Add regression test for ParseAttributeArgumentList with invalid input (fixes dotnet#8699) (dotnet#80705)
  Add regression test for compiler crash with syntax error in indexer declaration (dotnet#80772)
  Add runtime NullReferenceException validation to foreach null iteration tests (dotnet#80839)
  Update MicrosoftBuildTasksCoreVersionForMetrics to 17.11.48 (dotnet#80812)
  Mark CS4009 error as a "build only" error. (dotnet#80698)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Interlocked.Exchange: compiler choses wrong Exchange with nullable types

3 participants