Skip to content

Commit 7063899

Browse files
authored
Do not use constrained call on a conditional access receiver known to be a reference type. (#23359)
Fixes #23351.
1 parent 88cb9ea commit 7063899

3 files changed

Lines changed: 217 additions & 1 deletion

File tree

src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7335,5 +7335,107 @@ .locals init (System.Guid? V_0,
73357335
IL_0036: ret
73367336
}");
73377337
}
7338+
7339+
[Fact]
7340+
[WorkItem(23351, "https://github.com/dotnet/roslyn/issues/23351")]
7341+
public void ConditionalAccessOffConstrainedTypeParameter_Property()
7342+
{
7343+
var source = @"
7344+
using System;
7345+
7346+
class Program
7347+
{
7348+
static void Main(string[] args)
7349+
{
7350+
var obj1 = new MyObject1 { MyDate = DateTime.Parse(""2017-11-13T14:25:00Z"") };
7351+
var obj2 = new MyObject2<MyObject1>(obj1);
7352+
7353+
System.Console.WriteLine(obj1.MyDate.Ticks);
7354+
System.Console.WriteLine(obj2.CurrentDate.Value.Ticks);
7355+
System.Console.WriteLine(new MyObject2<MyObject1>(null).CurrentDate.HasValue);
7356+
}
7357+
}
7358+
7359+
abstract class MyBaseObject1
7360+
{
7361+
public DateTime MyDate { get; set; }
7362+
}
7363+
7364+
class MyObject1 : MyBaseObject1
7365+
{ }
7366+
7367+
class MyObject2<MyObjectType> where MyObjectType : MyBaseObject1, new()
7368+
{
7369+
public MyObject2(MyObjectType obj)
7370+
{
7371+
m_CurrentObject1 = obj;
7372+
}
7373+
7374+
private MyObjectType m_CurrentObject1 = null;
7375+
public MyObjectType CurrentObject1 => m_CurrentObject1;
7376+
public DateTime? CurrentDate => CurrentObject1?.MyDate;
7377+
}
7378+
";
7379+
7380+
var expectedOutput =
7381+
@"
7382+
636461511000000000
7383+
636461511000000000
7384+
False
7385+
";
7386+
CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: expectedOutput);
7387+
CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: expectedOutput);
7388+
}
7389+
7390+
[Fact]
7391+
[WorkItem(23351, "https://github.com/dotnet/roslyn/issues/23351")]
7392+
public void ConditionalAccessOffConstrainedTypeParameter_Field()
7393+
{
7394+
var source = @"
7395+
using System;
7396+
7397+
class Program
7398+
{
7399+
static void Main(string[] args)
7400+
{
7401+
var obj1 = new MyObject1 { MyDate = DateTime.Parse(""2017-11-13T14:25:00Z"") };
7402+
var obj2 = new MyObject2<MyObject1>(obj1);
7403+
7404+
System.Console.WriteLine(obj1.MyDate.Ticks);
7405+
System.Console.WriteLine(obj2.CurrentDate.Value.Ticks);
7406+
System.Console.WriteLine(new MyObject2<MyObject1>(null).CurrentDate.HasValue);
7407+
}
7408+
}
7409+
7410+
abstract class MyBaseObject1
7411+
{
7412+
public DateTime MyDate;
7413+
}
7414+
7415+
class MyObject1 : MyBaseObject1
7416+
{ }
7417+
7418+
class MyObject2<MyObjectType> where MyObjectType : MyBaseObject1, new()
7419+
{
7420+
public MyObject2(MyObjectType obj)
7421+
{
7422+
m_CurrentObject1 = obj;
7423+
}
7424+
7425+
private MyObjectType m_CurrentObject1 = null;
7426+
public MyObjectType CurrentObject1 => m_CurrentObject1;
7427+
public DateTime? CurrentDate => CurrentObject1?.MyDate;
7428+
}
7429+
";
7430+
7431+
var expectedOutput =
7432+
@"
7433+
636461511000000000
7434+
636461511000000000
7435+
False
7436+
";
7437+
CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: expectedOutput);
7438+
CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: expectedOutput);
7439+
}
73387440
}
73397441
}

src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
10341034
' if the receiver is actually a value type it would need to be boxed.
10351035
' let .constrained sort this out.
10361036

1037-
callKind = If(receiverType.IsReferenceType AndAlso Not AllowedToTakeRef(receiver, AddressKind.ReadOnly),
1037+
Debug.Assert(Not receiverType.IsReferenceType OrElse receiver.Kind <> BoundKind.ComplexConditionalAccessReceiver)
1038+
callKind = If(receiverType.IsReferenceType AndAlso
1039+
(receiver.Kind = BoundKind.ConditionalAccessReceiverPlaceholder OrElse Not AllowedToTakeRef(receiver, AddressKind.ReadOnly)),
10381040
CallKind.CallVirt,
10391041
CallKind.ConstrainedCallVirt)
10401042

src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9553,5 +9553,117 @@ Test
95539553
]]>)
95549554
End Sub
95559555

9556+
<Fact()>
9557+
<WorkItem(23351, "https://github.com/dotnet/roslyn/issues/23351")>
9558+
Public Sub ConditionalAccessOffConstrainedTypeParameter_Property()
9559+
9560+
Dim compilationDef =
9561+
<compilation>
9562+
<file name="a.vb">
9563+
Module Module1
9564+
Sub Main()
9565+
Dim obj1 As New MyObject1 With {.MyDate = CDate("2017-11-13T14:25:00Z")}
9566+
Dim obj2 As New MyObject2(Of MyObject1)(obj1)
9567+
9568+
System.Console.WriteLine(obj1.MyDate.Ticks)
9569+
System.Console.WriteLine(obj2.CurrentDate.Value.Ticks)
9570+
System.Console.WriteLine(new MyObject2(Of MyObject1)(Nothing).CurrentDate.HasValue)
9571+
End Sub
9572+
End Module
9573+
9574+
Public MustInherit Class MyBaseObject1
9575+
Property MyDate As Date
9576+
End Class
9577+
9578+
Public Class MyObject1
9579+
Inherits MyBaseObject1
9580+
End Class
9581+
9582+
Public Class MyObject2(Of MyObjectType As {MyBaseObject1, New})
9583+
Public Sub New(obj As MyObjectType)
9584+
m_CurrentObject1 = obj
9585+
End Sub
9586+
9587+
Private m_CurrentObject1 As MyObjectType = Nothing
9588+
Public ReadOnly Property CurrentObject1 As MyObjectType
9589+
Get
9590+
Return m_CurrentObject1
9591+
End Get
9592+
End Property
9593+
Public ReadOnly Property CurrentDate As Date?
9594+
Get
9595+
Return CurrentObject1?.MyDate
9596+
End Get
9597+
End Property
9598+
End Class
9599+
</file>
9600+
</compilation>
9601+
9602+
Dim expectedOutput =
9603+
<![CDATA[
9604+
636461511000000000
9605+
636461511000000000
9606+
False
9607+
]]>
9608+
CompileAndVerify(compilationDef, options:=TestOptions.DebugExe, expectedOutput:=expectedOutput)
9609+
CompileAndVerify(compilationDef, options:=TestOptions.ReleaseExe, expectedOutput:=expectedOutput)
9610+
End Sub
9611+
9612+
<Fact()>
9613+
<WorkItem(23351, "https://github.com/dotnet/roslyn/issues/23351")>
9614+
Public Sub ConditionalAccessOffConstrainedTypeParameter_Field()
9615+
9616+
Dim compilationDef =
9617+
<compilation>
9618+
<file name="a.vb">
9619+
Module Module1
9620+
Sub Main()
9621+
Dim obj1 As New MyObject1 With {.MyDate = CDate("2017-11-13T14:25:00Z")}
9622+
Dim obj2 As New MyObject2(Of MyObject1)(obj1)
9623+
9624+
System.Console.WriteLine(obj1.MyDate.Ticks)
9625+
System.Console.WriteLine(obj2.CurrentDate.Value.Ticks)
9626+
System.Console.WriteLine(new MyObject2(Of MyObject1)(Nothing).CurrentDate.HasValue)
9627+
End Sub
9628+
End Module
9629+
9630+
Public MustInherit Class MyBaseObject1
9631+
Public MyDate As Date
9632+
End Class
9633+
9634+
Public Class MyObject1
9635+
Inherits MyBaseObject1
9636+
End Class
9637+
9638+
Public Class MyObject2(Of MyObjectType As {MyBaseObject1, New})
9639+
Public Sub New(obj As MyObjectType)
9640+
m_CurrentObject1 = obj
9641+
End Sub
9642+
9643+
Private m_CurrentObject1 As MyObjectType = Nothing
9644+
Public ReadOnly Property CurrentObject1 As MyObjectType
9645+
Get
9646+
Return m_CurrentObject1
9647+
End Get
9648+
End Property
9649+
Public ReadOnly Property CurrentDate As Date?
9650+
Get
9651+
Return CurrentObject1?.MyDate
9652+
End Get
9653+
End Property
9654+
End Class
9655+
</file>
9656+
</compilation>
9657+
9658+
Dim expectedOutput =
9659+
<![CDATA[
9660+
636461511000000000
9661+
636461511000000000
9662+
False
9663+
]]>
9664+
CompileAndVerify(compilationDef, options:=TestOptions.DebugExe, expectedOutput:=expectedOutput)
9665+
CompileAndVerify(compilationDef, options:=TestOptions.ReleaseExe, expectedOutput:=expectedOutput)
9666+
End Sub
9667+
95569668
End Class
95579669
End Namespace

0 commit comments

Comments
 (0)