Skip to content

Commit

Permalink
Disallow ref assignment to ternary or another ref assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
jjonescz committed Sep 12, 2024
1 parent 9941c1f commit dd208cc
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 28 deletions.
13 changes: 13 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,12 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin
break;

case BoundKind.ConditionalOperator:
if (RequiresRefAssignableVariable(valueKind))
{
Error(diagnostics, ErrorCode.ERR_RefLocalOrParamExpected, node);
return false;
}

var conditional = (BoundConditionalOperator)expr;

// byref conditional defers to its operands
Expand All @@ -918,6 +924,13 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin
}

case BoundKind.AssignmentOperator:
// Cannot ref-assign to a ref assignment.
if (RequiresRefAssignableVariable(valueKind))
{
Error(diagnostics, ErrorCode.ERR_RefLocalOrParamExpected, node);
return false;
}

var assignment = (BoundAssignmentOperator)expr;
return CheckSimpleAssignmentValueKind(node, assignment, valueKind, diagnostics);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53275,58 +53275,58 @@ static void F4(bool b, ref IOut<string?> x4, ref IOut<string> y4)
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y4").WithArguments("IOut<string>", "IOut<string?>").WithLocation(31, 27));
}

[ConditionalFact(typeof(NoUsedAssembliesValidation), Reason = "https://github.com/dotnet/roslyn/issues/75023")]
[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/73928")]
public void ConditionalOperator_RefAssignment()
public void ConditionalOperator_Ref_Assignment()
{
var source = """
#nullable enable
class C
{
static void M1(bool b, ref string? x1, ref string y1, ref string? x2, ref string y2)
{
(b ? ref x1 : ref y1) = ref x2;
(b ? ref x1 : ref y1) = ref y2;
(b ? ref x1 : ref y1) = x2;
(b ? ref x1 : ref y1) = y2;

(b ? ref x1! : ref y1) = ref x2;
(b ? ref x1! : ref y1) = ref y2;
(b ? ref x1! : ref y1) = x2;
(b ? ref x1! : ref y1) = y2;

(b ? ref y1 : ref x1) = ref x2;
(b ? ref y1 : ref x1) = ref y2;
(b ? ref y1 : ref x1) = x2;
(b ? ref y1 : ref x1) = y2;

(b ? ref y1 : ref x1!) = ref x2;
(b ? ref y1 : ref x1!) = ref y2;
(b ? ref y1 : ref x1!) = x2;
(b ? ref y1 : ref x1!) = y2;

(b ? ref x1! : ref y1) = ref x2!;
(b ? ref y1 : ref x1!) = ref x2!;
(b ? ref x1! : ref y1) = x2!;
(b ? ref y1 : ref x1!) = x2!;
}
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (6,18): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'.
// (b ? ref x1 : ref y1) = ref x2;
// (b ? ref x1 : ref y1) = x2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(6, 18),
// (6,37): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'.
// (b ? ref x1 : ref y1) = ref x2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("string?", "string").WithLocation(6, 37),
// (6,33): warning CS8601: Possible null reference assignment.
// (b ? ref x1 : ref y1) = x2;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "x2").WithLocation(6, 33),
// (7,18): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'.
// (b ? ref x1 : ref y1) = ref y2;
// (b ? ref x1 : ref y1) = y2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(7, 18),
// (9,38): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'.
// (b ? ref x1! : ref y1) = ref x2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("string?", "string").WithLocation(9, 38),
// (9,34): warning CS8601: Possible null reference assignment.
// (b ? ref x1! : ref y1) = x2;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "x2").WithLocation(9, 34),
// (12,27): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'.
// (b ? ref y1 : ref x1) = ref x2;
// (b ? ref y1 : ref x1) = x2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(12, 27),
// (12,37): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'.
// (b ? ref y1 : ref x1) = ref x2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("string?", "string").WithLocation(12, 37),
// (12,33): warning CS8601: Possible null reference assignment.
// (b ? ref y1 : ref x1) = x2;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "x2").WithLocation(12, 33),
// (13,27): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'.
// (b ? ref y1 : ref x1) = ref y2;
// (b ? ref y1 : ref x1) = y2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(13, 27),
// (15,38): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'.
// (b ? ref y1 : ref x1!) = ref x2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("string?", "string").WithLocation(15, 38));
// (15,34): warning CS8601: Possible null reference assignment.
// (b ? ref y1 : ref x1!) = x2;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "x2").WithLocation(15, 34));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,42 @@ ref int P
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P").WithLocation(8, 9));
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75023")]
public void RefReassignToRefTernary()
{
var source = """
class C
{
void M(bool b, ref int x, ref int y, ref int z)
{
(b ? ref x : ref y) = ref z;
}
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (5,10): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// (b ? ref x : ref y) = ref z;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "b ? ref x : ref y").WithLocation(5, 10));
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75023")]
public void RefReassignToRefAssignment()
{
var source = """
class C
{
void M(ref int x, ref int y, ref int z)
{
(x = ref y) = ref z;
}
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (5,10): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// (x = ref y) = ref z;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "x = ref y").WithLocation(5, 10));
}

[Fact, WorkItem(44153, "https://github.com/dotnet/roslyn/issues/44153")]
public void RefErrorProperty()
{
Expand Down

0 comments on commit dd208cc

Please sign in to comment.