提交 c99ad715 编写于 作者: R Rikki Gibson 提交者: GitHub

Revert "Improve the code gen for a conditional access on a readonly unconstrained field (#35979)"

This reverts commit 6b22ff18.
上级 77728dcc
......@@ -405,43 +405,32 @@ private void EmitLoweredConditionalAccessExpression(BoundLoweredConditionalAcces
// if T happens to be a value type, it could be a target of mutating calls.
receiverTemp = EmitReceiverRef(receiver, AddressKind.Constrained);
if (receiverTemp is null)
{
// unconstrained case needs to handle case where T is actually a struct.
// such values are never nulls
// we will emit a check for such case, but the check is really a JIT-time
// constant since JIT will know if T is a struct or not.
// if ((object)default(T) != null)
// {
// goto whenNotNull
// }
// else
// {
// temp = receiverRef
// receiverRef = ref temp
// }
EmitDefaultValue(receiverType, true, receiver.Syntax);
EmitBox(receiverType, receiver.Syntax);
_builder.EmitBranch(ILOpCode.Brtrue, whenNotNullLabel);
EmitLoadIndirect(receiverType, receiver.Syntax);
cloneTemp = AllocateTemp(receiverType, receiver.Syntax);
_builder.EmitLocalStore(cloneTemp);
_builder.EmitLocalAddress(cloneTemp);
_builder.EmitLocalLoad(cloneTemp);
EmitBox(receiverType, receiver.Syntax);
// here we have loaded a ref to a temp and its boxed value { &T, O }
}
else
{
// we are calling the expression on a copy of the target anyway,
// so even if T is a struct, we don't need to make sure we call the expression on the original target.
_builder.EmitLocalLoad(receiverTemp);
EmitBox(receiverType, receiver.Syntax);
}
// unconstrained case needs to handle case where T is actually a struct.
// such values are never nulls
// we will emit a check for such case, but the check is really a JIT-time
// constant since JIT will know if T is a struct or not.
// if ((object)default(T) != null)
// {
// goto whenNotNull
// }
// else
// {
// temp = receiverRef
// receiverRef = ref temp
// }
EmitDefaultValue(receiverType, true, receiver.Syntax);
EmitBox(receiverType, receiver.Syntax);
_builder.EmitBranch(ILOpCode.Brtrue, whenNotNullLabel);
EmitLoadIndirect(receiverType, receiver.Syntax);
cloneTemp = AllocateTemp(receiverType, receiver.Syntax);
_builder.EmitLocalStore(cloneTemp);
_builder.EmitLocalAddress(cloneTemp);
_builder.EmitLocalLoad(cloneTemp);
EmitBox(receiver.Type, receiver.Syntax);
// here we have loaded a ref to a temp and its boxed value { &T, O }
}
else
{
......
......@@ -2763,287 +2763,5 @@ .maxstack 1
IL_0064: ret
}");
}
[Fact]
[WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")]
public void ConditionalAccessUnconstrainedTField()
{
var source = @"using System;
public class C<T>
{
public C(T t) => this.t = t;
public C(){}
private T t;
public void Print()
{
Console.WriteLine(t?.ToString());
Console.WriteLine(t);
}
}
public struct S
{
int a;
public override string ToString() => a++.ToString();
}
public static class Program
{
public static void Main()
{
new C<S>().Print();
new C<S?>().Print();
new C<S?>(new S()).Print();
new C<string>(""hello"").Print();
new C<string>().Print();
}
}";
var verify = CompileAndVerify(source, expectedOutput: @"0
1
0
0
hello
hello");
verify.VerifyIL("C<T>.Print()", @"
{
// Code size 75 (0x4b)
.maxstack 2
.locals init (T V_0)
IL_0000: ldarg.0
IL_0001: ldflda ""T C<T>.t""
IL_0006: ldloca.s V_0
IL_0008: initobj ""T""
IL_000e: ldloc.0
IL_000f: box ""T""
IL_0014: brtrue.s IL_002a
IL_0016: ldobj ""T""
IL_001b: stloc.0
IL_001c: ldloca.s V_0
IL_001e: ldloc.0
IL_001f: box ""T""
IL_0024: brtrue.s IL_002a
IL_0026: pop
IL_0027: ldnull
IL_0028: br.s IL_0035
IL_002a: constrained. ""T""
IL_0030: callvirt ""string object.ToString()""
IL_0035: call ""void System.Console.WriteLine(string)""
IL_003a: ldarg.0
IL_003b: ldfld ""T C<T>.t""
IL_0040: box ""T""
IL_0045: call ""void System.Console.WriteLine(object)""
IL_004a: ret
}");
}
[Fact]
[WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")]
public void ConditionalAccessReadonlyUnconstrainedTField()
{
var source = @"using System;
public class C<T>
{
public C(T t) => this.t = t;
public C(){}
readonly T t;
public void Print()
{
Console.WriteLine(t?.ToString());
Console.WriteLine(t);
}
}
public struct S
{
int a;
public override string ToString() => a++.ToString();
}
public static class Program
{
public static void Main()
{
new C<S>().Print();
new C<S?>().Print();
new C<S?>(new S()).Print();
new C<string>(""hello"").Print();
new C<string>().Print();
}
}
";
var verify = CompileAndVerify(source, expectedOutput: @"0
0
0
0
hello
hello");
verify.VerifyIL("C<T>.Print()", @"
{
// Code size 54 (0x36)
.maxstack 2
.locals init (T V_0)
IL_0000: ldarg.0
IL_0001: ldfld ""T C<T>.t""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: ldloc.0
IL_000a: box ""T""
IL_000f: brtrue.s IL_0015
IL_0011: pop
IL_0012: ldnull
IL_0013: br.s IL_0020
IL_0015: constrained. ""T""
IL_001b: callvirt ""string object.ToString()""
IL_0020: call ""void System.Console.WriteLine(string)""
IL_0025: ldarg.0
IL_0026: ldfld ""T C<T>.t""
IL_002b: box ""T""
IL_0030: call ""void System.Console.WriteLine(object)""
IL_0035: ret
}");
}
[Fact]
[WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")]
public void ConditionalAccessUnconstrainedTLocal()
{
var source = @"using System;
public class C<T>
{
public C(T t) => this.t = t;
public C(){}
private T t;
public void Print()
{
var temp = t;
Console.WriteLine(temp?.ToString());
Console.WriteLine(temp);
}
}
public struct S
{
int a;
public override string ToString() => a++.ToString();
}
public static class Program
{
public static void Main()
{
new C<S>().Print();
new C<S?>().Print();
new C<S?>(new S()).Print();
new C<string>(""hello"").Print();
new C<string>().Print();
}
}";
var verify = CompileAndVerify(source, expectedOutput: @"0
1
0
1
hello
hello");
verify.VerifyIL("C<T>.Print()", @"
{
// Code size 48 (0x30)
.maxstack 1
.locals init (T V_0) //temp
IL_0000: ldarg.0
IL_0001: ldfld ""T C<T>.t""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: box ""T""
IL_000d: brtrue.s IL_0012
IL_000f: ldnull
IL_0010: br.s IL_001f
IL_0012: ldloca.s V_0
IL_0014: constrained. ""T""
IL_001a: callvirt ""string object.ToString()""
IL_001f: call ""void System.Console.WriteLine(string)""
IL_0024: ldloc.0
IL_0025: box ""T""
IL_002a: call ""void System.Console.WriteLine(object)""
IL_002f: ret
}");
}
[Fact]
[WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")]
public void ConditionalAccessUnconstrainedTTemp()
{
var source = @"using System;
public class C<T>
{
public C(T t) => this.t = t;
public C(){}
T t;
T M() => t;
public void Print() => Console.WriteLine(M()?.ToString());
}
public static class Program
{
public static void Main()
{
new C<int>().Print();
new C<int?>().Print();
new C<int?>(0).Print();
new C<string>(""hello"").Print();
new C<string>().Print();
}
}
";
var verify = CompileAndVerify(source, expectedOutput: @"0
0
hello
");
verify.VerifyIL("C<T>.Print()", @"
{
// Code size 38 (0x26)
.maxstack 2
.locals init (T V_0)
IL_0000: ldarg.0
IL_0001: call ""T C<T>.M()""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: ldloc.0
IL_000a: box ""T""
IL_000f: brtrue.s IL_0015
IL_0011: pop
IL_0012: ldnull
IL_0013: br.s IL_0020
IL_0015: constrained. ""T""
IL_001b: callvirt ""string object.ToString()""
IL_0020: call ""void System.Console.WriteLine(string)""
IL_0025: ret
}");
}
}
}
......@@ -2461,32 +2461,49 @@ static void Main(string[] args)
False");
comp.VerifyIL("Program.Test<T>(System.Func<T>)", @"
{
// Code size 62 (0x3e)
// Code size 110 (0x6e)
.maxstack 2
.locals init (T V_0)
.locals init (T V_0,
T V_1)
IL_0000: ldarg.0
IL_0001: callvirt ""T System.Func<T>.Invoke()""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: ldloc.0
IL_000a: box ""T""
IL_000f: brtrue.s IL_0014
IL_0011: pop
IL_0012: br.s IL_001f
IL_0014: constrained. ""T""
IL_001a: callvirt ""void System.IDisposable.Dispose()""
IL_001f: ldarg.0
IL_0020: callvirt ""T System.Func<T>.Invoke()""
IL_0025: stloc.0
IL_0026: ldloca.s V_0
IL_0028: ldloc.0
IL_0029: box ""T""
IL_002e: brtrue.s IL_0032
IL_0030: pop
IL_0031: ret
IL_0032: constrained. ""T""
IL_0038: callvirt ""void System.IDisposable.Dispose()""
IL_003d: ret
IL_0009: ldloca.s V_1
IL_000b: initobj ""T""
IL_0011: ldloc.1
IL_0012: box ""T""
IL_0017: brtrue.s IL_002c
IL_0019: ldobj ""T""
IL_001e: stloc.1
IL_001f: ldloca.s V_1
IL_0021: ldloc.1
IL_0022: box ""T""
IL_0027: brtrue.s IL_002c
IL_0029: pop
IL_002a: br.s IL_0037
IL_002c: constrained. ""T""
IL_0032: callvirt ""void System.IDisposable.Dispose()""
IL_0037: ldarg.0
IL_0038: callvirt ""T System.Func<T>.Invoke()""
IL_003d: stloc.0
IL_003e: ldloca.s V_0
IL_0040: ldloca.s V_1
IL_0042: initobj ""T""
IL_0048: ldloc.1
IL_0049: box ""T""
IL_004e: brtrue.s IL_0062
IL_0050: ldobj ""T""
IL_0055: stloc.1
IL_0056: ldloca.s V_1
IL_0058: ldloc.1
IL_0059: box ""T""
IL_005e: brtrue.s IL_0062
IL_0060: pop
IL_0061: ret
IL_0062: constrained. ""T""
IL_0068: callvirt ""void System.IDisposable.Dispose()""
IL_006d: ret
}
");
}
......
......@@ -424,11 +424,14 @@ .maxstack 3
).VerifyIL(
"<>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.ToString",
@"{
// Code size 123 (0x7b)
// Code size 199 (0xc7)
.maxstack 7
.locals init (<Length>j__TPar V_0,
<at1>j__TPar V_1,
<C>j__TPar V_2)
<Length>j__TPar V_1,
<at1>j__TPar V_2,
<at1>j__TPar V_3,
<C>j__TPar V_4,
<C>j__TPar V_5)
IL_0000: ldnull
IL_0001: ldstr ""{{ Length = {0}, at1 = {1}, C = {2} }}""
IL_0006: ldc.i4.3
......@@ -439,47 +442,71 @@ .maxstack 7
IL_000f: ldfld ""<Length>j__TPar <>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.<Length>i__Field""
IL_0014: stloc.0
IL_0015: ldloca.s V_0
IL_0017: ldloc.0
IL_0018: box ""<Length>j__TPar""
IL_001d: brtrue.s IL_0023
IL_001f: pop
IL_0020: ldnull
IL_0021: br.s IL_002e
IL_0023: constrained. ""<Length>j__TPar""
IL_0029: callvirt ""string object.ToString()""
IL_002e: stelem.ref
IL_002f: dup
IL_0030: ldc.i4.1
IL_0031: ldarg.0
IL_0032: ldfld ""<at1>j__TPar <>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.<at1>i__Field""
IL_0037: stloc.1
IL_0038: ldloca.s V_1
IL_003a: ldloc.1
IL_003b: box ""<at1>j__TPar""
IL_0040: brtrue.s IL_0046
IL_0042: pop
IL_0043: ldnull
IL_0044: br.s IL_0051
IL_0046: constrained. ""<at1>j__TPar""
IL_004c: callvirt ""string object.ToString()""
IL_0051: stelem.ref
IL_0052: dup
IL_0053: ldc.i4.2
IL_0054: ldarg.0
IL_0055: ldfld ""<C>j__TPar <>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.<C>i__Field""
IL_005a: stloc.2
IL_005b: ldloca.s V_2
IL_005d: ldloc.2
IL_005e: box ""<C>j__TPar""
IL_0063: brtrue.s IL_0069
IL_0065: pop
IL_0066: ldnull
IL_0067: br.s IL_0074
IL_0069: constrained. ""<C>j__TPar""
IL_006f: callvirt ""string object.ToString()""
IL_0074: stelem.ref
IL_0075: call ""string string.Format(System.IFormatProvider, string, params object[])""
IL_007a: ret
IL_0017: ldloca.s V_1
IL_0019: initobj ""<Length>j__TPar""
IL_001f: ldloc.1
IL_0020: box ""<Length>j__TPar""
IL_0025: brtrue.s IL_003b
IL_0027: ldobj ""<Length>j__TPar""
IL_002c: stloc.1
IL_002d: ldloca.s V_1
IL_002f: ldloc.1
IL_0030: box ""<Length>j__TPar""
IL_0035: brtrue.s IL_003b
IL_0037: pop
IL_0038: ldnull
IL_0039: br.s IL_0046
IL_003b: constrained. ""<Length>j__TPar""
IL_0041: callvirt ""string object.ToString()""
IL_0046: stelem.ref
IL_0047: dup
IL_0048: ldc.i4.1
IL_0049: ldarg.0
IL_004a: ldfld ""<at1>j__TPar <>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.<at1>i__Field""
IL_004f: stloc.2
IL_0050: ldloca.s V_2
IL_0052: ldloca.s V_3
IL_0054: initobj ""<at1>j__TPar""
IL_005a: ldloc.3
IL_005b: box ""<at1>j__TPar""
IL_0060: brtrue.s IL_0076
IL_0062: ldobj ""<at1>j__TPar""
IL_0067: stloc.3
IL_0068: ldloca.s V_3
IL_006a: ldloc.3
IL_006b: box ""<at1>j__TPar""
IL_0070: brtrue.s IL_0076
IL_0072: pop
IL_0073: ldnull
IL_0074: br.s IL_0081
IL_0076: constrained. ""<at1>j__TPar""
IL_007c: callvirt ""string object.ToString()""
IL_0081: stelem.ref
IL_0082: dup
IL_0083: ldc.i4.2
IL_0084: ldarg.0
IL_0085: ldfld ""<C>j__TPar <>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.<C>i__Field""
IL_008a: stloc.s V_4
IL_008c: ldloca.s V_4
IL_008e: ldloca.s V_5
IL_0090: initobj ""<C>j__TPar""
IL_0096: ldloc.s V_5
IL_0098: box ""<C>j__TPar""
IL_009d: brtrue.s IL_00b5
IL_009f: ldobj ""<C>j__TPar""
IL_00a4: stloc.s V_5
IL_00a6: ldloca.s V_5
IL_00a8: ldloc.s V_5
IL_00aa: box ""<C>j__TPar""
IL_00af: brtrue.s IL_00b5
IL_00b1: pop
IL_00b2: ldnull
IL_00b3: br.s IL_00c0
IL_00b5: constrained. ""<C>j__TPar""
IL_00bb: callvirt ""string object.ToString()""
IL_00c0: stelem.ref
IL_00c1: call ""string string.Format(System.IFormatProvider, string, params object[])""
IL_00c6: ret
}"
);
}
......@@ -846,11 +873,14 @@ .maxstack 3
).VerifyIL(
"<>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.ToString",
@"{
// Code size 123 (0x7b)
// Code size 199 (0xc7)
.maxstack 7
.locals init (<ToString>j__TPar V_0,
<Equals>j__TPar V_1,
<GetHashCode>j__TPar V_2)
<ToString>j__TPar V_1,
<Equals>j__TPar V_2,
<Equals>j__TPar V_3,
<GetHashCode>j__TPar V_4,
<GetHashCode>j__TPar V_5)
IL_0000: ldnull
IL_0001: ldstr ""{{ ToString = {0}, Equals = {1}, GetHashCode = {2} }}""
IL_0006: ldc.i4.3
......@@ -861,47 +891,71 @@ .maxstack 7
IL_000f: ldfld ""<ToString>j__TPar <>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.<ToString>i__Field""
IL_0014: stloc.0
IL_0015: ldloca.s V_0
IL_0017: ldloc.0
IL_0018: box ""<ToString>j__TPar""
IL_001d: brtrue.s IL_0023
IL_001f: pop
IL_0020: ldnull
IL_0021: br.s IL_002e
IL_0023: constrained. ""<ToString>j__TPar""
IL_0029: callvirt ""string object.ToString()""
IL_002e: stelem.ref
IL_002f: dup
IL_0030: ldc.i4.1
IL_0031: ldarg.0
IL_0032: ldfld ""<Equals>j__TPar <>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.<Equals>i__Field""
IL_0037: stloc.1
IL_0038: ldloca.s V_1
IL_003a: ldloc.1
IL_003b: box ""<Equals>j__TPar""
IL_0040: brtrue.s IL_0046
IL_0042: pop
IL_0043: ldnull
IL_0044: br.s IL_0051
IL_0046: constrained. ""<Equals>j__TPar""
IL_004c: callvirt ""string object.ToString()""
IL_0051: stelem.ref
IL_0052: dup
IL_0053: ldc.i4.2
IL_0054: ldarg.0
IL_0055: ldfld ""<GetHashCode>j__TPar <>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.<GetHashCode>i__Field""
IL_005a: stloc.2
IL_005b: ldloca.s V_2
IL_005d: ldloc.2
IL_005e: box ""<GetHashCode>j__TPar""
IL_0063: brtrue.s IL_0069
IL_0065: pop
IL_0066: ldnull
IL_0067: br.s IL_0074
IL_0069: constrained. ""<GetHashCode>j__TPar""
IL_006f: callvirt ""string object.ToString()""
IL_0074: stelem.ref
IL_0075: call ""string string.Format(System.IFormatProvider, string, params object[])""
IL_007a: ret
IL_0017: ldloca.s V_1
IL_0019: initobj ""<ToString>j__TPar""
IL_001f: ldloc.1
IL_0020: box ""<ToString>j__TPar""
IL_0025: brtrue.s IL_003b
IL_0027: ldobj ""<ToString>j__TPar""
IL_002c: stloc.1
IL_002d: ldloca.s V_1
IL_002f: ldloc.1
IL_0030: box ""<ToString>j__TPar""
IL_0035: brtrue.s IL_003b
IL_0037: pop
IL_0038: ldnull
IL_0039: br.s IL_0046
IL_003b: constrained. ""<ToString>j__TPar""
IL_0041: callvirt ""string object.ToString()""
IL_0046: stelem.ref
IL_0047: dup
IL_0048: ldc.i4.1
IL_0049: ldarg.0
IL_004a: ldfld ""<Equals>j__TPar <>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.<Equals>i__Field""
IL_004f: stloc.2
IL_0050: ldloca.s V_2
IL_0052: ldloca.s V_3
IL_0054: initobj ""<Equals>j__TPar""
IL_005a: ldloc.3
IL_005b: box ""<Equals>j__TPar""
IL_0060: brtrue.s IL_0076
IL_0062: ldobj ""<Equals>j__TPar""
IL_0067: stloc.3
IL_0068: ldloca.s V_3
IL_006a: ldloc.3
IL_006b: box ""<Equals>j__TPar""
IL_0070: brtrue.s IL_0076
IL_0072: pop
IL_0073: ldnull
IL_0074: br.s IL_0081
IL_0076: constrained. ""<Equals>j__TPar""
IL_007c: callvirt ""string object.ToString()""
IL_0081: stelem.ref
IL_0082: dup
IL_0083: ldc.i4.2
IL_0084: ldarg.0
IL_0085: ldfld ""<GetHashCode>j__TPar <>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.<GetHashCode>i__Field""
IL_008a: stloc.s V_4
IL_008c: ldloca.s V_4
IL_008e: ldloca.s V_5
IL_0090: initobj ""<GetHashCode>j__TPar""
IL_0096: ldloc.s V_5
IL_0098: box ""<GetHashCode>j__TPar""
IL_009d: brtrue.s IL_00b5
IL_009f: ldobj ""<GetHashCode>j__TPar""
IL_00a4: stloc.s V_5
IL_00a6: ldloca.s V_5
IL_00a8: ldloc.s V_5
IL_00aa: box ""<GetHashCode>j__TPar""
IL_00af: brtrue.s IL_00b5
IL_00b1: pop
IL_00b2: ldnull
IL_00b3: br.s IL_00c0
IL_00b5: constrained. ""<GetHashCode>j__TPar""
IL_00bb: callvirt ""string object.ToString()""
IL_00c0: stelem.ref
IL_00c1: call ""string string.Format(System.IFormatProvider, string, params object[])""
IL_00c6: ret
}"
).VerifyIL(
"<>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.ToString.get",
......
......@@ -288,43 +288,35 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
Dim nullCheckOnCopy = conditional.CaptureReceiver OrElse (receiverType.IsReferenceType AndAlso receiverType.TypeKind = TypeKind.TypeParameter)
If nullCheckOnCopy Then
receiverTemp = EmitReceiverRef(receiver, isAccessConstrained:=Not receiverType.IsReferenceType, addressKind:=AddressKind.ReadOnly)
EmitReceiverRef(receiver, isAccessConstrained:=Not receiverType.IsReferenceType, addressKind:=AddressKind.ReadOnly)
If Not receiverType.IsReferenceType Then
If receiverTemp Is Nothing Then
' unconstrained case needs to handle case where T Is actually a struct.
' such values are never nulls
' we will emit a check for such case, but the check Is really a JIT-time
' constant since JIT will know if T Is a struct Or Not.
'
' if ((object)default(T) != null)
' {
' goto whenNotNull
' }
' else
' {
' temp = receiverRef
' receiverRef = ref temp
' }
EmitInitObj(receiverType, True, receiver.Syntax)
EmitBox(receiverType, receiver.Syntax)
_builder.EmitBranch(ILOpCode.Brtrue, whenNotNullLabel)
EmitLoadIndirect(receiverType, receiver.Syntax)
temp = AllocateTemp(receiverType, receiver.Syntax)
_builder.EmitLocalStore(temp)
_builder.EmitLocalAddress(temp)
_builder.EmitLocalLoad(temp)
EmitBox(receiverType, receiver.Syntax)
' unconstrained case needs to handle case where T Is actually a struct.
' such values are never nulls
' we will emit a check for such case, but the check Is really a JIT-time
' constant since JIT will know if T Is a struct Or Not.
'
' if ((object)default(T) != null)
' {
' goto whenNotNull
' }
' else
' {
' temp = receiverRef
' receiverRef = ref temp
' }
EmitInitObj(receiverType, True, receiver.Syntax)
EmitBox(receiverType, receiver.Syntax)
_builder.EmitBranch(ILOpCode.Brtrue, whenNotNullLabel)
EmitLoadIndirect(receiverType, receiver.Syntax)
' here we have loaded a ref to a temp And its boxed value { &T, O }
Else
' we are calling the expression on a copy of the target anyway,
' so even if T is a struct, we don't need to make sure we call the expression on the original target.
temp = AllocateTemp(receiverType, receiver.Syntax)
_builder.EmitLocalStore(temp)
_builder.EmitLocalAddress(temp)
_builder.EmitLocalLoad(temp)
EmitBox(receiver.Type, receiver.Syntax)
_builder.EmitLocalLoad(receiverTemp)
EmitBox(receiverType, receiver.Syntax)
End If
' here we have loaded a ref to a temp And its boxed value { &T, O }
Else
_builder.EmitOpCode(ILOpCode.Dup)
' here we have loaded two copies of a reference { O, O }
......@@ -368,7 +360,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
_builder.MarkLabel(whenNotNullLabel)
If Not nullCheckOnCopy Then
Debug.Assert(receiverTemp Is Nothing)
receiverTemp = EmitReceiverRef(receiver, isAccessConstrained:=Not receiverType.IsReferenceType, addressKind:=AddressKind.ReadOnly)
Debug.Assert(receiverTemp Is Nothing OrElse receiver.IsDefaultValue())
End If
......
......@@ -613,23 +613,32 @@ Null
verifier.VerifyIL("Module1.Test8",
<![CDATA[
{
// Code size 38 (0x26)
// Code size 62 (0x3e)
.maxstack 2
.locals init (T V_0)
.locals init (T V_0,
T V_1)
IL_0000: ldarg.0
IL_0001: call "Function Module1.GetT(Of T)(T) As T"
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: ldloc.0
IL_000a: box "T"
IL_000f: brtrue.s IL_0015
IL_0011: pop
IL_0012: ldnull
IL_0013: br.s IL_0020
IL_0015: constrained. "T"
IL_001b: callvirt "Function I1.get_P2() As String"
IL_0020: call "Sub Module1.Do(Of String)(String)"
IL_0025: ret
IL_0009: ldloca.s V_1
IL_000b: initobj "T"
IL_0011: ldloc.1
IL_0012: box "T"
IL_0017: brtrue.s IL_002d
IL_0019: ldobj "T"
IL_001e: stloc.1
IL_001f: ldloca.s V_1
IL_0021: ldloc.1
IL_0022: box "T"
IL_0027: brtrue.s IL_002d
IL_0029: pop
IL_002a: ldnull
IL_002b: br.s IL_0038
IL_002d: constrained. "T"
IL_0033: callvirt "Function I1.get_P2() As String"
IL_0038: call "Sub Module1.Do(Of String)(String)"
IL_003d: ret
}
]]>)
......@@ -3543,21 +3552,30 @@ Ext4 C1
verifier.VerifyIL("Module1.Test1_6",
<![CDATA[
{
// Code size 30 (0x1e)
// Code size 54 (0x36)
.maxstack 2
.locals init (T V_0)
.locals init (T V_0,
T V_1)
IL_0000: ldarg.0
IL_0001: call "Function Module1.GetT(Of T)(T) As T"
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: ldloc.0
IL_000a: box "T"
IL_000f: brtrue.s IL_0013
IL_0011: pop
IL_0012: ret
IL_0013: ldobj "T"
IL_0018: call "Sub Module1.Ext1(Of T)(T)"
IL_001d: ret
IL_0009: ldloca.s V_1
IL_000b: initobj "T"
IL_0011: ldloc.1
IL_0012: box "T"
IL_0017: brtrue.s IL_002b
IL_0019: ldobj "T"
IL_001e: stloc.1
IL_001f: ldloca.s V_1
IL_0021: ldloc.1
IL_0022: box "T"
IL_0027: brtrue.s IL_002b
IL_0029: pop
IL_002a: ret
IL_002b: ldobj "T"
IL_0030: call "Sub Module1.Ext1(Of T)(T)"
IL_0035: ret
}
]]>)
......@@ -5288,317 +5306,6 @@ C1
]]>)
End Sub
<Fact>
<WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")>
Public Sub CodeGen_ConditionalAccessUnconstrainedTField()
Dim c = CompileAndVerify(
<compilation>
<file name="a.vb">
Imports System
Public Class C(Of T)
Public Sub New(t As T)
field = t
End Sub
Public Sub New()
End Sub
Private field As T
Public Sub Print()
Console.WriteLine(field?.ToString())
Console.WriteLine(field)
End Sub
End Class
Public Structure S
Private a As Integer
Public Overrides Function ToString() As String
Dim result = a.ToString()
a = a + 1
Return result
End Function
End Structure
Module Program
Sub Main()
Call New C(Of S)().Print()
Call New C(Of S?)().Print()
Call New C(Of S?)(New S()).Print()
Call New C(Of String)("hello").Print()
Call New C(Of String)().Print()
End Sub
End Module
</file>
</compilation>, expectedOutput:="0
1
0
0
hello
hello")
c.VerifyIL("C(Of T).Print()",
<![CDATA[
{
// Code size 75 (0x4b)
.maxstack 2
.locals init (T V_0)
IL_0000: ldarg.0
IL_0001: ldflda "C(Of T).field As T"
IL_0006: ldloca.s V_0
IL_0008: initobj "T"
IL_000e: ldloc.0
IL_000f: box "T"
IL_0014: brtrue.s IL_002a
IL_0016: ldobj "T"
IL_001b: stloc.0
IL_001c: ldloca.s V_0
IL_001e: ldloc.0
IL_001f: box "T"
IL_0024: brtrue.s IL_002a
IL_0026: pop
IL_0027: ldnull
IL_0028: br.s IL_0035
IL_002a: constrained. "T"
IL_0030: callvirt "Function Object.ToString() As String"
IL_0035: call "Sub System.Console.WriteLine(String)"
IL_003a: ldarg.0
IL_003b: ldfld "C(Of T).field As T"
IL_0040: box "T"
IL_0045: call "Sub System.Console.WriteLine(Object)"
IL_004a: ret
}
]]>)
End Sub
<Fact>
<WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")>
Public Sub CodeGen_ConditionalAccessReadonlyUnconstrainedTField()
Dim c = CompileAndVerify(
<compilation>
<file name="a.vb">
Imports System
Public Class C(Of T)
Public Sub New(ByVal t As T)
field = t
End Sub
Public Sub New()
End Sub
ReadOnly field As T
Public Sub Print()
Console.WriteLine(field?.ToString())
Console.WriteLine(field)
End Sub
End Class
Public Structure S
Private a As Integer
Public Overrides Function ToString() As String
Return Math.Min(System.Threading.Interlocked.Increment(a), a - 1).ToString()
End Function
End Structure
Module Program
Sub Main()
Call New C(Of S)().Print()
Call New C(Of S?)().Print()
Call New C(Of S?)(New S()).Print()
Call New C(Of String)("hello").Print()
Call New C(Of String)().Print()
End Sub
End Module
</file>
</compilation>, expectedOutput:="0
0
0
0
hello
hello")
c.VerifyIL("C(Of T).Print()",
<![CDATA[
{
// Code size 54 (0x36)
.maxstack 2
.locals init (T V_0)
IL_0000: ldarg.0
IL_0001: ldfld "C(Of T).field As T"
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: ldloc.0
IL_000a: box "T"
IL_000f: brtrue.s IL_0015
IL_0011: pop
IL_0012: ldnull
IL_0013: br.s IL_0020
IL_0015: constrained. "T"
IL_001b: callvirt "Function Object.ToString() As String"
IL_0020: call "Sub System.Console.WriteLine(String)"
IL_0025: ldarg.0
IL_0026: ldfld "C(Of T).field As T"
IL_002b: box "T"
IL_0030: call "Sub System.Console.WriteLine(Object)"
IL_0035: ret
}
]]>)
End Sub
<Fact>
<WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")>
Public Sub CodeGen_ConditionalAccessUnconstrainedTLocal()
Dim c = CompileAndVerify(
<compilation>
<file name="a.vb">
Imports System
Public Class C(Of T)
Public Sub New(ByVal t As T)
field = t
End Sub
Public Sub New()
End Sub
Private field As T
Public Sub Print()
Dim temp = field
Console.WriteLine(temp?.ToString())
Console.WriteLine(temp)
End Sub
End Class
Public Structure S
Private a As Integer
Public Overrides Function ToString() As String
Return Math.Min(System.Threading.Interlocked.Increment(a), a - 1).ToString()
End Function
End Structure
Module Program
Sub Main()
Call New C(Of S)().Print()
Call New C(Of S?)().Print()
Call New C(Of S?)(New S()).Print()
Call New C(Of String)("hello").Print()
Call New C(Of String)().Print()
End Sub
End Module
</file>
</compilation>, expectedOutput:="0
1
0
1
hello
hello")
c.VerifyIL("C(Of T).Print()",
<![CDATA[
{
// Code size 48 (0x30)
.maxstack 1
.locals init (T V_0) //temp
IL_0000: ldarg.0
IL_0001: ldfld "C(Of T).field As T"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: box "T"
IL_000d: brtrue.s IL_0012
IL_000f: ldnull
IL_0010: br.s IL_001f
IL_0012: ldloca.s V_0
IL_0014: constrained. "T"
IL_001a: callvirt "Function Object.ToString() As String"
IL_001f: call "Sub System.Console.WriteLine(String)"
IL_0024: ldloc.0
IL_0025: box "T"
IL_002a: call "Sub System.Console.WriteLine(Object)"
IL_002f: ret
}
]]>)
End Sub
<Fact>
<WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")>
Public Sub CodeGen_ConditionalAccessUnconstrainedTTemp()
Dim c = CompileAndVerify(
<compilation>
<file name="a.vb">
Imports System
Public Class C(Of T)
Public Sub New(ByVal t As T)
field = t
End Sub
Public Sub New()
End Sub
Private field As T
Private Function M() As T
Return field
End Function
Public Sub Print()
Console.WriteLine(M()?.ToString())
End Sub
End Class
Module Program
Sub Main()
Call New C(Of Integer)().Print()
Call New C(Of Integer?)().Print()
Call New C(Of Integer?)(0).Print()
Call New C(Of String)("hello").Print()
Call New C(Of String)().Print()
End Sub
End Module
</file>
</compilation>, expectedOutput:="0
0
hello
")
c.VerifyIL("C(Of T).Print()",
<![CDATA[
{
// Code size 38 (0x26)
.maxstack 2
.locals init (T V_0)
IL_0000: ldarg.0
IL_0001: call "Function C(Of T).M() As T"
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: ldloc.0
IL_000a: box "T"
IL_000f: brtrue.s IL_0015
IL_0011: pop
IL_0012: ldnull
IL_0013: br.s IL_0020
IL_0015: constrained. "T"
IL_001b: callvirt "Function Object.ToString() As String"
IL_0020: call "Sub System.Console.WriteLine(String)"
IL_0025: ret
}
]]>)
End Sub
<Fact()>
Public Sub InlineNullableIsTrue_01()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册