Skip to content

C#: Make value types assignable to their Nullable<T> counterparts#7151

Merged
knutwannheden merged 2 commits intomainfrom
nullable-type-assignability
Mar 26, 2026
Merged

C#: Make value types assignable to their Nullable<T> counterparts#7151
knutwannheden merged 2 commits intomainfrom
nullable-type-assignability

Conversation

@knutwannheden
Copy link
Copy Markdown
Contributor

Motivation

In C#, a value type T is implicitly convertible to Nullable<T> (T?). The TypeUtils.IsAssignableTo check did not account for this — IsAssignableTo(int, int?) returned false. This matters for C# recipes that need to reason about nullable assignability, such as the ThrowIfGreaterThan family of recipes where ThrowIfGreaterThan<T> has a where T : IComparable<T> constraint that Nullable<T> doesn't satisfy.

Examples

// These now return true:
TypeUtils.IsAssignableTo(intType, nullableIntType)       // int → int?
TypeUtils.IsAssignableTo(dateTimeType, nullableDateType)  // DateTime → DateTime?
TypeUtils.IsAssignableTo(nullableIntType, nullableIntType) // int? → int?

// These correctly return false:
TypeUtils.IsAssignableTo(intType, nullableDoubleType)     // int → double? (type mismatch)

Summary

  • Handle Nullable<T> as a special case in IsAssignableTo(JavaType?, JavaType?) — when the target is Parameterized(System.Nullable, [T]), unwrap and check if the source is assignable to T
  • Also handle Nullable<T>Nullable<T> by unwrapping both sides
  • Added 5 unit tests covering primitive, class, struct, mismatch, and self-assignment scenarios

Test plan

  • All 60 TypeUtilsTests pass (including 5 new nullable tests)
  • Existing tests unaffected (no behavioral change for non-nullable types)

In C#, a value type T is implicitly convertible to Nullable<T>. The
TypeUtils.IsAssignableTo check did not account for this, returning false
when checking e.g. int against int?. This caused recipe authors to lack
a reliable way to reason about nullable assignability.
Verify that int? is mapped as Parameterized(System.Nullable, [Int]),
while string? and object? (nullable reference types) are mapped as
plain Class types without Nullable wrapping, matching Roslyn semantics.
@knutwannheden knutwannheden force-pushed the nullable-type-assignability branch from 6471721 to 4c88387 Compare March 26, 2026 08:32
@knutwannheden knutwannheden changed the title C#: Make value types assignable to their Nullable<T> counterparts C#: Make value types assignable to their Nullable<T> counterparts Mar 26, 2026
@knutwannheden knutwannheden merged commit 38ab9f5 into main Mar 26, 2026
1 check passed
@knutwannheden knutwannheden deleted the nullable-type-assignability branch March 26, 2026 08:37
@github-project-automation github-project-automation bot moved this from In Progress to Done in OpenRewrite Mar 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant