Skip to content

Commit

Permalink
Reference conversion on this in init-only phase
Browse files Browse the repository at this point in the history
  • Loading branch information
jcouv committed Jan 13, 2021
1 parent 2aea4cf commit 0fd202e
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,17 @@ bool isAllowedInitOnlySet(BoundExpression receiver)
return true;
}

while (receiver is BoundConversion boundConversion)
{
var conversion = boundConversion.Conversion;
if (!(conversion.IsIdentity || conversion.IsReference))
{
return false;
}

receiver = boundConversion.Operand;
}

// bad: other.InitOnlyProperty = ...
if (!(receiver is BoundThisReference || receiver is BoundBaseReference))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1660,6 +1660,60 @@ public string RegularProperty2
);
}

[Fact, WorkItem(50053, "https://github.com/dotnet/roslyn/issues/50053")]
public void PrivatelyImplementingInitOnlyProperty_ReferenceConversion()
{
string source = @"
var x = new DerivedType() { SomethingElse = 42 };
System.Console.Write(x.SomethingElse);
public interface ISomething { int Property { get; init; } }
public record BaseType : ISomething { int ISomething.Property { get; init; } }
public record DerivedType : BaseType
{
public int SomethingElse
{
get => ((ISomething)this).Property;
init => ((ISomething)this).Property = value;
}
}
";

var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, options: TestOptions.DebugExe);
comp.VerifyDiagnostics();
// [ : BaseType::ISomething.set_Property] Cannot change initonly field outside its .ctor.
CompileAndVerify(comp, expectedOutput: "42", verify: Verification.Skipped);
}

[Fact, WorkItem(50053, "https://github.com/dotnet/roslyn/issues/50053")]
public void PrivatelyImplementingInitOnlyProperty_BoxingConversion()
{
string source = @"
var x = new Type() { SomethingElse = 42 };
public interface ISomething { int Property { get; init; } }
public struct Type : ISomething
{
int ISomething.Property { get; init; }
public int SomethingElse
{
get => throw null;
init => ((ISomething)this).Property = value;
}
}
";

var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, options: TestOptions.DebugExe);
comp.VerifyDiagnostics(
// (13,17): error CS8852: Init-only property or indexer 'ISomething.Property' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor.
// init => ((ISomething)this).Property = value;
Diagnostic(ErrorCode.ERR_AssignmentInitOnly, "((ISomething)this).Property").WithArguments("ISomething.Property").WithLocation(13, 17)
);
}

[Fact]
public void OverridingInitOnlyProperty()
{
Expand Down

0 comments on commit 0fd202e

Please sign in to comment.