提交 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 ...@@ -405,43 +405,32 @@ private void EmitLoweredConditionalAccessExpression(BoundLoweredConditionalAcces
// if T happens to be a value type, it could be a target of mutating calls. // if T happens to be a value type, it could be a target of mutating calls.
receiverTemp = EmitReceiverRef(receiver, AddressKind.Constrained); 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
// unconstrained case needs to handle case where T is actually a struct. // we will emit a check for such case, but the check is really a JIT-time
// such values are never nulls // constant since JIT will know if T is a struct or not.
// 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)
// {
// if ((object)default(T) != null) // goto whenNotNull
// { // }
// goto whenNotNull // else
// } // {
// else // temp = receiverRef
// { // receiverRef = ref temp
// temp = receiverRef // }
// receiverRef = ref temp EmitDefaultValue(receiverType, true, receiver.Syntax);
// } EmitBox(receiverType, receiver.Syntax);
EmitDefaultValue(receiverType, true, receiver.Syntax); _builder.EmitBranch(ILOpCode.Brtrue, whenNotNullLabel);
EmitBox(receiverType, receiver.Syntax); EmitLoadIndirect(receiverType, receiver.Syntax);
_builder.EmitBranch(ILOpCode.Brtrue, whenNotNullLabel);
EmitLoadIndirect(receiverType, receiver.Syntax); cloneTemp = AllocateTemp(receiverType, receiver.Syntax);
_builder.EmitLocalStore(cloneTemp);
cloneTemp = AllocateTemp(receiverType, receiver.Syntax); _builder.EmitLocalAddress(cloneTemp);
_builder.EmitLocalStore(cloneTemp); _builder.EmitLocalLoad(cloneTemp);
_builder.EmitLocalAddress(cloneTemp); EmitBox(receiver.Type, receiver.Syntax);
_builder.EmitLocalLoad(cloneTemp);
EmitBox(receiverType, receiver.Syntax); // here we have loaded a ref to a temp and its boxed value { &T, O }
// 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);
}
} }
else else
{ {
......
...@@ -2763,287 +2763,5 @@ .maxstack 1 ...@@ -2763,287 +2763,5 @@ .maxstack 1
IL_0064: ret 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) ...@@ -2461,32 +2461,49 @@ static void Main(string[] args)
False"); False");
comp.VerifyIL("Program.Test<T>(System.Func<T>)", @" comp.VerifyIL("Program.Test<T>(System.Func<T>)", @"
{ {
// Code size 62 (0x3e) // Code size 110 (0x6e)
.maxstack 2 .maxstack 2
.locals init (T V_0) .locals init (T V_0,
T V_1)
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: callvirt ""T System.Func<T>.Invoke()"" IL_0001: callvirt ""T System.Func<T>.Invoke()""
IL_0006: stloc.0 IL_0006: stloc.0
IL_0007: ldloca.s V_0 IL_0007: ldloca.s V_0
IL_0009: ldloc.0 IL_0009: ldloca.s V_1
IL_000a: box ""T"" IL_000b: initobj ""T""
IL_000f: brtrue.s IL_0014 IL_0011: ldloc.1
IL_0011: pop IL_0012: box ""T""
IL_0012: br.s IL_001f IL_0017: brtrue.s IL_002c
IL_0014: constrained. ""T"" IL_0019: ldobj ""T""
IL_001a: callvirt ""void System.IDisposable.Dispose()"" IL_001e: stloc.1
IL_001f: ldarg.0 IL_001f: ldloca.s V_1
IL_0020: callvirt ""T System.Func<T>.Invoke()"" IL_0021: ldloc.1
IL_0025: stloc.0 IL_0022: box ""T""
IL_0026: ldloca.s V_0 IL_0027: brtrue.s IL_002c
IL_0028: ldloc.0 IL_0029: pop
IL_0029: box ""T"" IL_002a: br.s IL_0037
IL_002e: brtrue.s IL_0032 IL_002c: constrained. ""T""
IL_0030: pop IL_0032: callvirt ""void System.IDisposable.Dispose()""
IL_0031: ret IL_0037: ldarg.0
IL_0032: constrained. ""T"" IL_0038: callvirt ""T System.Func<T>.Invoke()""
IL_0038: callvirt ""void System.IDisposable.Dispose()"" IL_003d: stloc.0
IL_003d: ret 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 ...@@ -424,11 +424,14 @@ .maxstack 3
).VerifyIL( ).VerifyIL(
"<>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.ToString", "<>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.ToString",
@"{ @"{
// Code size 123 (0x7b) // Code size 199 (0xc7)
.maxstack 7 .maxstack 7
.locals init (<Length>j__TPar V_0, .locals init (<Length>j__TPar V_0,
<at1>j__TPar V_1, <Length>j__TPar V_1,
<C>j__TPar V_2) <at1>j__TPar V_2,
<at1>j__TPar V_3,
<C>j__TPar V_4,
<C>j__TPar V_5)
IL_0000: ldnull IL_0000: ldnull
IL_0001: ldstr ""{{ Length = {0}, at1 = {1}, C = {2} }}"" IL_0001: ldstr ""{{ Length = {0}, at1 = {1}, C = {2} }}""
IL_0006: ldc.i4.3 IL_0006: ldc.i4.3
...@@ -439,47 +442,71 @@ .maxstack 7 ...@@ -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_000f: ldfld ""<Length>j__TPar <>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.<Length>i__Field""
IL_0014: stloc.0 IL_0014: stloc.0
IL_0015: ldloca.s V_0 IL_0015: ldloca.s V_0
IL_0017: ldloc.0 IL_0017: ldloca.s V_1
IL_0018: box ""<Length>j__TPar"" IL_0019: initobj ""<Length>j__TPar""
IL_001d: brtrue.s IL_0023 IL_001f: ldloc.1
IL_001f: pop IL_0020: box ""<Length>j__TPar""
IL_0020: ldnull IL_0025: brtrue.s IL_003b
IL_0021: br.s IL_002e IL_0027: ldobj ""<Length>j__TPar""
IL_0023: constrained. ""<Length>j__TPar"" IL_002c: stloc.1
IL_0029: callvirt ""string object.ToString()"" IL_002d: ldloca.s V_1
IL_002e: stelem.ref IL_002f: ldloc.1
IL_002f: dup IL_0030: box ""<Length>j__TPar""
IL_0030: ldc.i4.1 IL_0035: brtrue.s IL_003b
IL_0031: ldarg.0 IL_0037: pop
IL_0032: ldfld ""<at1>j__TPar <>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.<at1>i__Field"" IL_0038: ldnull
IL_0037: stloc.1 IL_0039: br.s IL_0046
IL_0038: ldloca.s V_1 IL_003b: constrained. ""<Length>j__TPar""
IL_003a: ldloc.1 IL_0041: callvirt ""string object.ToString()""
IL_003b: box ""<at1>j__TPar"" IL_0046: stelem.ref
IL_0040: brtrue.s IL_0046 IL_0047: dup
IL_0042: pop IL_0048: ldc.i4.1
IL_0043: ldnull IL_0049: ldarg.0
IL_0044: br.s IL_0051 IL_004a: ldfld ""<at1>j__TPar <>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.<at1>i__Field""
IL_0046: constrained. ""<at1>j__TPar"" IL_004f: stloc.2
IL_004c: callvirt ""string object.ToString()"" IL_0050: ldloca.s V_2
IL_0051: stelem.ref IL_0052: ldloca.s V_3
IL_0052: dup IL_0054: initobj ""<at1>j__TPar""
IL_0053: ldc.i4.2 IL_005a: ldloc.3
IL_0054: ldarg.0 IL_005b: box ""<at1>j__TPar""
IL_0055: ldfld ""<C>j__TPar <>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.<C>i__Field"" IL_0060: brtrue.s IL_0076
IL_005a: stloc.2 IL_0062: ldobj ""<at1>j__TPar""
IL_005b: ldloca.s V_2 IL_0067: stloc.3
IL_005d: ldloc.2 IL_0068: ldloca.s V_3
IL_005e: box ""<C>j__TPar"" IL_006a: ldloc.3
IL_0063: brtrue.s IL_0069 IL_006b: box ""<at1>j__TPar""
IL_0065: pop IL_0070: brtrue.s IL_0076
IL_0066: ldnull IL_0072: pop
IL_0067: br.s IL_0074 IL_0073: ldnull
IL_0069: constrained. ""<C>j__TPar"" IL_0074: br.s IL_0081
IL_006f: callvirt ""string object.ToString()"" IL_0076: constrained. ""<at1>j__TPar""
IL_0074: stelem.ref IL_007c: callvirt ""string object.ToString()""
IL_0075: call ""string string.Format(System.IFormatProvider, string, params object[])"" IL_0081: stelem.ref
IL_007a: ret 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 ...@@ -846,11 +873,14 @@ .maxstack 3
).VerifyIL( ).VerifyIL(
"<>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.ToString", "<>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.ToString",
@"{ @"{
// Code size 123 (0x7b) // Code size 199 (0xc7)
.maxstack 7 .maxstack 7
.locals init (<ToString>j__TPar V_0, .locals init (<ToString>j__TPar V_0,
<Equals>j__TPar V_1, <ToString>j__TPar V_1,
<GetHashCode>j__TPar V_2) <Equals>j__TPar V_2,
<Equals>j__TPar V_3,
<GetHashCode>j__TPar V_4,
<GetHashCode>j__TPar V_5)
IL_0000: ldnull IL_0000: ldnull
IL_0001: ldstr ""{{ ToString = {0}, Equals = {1}, GetHashCode = {2} }}"" IL_0001: ldstr ""{{ ToString = {0}, Equals = {1}, GetHashCode = {2} }}""
IL_0006: ldc.i4.3 IL_0006: ldc.i4.3
...@@ -861,47 +891,71 @@ .maxstack 7 ...@@ -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_000f: ldfld ""<ToString>j__TPar <>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.<ToString>i__Field""
IL_0014: stloc.0 IL_0014: stloc.0
IL_0015: ldloca.s V_0 IL_0015: ldloca.s V_0
IL_0017: ldloc.0 IL_0017: ldloca.s V_1
IL_0018: box ""<ToString>j__TPar"" IL_0019: initobj ""<ToString>j__TPar""
IL_001d: brtrue.s IL_0023 IL_001f: ldloc.1
IL_001f: pop IL_0020: box ""<ToString>j__TPar""
IL_0020: ldnull IL_0025: brtrue.s IL_003b
IL_0021: br.s IL_002e IL_0027: ldobj ""<ToString>j__TPar""
IL_0023: constrained. ""<ToString>j__TPar"" IL_002c: stloc.1
IL_0029: callvirt ""string object.ToString()"" IL_002d: ldloca.s V_1
IL_002e: stelem.ref IL_002f: ldloc.1
IL_002f: dup IL_0030: box ""<ToString>j__TPar""
IL_0030: ldc.i4.1 IL_0035: brtrue.s IL_003b
IL_0031: ldarg.0 IL_0037: pop
IL_0032: ldfld ""<Equals>j__TPar <>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.<Equals>i__Field"" IL_0038: ldnull
IL_0037: stloc.1 IL_0039: br.s IL_0046
IL_0038: ldloca.s V_1 IL_003b: constrained. ""<ToString>j__TPar""
IL_003a: ldloc.1 IL_0041: callvirt ""string object.ToString()""
IL_003b: box ""<Equals>j__TPar"" IL_0046: stelem.ref
IL_0040: brtrue.s IL_0046 IL_0047: dup
IL_0042: pop IL_0048: ldc.i4.1
IL_0043: ldnull IL_0049: ldarg.0
IL_0044: br.s IL_0051 IL_004a: ldfld ""<Equals>j__TPar <>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.<Equals>i__Field""
IL_0046: constrained. ""<Equals>j__TPar"" IL_004f: stloc.2
IL_004c: callvirt ""string object.ToString()"" IL_0050: ldloca.s V_2
IL_0051: stelem.ref IL_0052: ldloca.s V_3
IL_0052: dup IL_0054: initobj ""<Equals>j__TPar""
IL_0053: ldc.i4.2 IL_005a: ldloc.3
IL_0054: ldarg.0 IL_005b: box ""<Equals>j__TPar""
IL_0055: ldfld ""<GetHashCode>j__TPar <>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.<GetHashCode>i__Field"" IL_0060: brtrue.s IL_0076
IL_005a: stloc.2 IL_0062: ldobj ""<Equals>j__TPar""
IL_005b: ldloca.s V_2 IL_0067: stloc.3
IL_005d: ldloc.2 IL_0068: ldloca.s V_3
IL_005e: box ""<GetHashCode>j__TPar"" IL_006a: ldloc.3
IL_0063: brtrue.s IL_0069 IL_006b: box ""<Equals>j__TPar""
IL_0065: pop IL_0070: brtrue.s IL_0076
IL_0066: ldnull IL_0072: pop
IL_0067: br.s IL_0074 IL_0073: ldnull
IL_0069: constrained. ""<GetHashCode>j__TPar"" IL_0074: br.s IL_0081
IL_006f: callvirt ""string object.ToString()"" IL_0076: constrained. ""<Equals>j__TPar""
IL_0074: stelem.ref IL_007c: callvirt ""string object.ToString()""
IL_0075: call ""string string.Format(System.IFormatProvider, string, params object[])"" IL_0081: stelem.ref
IL_007a: ret 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( ).VerifyIL(
"<>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.ToString.get", "<>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.ToString.get",
......
...@@ -288,43 +288,35 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen ...@@ -288,43 +288,35 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
Dim nullCheckOnCopy = conditional.CaptureReceiver OrElse (receiverType.IsReferenceType AndAlso receiverType.TypeKind = TypeKind.TypeParameter) Dim nullCheckOnCopy = conditional.CaptureReceiver OrElse (receiverType.IsReferenceType AndAlso receiverType.TypeKind = TypeKind.TypeParameter)
If nullCheckOnCopy Then 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 Not receiverType.IsReferenceType Then
If receiverTemp Is Nothing Then ' unconstrained case needs to handle case where T Is actually a struct.
' unconstrained case needs to handle case where T Is actually a struct. ' such values are never nulls
' such values are never nulls ' we will emit a check for such case, but the check Is really a JIT-time
' 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.
' constant since JIT will know if T Is a struct Or Not. '
' ' if ((object)default(T) != null)
' if ((object)default(T) != null) ' {
' { ' goto whenNotNull
' goto whenNotNull ' }
' } ' else
' else ' {
' { ' temp = receiverRef
' temp = receiverRef ' receiverRef = ref temp
' receiverRef = ref temp ' }
' } EmitInitObj(receiverType, True, receiver.Syntax)
EmitInitObj(receiverType, True, receiver.Syntax) EmitBox(receiverType, receiver.Syntax)
EmitBox(receiverType, receiver.Syntax) _builder.EmitBranch(ILOpCode.Brtrue, whenNotNullLabel)
_builder.EmitBranch(ILOpCode.Brtrue, whenNotNullLabel) EmitLoadIndirect(receiverType, receiver.Syntax)
EmitLoadIndirect(receiverType, receiver.Syntax)
temp = AllocateTemp(receiverType, receiver.Syntax)
_builder.EmitLocalStore(temp)
_builder.EmitLocalAddress(temp)
_builder.EmitLocalLoad(temp)
EmitBox(receiverType, receiver.Syntax)
' here we have loaded a ref to a temp And its boxed value { &T, O } temp = AllocateTemp(receiverType, receiver.Syntax)
Else _builder.EmitLocalStore(temp)
' we are calling the expression on a copy of the target anyway, _builder.EmitLocalAddress(temp)
' so even if T is a struct, we don't need to make sure we call the expression on the original target. _builder.EmitLocalLoad(temp)
EmitBox(receiver.Type, receiver.Syntax)
_builder.EmitLocalLoad(receiverTemp) ' here we have loaded a ref to a temp And its boxed value { &T, O }
EmitBox(receiverType, receiver.Syntax)
End If
Else Else
_builder.EmitOpCode(ILOpCode.Dup) _builder.EmitOpCode(ILOpCode.Dup)
' here we have loaded two copies of a reference { O, O } ' here we have loaded two copies of a reference { O, O }
...@@ -368,7 +360,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen ...@@ -368,7 +360,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
_builder.MarkLabel(whenNotNullLabel) _builder.MarkLabel(whenNotNullLabel)
If Not nullCheckOnCopy Then If Not nullCheckOnCopy Then
Debug.Assert(receiverTemp Is Nothing)
receiverTemp = EmitReceiverRef(receiver, isAccessConstrained:=Not receiverType.IsReferenceType, addressKind:=AddressKind.ReadOnly) receiverTemp = EmitReceiverRef(receiver, isAccessConstrained:=Not receiverType.IsReferenceType, addressKind:=AddressKind.ReadOnly)
Debug.Assert(receiverTemp Is Nothing OrElse receiver.IsDefaultValue()) Debug.Assert(receiverTemp Is Nothing OrElse receiver.IsDefaultValue())
End If End If
......
...@@ -613,23 +613,32 @@ Null ...@@ -613,23 +613,32 @@ Null
verifier.VerifyIL("Module1.Test8", verifier.VerifyIL("Module1.Test8",
<![CDATA[ <![CDATA[
{ {
// Code size 38 (0x26) // Code size 62 (0x3e)
.maxstack 2 .maxstack 2
.locals init (T V_0) .locals init (T V_0,
T V_1)
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: call "Function Module1.GetT(Of T)(T) As T" IL_0001: call "Function Module1.GetT(Of T)(T) As T"
IL_0006: stloc.0 IL_0006: stloc.0
IL_0007: ldloca.s V_0 IL_0007: ldloca.s V_0
IL_0009: ldloc.0 IL_0009: ldloca.s V_1
IL_000a: box "T" IL_000b: initobj "T"
IL_000f: brtrue.s IL_0015 IL_0011: ldloc.1
IL_0011: pop IL_0012: box "T"
IL_0012: ldnull IL_0017: brtrue.s IL_002d
IL_0013: br.s IL_0020 IL_0019: ldobj "T"
IL_0015: constrained. "T" IL_001e: stloc.1
IL_001b: callvirt "Function I1.get_P2() As String" IL_001f: ldloca.s V_1
IL_0020: call "Sub Module1.Do(Of String)(String)" IL_0021: ldloc.1
IL_0025: ret 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 ...@@ -3543,21 +3552,30 @@ Ext4 C1
verifier.VerifyIL("Module1.Test1_6", verifier.VerifyIL("Module1.Test1_6",
<![CDATA[ <![CDATA[
{ {
// Code size 30 (0x1e) // Code size 54 (0x36)
.maxstack 2 .maxstack 2
.locals init (T V_0) .locals init (T V_0,
T V_1)
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: call "Function Module1.GetT(Of T)(T) As T" IL_0001: call "Function Module1.GetT(Of T)(T) As T"
IL_0006: stloc.0 IL_0006: stloc.0
IL_0007: ldloca.s V_0 IL_0007: ldloca.s V_0
IL_0009: ldloc.0 IL_0009: ldloca.s V_1
IL_000a: box "T" IL_000b: initobj "T"
IL_000f: brtrue.s IL_0013 IL_0011: ldloc.1
IL_0011: pop IL_0012: box "T"
IL_0012: ret IL_0017: brtrue.s IL_002b
IL_0013: ldobj "T" IL_0019: ldobj "T"
IL_0018: call "Sub Module1.Ext1(Of T)(T)" IL_001e: stloc.1
IL_001d: ret 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 ...@@ -5288,317 +5306,6 @@ C1
]]>) ]]>)
End Sub 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()> <Fact()>
Public Sub InlineNullableIsTrue_01() Public Sub InlineNullableIsTrue_01()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册