Surprising semantic model and IOp behavior around nullable.
- Dominant language
- C#
- Stars
- 20.7k
- Forks
- 4.3k
- PR merge metrics
- PR metrics pending
Description
See following test for a template of code demonstrating surprising behavior:
```
[Fact, WorkItem(651624, "https://github.com/dotnet/roslyn/issues/60552")]
public void TestSemanticModelConversionFromNullableToNonNullable()
{
var src =
"""
#nullable enable
using System;
class C
{
public string Main(string? x)
{
return x;
}
public (int a, int b) Main((int, int) x)
{
return x;
}
public dynamic Main(object x)
{
return x;
}
}
""";
var comp = CreateCompilation(src);
var syntaxTree = comp.SyntaxTrees.Single();
var semanticModel = comp.GetSemanticModel(syntaxTree);
var root = syntaxTree.GetRoot();
var returnStatements = root.DescendantNodesAndSelf().OfType().ToArray();
var conversionInfo1 = semanticModel.GetConversion(returnStatements[0].Expression);
var conversionInfo2 = semanticModel.GetConversion(returnStatements[1].Expression);
var conversionInfo3 = semanticModel.GetConversion(returnStatements[2].Expression);
var typeInfo1 = semanticModel.GetTypeInfo(returnStatements[0].Expression);
var typeInfo2 = semanticModel.GetTypeInfo(returnStatements[1].Expression);
var typeInfo3 = semanticModel.GetTypeInfo(returnStatements[2].Expression);
}
```
Here we have 3 methods, which take in a value, and return that same value, all of which go through 'identity' conversions. And, intuitively, at runtime we're not going to actually do any actual conversions here.
However, for both tuples and dynamic, you at least get a TypeInfo telling you accurately what your converted type is. And the converted type is expectedly different from the starting type. In other words, the semantic model lets you know you're goin gfrom `(int,int)` to `(int a, int b)` or from `(object)` to `(dynamic)`.
However, for nullable it does not tell you this. This seems *odd* to me. Effectively, in the semantic model there is no way to say "the starting type is X, but it has changed to Y" despite X and Y being different types.
It's unclear to IDE team why nullable behaves this way. Other identity conversions do not, and the semantic model gives us the info we need to know that the lang is considering converting the types here. This *feels* like a bug. And it's a bug that definitely makes our lives harder as we cannot figure out when these changes are happening, despite them causing the compiler itself ot issue warnings.
This is highly relevant to us in terms of determining which casts we both need to add, or want to remove.
We would ask taht the semantic model indicate this information (and include in the iop tree) As it does for tehse other identity conversions with disparate types.
Contributor guide
Assessment
This issue has not been assessed yet.