提交 2b545038 编写于 作者: V vsadov

Nullable nontrivial constructor should propagate state of the argument to Value.

```cs
S? x = <expr of Type S>;  // works already
S? x = new Nullable<S>(<expr of Type S>);  // means the same as above and should work the same.
```

Fixes:#32626
上级 d99071e1
......@@ -1423,10 +1423,25 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre
}
}
}
else if (type.IsNullableType() && isDefaultValueTypeConstructor)
else if (type.IsNullableType())
{
// a nullable value type created with its default constructor is by definition null
resultState = NullableFlowState.MaybeNull;
if (isDefaultValueTypeConstructor)
{
// a nullable value type created with its default constructor is by definition null
resultState = NullableFlowState.MaybeNull;
}
else
{
// if we deal with one-parameter ctor that takes underlying, then Value state is inferred from the argument.
if (constructor.ParameterCount == 1)
{
var parameterType = constructor.ParameterTypes[0];
if (AreNullableAndUnderlyingTypes(type, parameterType.TypeSymbol, out TypeSymbolWithAnnotations underlyingType))
{
TrackNullableStateWhenWrappingUnderlying(node, arguments[0], type, underlyingType);
}
}
}
}
}
......@@ -3656,13 +3671,18 @@ private void TrackNullableStateIfNullableConversion(BoundConversion node)
if (AreNullableAndUnderlyingTypes(convertedType, operandType, out TypeSymbolWithAnnotations underlyingType))
{
// Conversion of T to Nullable<T> is equivalent to new Nullable<T>(t).
int valueSlot = MakeSlot(operand);
if (valueSlot > 0)
{
int containingSlot = GetOrCreateObjectCreationPlaceholderSlot(node);
Debug.Assert(containingSlot > 0);
TrackNullableStateOfNullableValue(containingSlot, convertedType, operand, underlyingType.ToTypeWithState(), valueSlot);
}
TrackNullableStateWhenWrappingUnderlying(node, operand, convertedType, underlyingType);
}
}
private void TrackNullableStateWhenWrappingUnderlying(BoundExpression node, BoundExpression operand, TypeSymbol convertedType, TypeSymbolWithAnnotations underlyingType)
{
int valueSlot = MakeSlot(operand);
if (valueSlot > 0)
{
int containingSlot = GetOrCreateObjectCreationPlaceholderSlot(node);
Debug.Assert(containingSlot > 0);
TrackNullableStateOfNullableValue(containingSlot, convertedType, operand, underlyingType.ToTypeWithState(), valueSlot);
}
}
......
......@@ -77901,6 +77901,54 @@ static void F(bool? i, bool b)
Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "(bool)(!i)").WithLocation(23, 13));
}
[WorkItem(32626, "https://github.com/dotnet/roslyn/issues/32626")]
[Fact]
public void NullableCtor()
{
var source =
@"
#nullable enable
using System;
struct S
{
internal object? F;
}
class Program
{
static void Baseline()
{
S? x = new S();
x.Value.F.ToString(); // warning baseline
S? y = new S() { F = 2 };
y.Value.F.ToString(); // ok baseline
}
static void F()
{
S? x = new Nullable<S>(new S());
x.Value.F.ToString(); // warning
S? y = new Nullable<S>(new S() { F = 2 });
y.Value.F.ToString(); // ok
}
}
";
var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
comp.VerifyDiagnostics(
// (16,9): warning CS8602: Possible dereference of a null reference.
// x.Value.F.ToString(); // warning baseline
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x.Value.F").WithLocation(16, 9),
// (25,9): warning CS8602: Possible dereference of a null reference.
// x.Value.F.ToString(); // warning
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x.Value.F").WithLocation(25, 9)
);
}
[Fact]
public void NullableT_AlwaysTrueOrFalse()
{
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册