未验证 提交 ee4b5bf6 编写于 作者: C Charles Stoner 提交者: GitHub

Analyze argument conversion for this argument of Deconstruct extension method (#39694)

上级 5b96642e
......@@ -1060,9 +1060,9 @@ private enum AssignmentKind
return false;
}
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
if (RequiresSafetyWarningWhenNullIntroduced(targetType))
{
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
if (conversion.Kind == ConversionKind.UnsetConversionKind)
conversion = this._conversions.ClassifyImplicitConversionFromType(valueType.Type, targetType.Type, ref useSiteDiagnostics);
......@@ -6025,7 +6025,7 @@ public override BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstruct
return VisitDeconstructionAssignmentOperator(node, rightResultOpt: null);
}
private BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node, TypeWithState? rightResultOpt = null)
private BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node, TypeWithState? rightResultOpt)
{
var previousDisableNullabilityAnalysis = _disableNullabilityAnalysis;
_disableNullabilityAnalysis = true;
......@@ -6124,7 +6124,8 @@ private void VisitDeconstructMethodArguments(ArrayBuilder<DeconstructionVariable
if (invocation.InvokedAsExtensionMethod)
{
// Check nullability for `this` parameter
CheckExtensionMethodThisNullability(right, conversion, deconstructMethod.Parameters[0], rightResult);
var argConversion = RemoveConversion(invocation.Arguments[0], includeExplicitConversions: false).conversion;
CheckExtensionMethodThisNullability(right, argConversion, deconstructMethod.Parameters[0], rightResult);
}
for (int i = 0; i < n; i++)
......@@ -6891,7 +6892,7 @@ public override void VisitForEachIterationVariables(BoundForEachStatement node)
var assignment = node.DeconstructionOpt.DeconstructionAssignment;
// Visit the assignment as a deconstruction with an explicit type
VisitDeconstructionAssignmentOperator(assignment, sourceState);
VisitDeconstructionAssignmentOperator(assignment, sourceState.HasNullType ? (TypeWithState?)null : sourceState);
// https://github.com/dotnet/roslyn/issues/35010: if the iteration variable is a tuple deconstruction, we need to put something in the tree
Visit(node.IterationVariableType);
......
......@@ -106328,7 +106328,6 @@ static void F(string x, object? y)
);
}
[Fact]
[WorkItem(35131, "https://github.com/dotnet/roslyn/issues/35131")]
[WorkItem(33017, "https://github.com/dotnet/roslyn/issues/33017")]
......@@ -106473,7 +106472,6 @@ static void F(object? x, object y)
);
}
[Fact]
[WorkItem(33019, "https://github.com/dotnet/roslyn/issues/33019")]
public void Deconstruction_37()
......@@ -106609,6 +106607,9 @@ static void F(Pair<object, object?>? p)
}";
var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
comp.VerifyDiagnostics(
// (12,34): warning CS8620: Argument of type 'Pair<object, object?>' cannot be used for parameter 'p' of type 'Pair<object?, object>' in 'void E.Deconstruct(Pair<object?, object>? p, out object x, out object? y)' due to differences in the nullability of reference types.
// (object? x, object? y) = p;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "p").WithArguments("Pair<object, object?>", "Pair<object?, object>", "p", "void E.Deconstruct(Pair<object?, object>? p, out object x, out object? y)").WithLocation(12, 34),
// (14,9): warning CS8602: Dereference of a possibly null reference.
// y.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y").WithLocation(14, 9));
......@@ -106744,7 +106745,6 @@ static void F(Pair<object?, Pair<object, object?>> p)
);
}
[Fact]
[WorkItem(33006, "https://github.com/dotnet/roslyn/issues/33006")]
public void Deconstruction_ExtensionMethod_06()
......@@ -106779,6 +106779,153 @@ static void F(string? x, object? y)
);
}
[Fact]
public void Deconstruction_ExtensionMethod_07()
{
var source =
@"class A<T, U>
{
}
class B : A<object, object?>
{
}
static class E
{
internal static void Deconstruct(this A<object?, object> a, out object? x, out object y) => throw null!;
}
class Program
{
static void F(B b)
{
(object? x, object? y) = b; // 1
x.ToString(); // 2
y.ToString();
}
}";
var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
comp.VerifyDiagnostics(
// (15,34): warning CS8620: Argument of type 'B' cannot be used for parameter 'a' of type 'A<object?, object>' in 'void E.Deconstruct(A<object?, object> a, out object? x, out object y)' due to differences in the nullability of reference types.
// (object? x, object? y) = b; // 1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "b").WithArguments("B", "A<object?, object>", "a", "void E.Deconstruct(A<object?, object> a, out object? x, out object y)").WithLocation(15, 34),
// (16,9): warning CS8602: Dereference of a possibly null reference.
// x.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(16, 9));
}
[Fact]
public void Deconstruction_ExtensionMethod_08()
{
var source =
@"#nullable enable
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
class Enumerable<T> : IAsyncEnumerable<T>
{
IAsyncEnumerator<T> IAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken token) => throw null!;
}
class Pair<T, U>
{
}
static class E
{
internal static void Deconstruct(this Pair<object?, object> p, out object? x, out object y) => throw null!;
}
static class Program
{
static async Task Main()
{
var e = new Enumerable<Pair<object, object?>>();
await foreach (var (x1, y1) in e) // 1
{
x1.ToString(); // 2
y1.ToString();
}
await foreach ((object x2, object? y2) in e) // 3, 4
{
x2.ToString(); // 5
y2.ToString();
}
}
}";
var comp = CreateCompilationWithTasksExtensions(new[] { s_IAsyncEnumerable, source });
comp.VerifyDiagnostics(
// (21,40): warning CS8620: Argument of type 'Pair<object, object?>' cannot be used for parameter 'p' of type 'Pair<object?, object>' in 'void E.Deconstruct(Pair<object?, object> p, out object? x, out object y)' due to differences in the nullability of reference types.
// await foreach (var (x1, y1) in e) // 1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "e").WithArguments("Pair<object, object?>", "Pair<object?, object>", "p", "void E.Deconstruct(Pair<object?, object> p, out object? x, out object y)").WithLocation(21, 40),
// (23,13): warning CS8602: Dereference of a possibly null reference.
// x1.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(23, 13),
// (26,25): warning CS8600: Converting null literal or possible null value to non-nullable type.
// await foreach ((object x2, object? y2) in e) // 3, 4
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "object x2").WithLocation(26, 25),
// (26,51): warning CS8620: Argument of type 'Pair<object, object?>' cannot be used for parameter 'p' of type 'Pair<object?, object>' in 'void E.Deconstruct(Pair<object?, object> p, out object? x, out object y)' due to differences in the nullability of reference types.
// await foreach ((object x2, object? y2) in e) // 3, 4
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "e").WithArguments("Pair<object, object?>", "Pair<object?, object>", "p", "void E.Deconstruct(Pair<object?, object> p, out object? x, out object y)").WithLocation(26, 51),
// (28,13): warning CS8602: Dereference of a possibly null reference.
// x2.ToString(); // 5
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x2").WithLocation(28, 13));
}
[Fact]
public void Deconstruction_ExtensionMethod_09()
{
var source =
@"#nullable enable
using System.Threading.Tasks;
class Enumerable<T>
{
public Enumerator<T> GetAsyncEnumerator() => new Enumerator<T>();
}
class Enumerator<T>
{
public T Current => default!;
public ValueTask<bool> MoveNextAsync() => default;
public ValueTask DisposeAsync() => default;
}
class Pair<T, U>
{
}
static class E
{
internal static void Deconstruct(this Pair<object?, object> p, out object? x, out object y) => throw null!;
}
static class Program
{
static async Task Main()
{
var e = new Enumerable<Pair<object, object?>>();
await foreach (var (x1, y1) in e) // 1
{
x1.ToString(); // 2
y1.ToString();
}
await foreach ((object x2, object? y2) in e) // 3, 4
{
x2.ToString(); // 5
y2.ToString();
}
}
}";
var comp = CreateCompilationWithTasksExtensions(source);
comp.VerifyDiagnostics(
// (25,40): warning CS8620: Argument of type 'Pair<object, object?>' cannot be used for parameter 'p' of type 'Pair<object?, object>' in 'void E.Deconstruct(Pair<object?, object> p, out object? x, out object y)' due to differences in the nullability of reference types.
// await foreach (var (x1, y1) in e) // 1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "e").WithArguments("Pair<object, object?>", "Pair<object?, object>", "p", "void E.Deconstruct(Pair<object?, object> p, out object? x, out object y)").WithLocation(25, 40),
// (27,13): warning CS8602: Dereference of a possibly null reference.
// x1.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(27, 13),
// (30,25): warning CS8600: Converting null literal or possible null value to non-nullable type.
// await foreach ((object x2, object? y2) in e) // 3, 4
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "object x2").WithLocation(30, 25),
// (30,51): warning CS8620: Argument of type 'Pair<object, object?>' cannot be used for parameter 'p' of type 'Pair<object?, object>' in 'void E.Deconstruct(Pair<object?, object> p, out object? x, out object y)' due to differences in the nullability of reference types.
// await foreach ((object x2, object? y2) in e) // 3, 4
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "e").WithArguments("Pair<object, object?>", "Pair<object?, object>", "p", "void E.Deconstruct(Pair<object?, object> p, out object? x, out object y)").WithLocation(30, 51),
// (32,13): warning CS8602: Dereference of a possibly null reference.
// x2.ToString(); // 5
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x2").WithLocation(32, 13));
}
[Fact]
[WorkItem(33006, "https://github.com/dotnet/roslyn/issues/33006")]
public void Deconstruction_ExtensionMethod_ConstraintWarning()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册