未验证 提交 d8ef80e3 编写于 作者: Y Yair Halberstadt 提交者: GitHub

Fix invalid IL for unconstrained conditional access. (#40878)

上级 4e88ffa6
......@@ -407,6 +407,8 @@ 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
......@@ -430,11 +432,22 @@ private void EmitLoweredConditionalAccessExpression(BoundLoweredConditionalAcces
_builder.EmitLocalStore(cloneTemp);
_builder.EmitLocalAddress(cloneTemp);
_builder.EmitLocalLoad(cloneTemp);
EmitBox(receiver.Type, receiver.Syntax);
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.
// We currently have an address on the stack. Duplicate it, and load the value of the address.
_builder.EmitOpCode(ILOpCode.Dup);
EmitLoadIndirect(receiverType, receiver.Syntax);
EmitBox(receiverType, receiver.Syntax);
}
}
else
{
// this does not need to be writeable
// we may call "HasValue" on this, but it is not mutating
......
......@@ -2893,36 +2893,28 @@ public static void Main()
verify.VerifyIL("C<T>.Print()", @"
{
// Code size 78 (0x4e)
// Code size 59 (0x3b)
.maxstack 2
.locals init (T V_0,
T V_1)
.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: 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 ""string object.ToString()""
IL_0038: call ""void System.Console.WriteLine(string)""
IL_003d: ldarg.0
IL_003e: ldfld ""T C<T>.t""
IL_0043: box ""T""
IL_0048: call ""void System.Console.WriteLine(object)""
IL_004d: ret
IL_0009: dup
IL_000a: ldobj ""T""
IL_000f: box ""T""
IL_0014: brtrue.s IL_001a
IL_0016: pop
IL_0017: ldnull
IL_0018: br.s IL_0025
IL_001a: constrained. ""T""
IL_0020: callvirt ""string object.ToString()""
IL_0025: call ""void System.Console.WriteLine(string)""
IL_002a: ldarg.0
IL_002b: ldfld ""T C<T>.t""
IL_0030: box ""T""
IL_0035: call ""void System.Console.WriteLine(object)""
IL_003a: ret
}");
}
......@@ -3036,33 +3028,26 @@ public static void Main()
verify.VerifyIL("C<T>.Print()", @"
{
// Code size 62 (0x3e)
// Code size 43 (0x2b)
.maxstack 2
.locals init (T V_0,
T V_1)
.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: 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 ""string object.ToString()""
IL_0038: call ""void System.Console.WriteLine(string)""
IL_003d: ret
IL_0009: dup
IL_000a: ldobj ""T""
IL_000f: box ""T""
IL_0014: brtrue.s IL_001a
IL_0016: pop
IL_0017: ldnull
IL_0018: br.s IL_0025
IL_001a: constrained. ""T""
IL_0020: callvirt ""string object.ToString()""
IL_0025: call ""void System.Console.WriteLine(string)""
IL_002a: ret
}");
}
[Fact, WorkItem(40690, "https://github.com/dotnet/roslyn/issues/40690")]
......@@ -3070,83 +3055,125 @@ public void ConditionalAccess_GenericExtension_ValueTuple()
{
var source = @"
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace bug
public static class Extension
{
public static class Extension
{
public static String GetValue(this object value) => value?.ToString();
}
public partial class BGen<__T__>
{
public (Int64, __T__) Data { get; }
public BGen((Int64, __T__) data)
public static string GetValue(this object value) => value?.ToString();
}
public class Class<T>
{
public (long, T) Data { get; }
public Class((long, T) data)
{
this.Data = data;
Data = data;
}
internal String Value
internal string Value
{
get
{
/// This works fine:
//var i2 = Data.Item2;
//var q2 = i2?.GetValue();
// This causes the AccessViolation:
var q2 = Data.Item2?.GetValue();
return q2;
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(new Class<string>((0, ""abc"")).Value);
Console.WriteLine(new Class<string>((0, null)).Value);
Console.WriteLine(new Class<int>((0, 0)).Value);
Console.WriteLine(new Class<int?>((0, 0)).Value);
Console.WriteLine(new Class<int?>((0, null)).Value);
}
}";
var verifier = CompileAndVerify(source, expectedOutput: @"abc
class Program
{
static void Main(string[] args)
0
0
");
verifier.VerifyIL("Class<T>.Value.get", @"
{
// Code size 46 (0x2e)
.maxstack 2
.locals init (System.ValueTuple<long, T> V_0)
IL_0000: ldarg.0
IL_0001: call ""System.ValueTuple<long, T> Class<T>.Data.get""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: ldflda ""T System.ValueTuple<long, T>.Item2""
IL_000e: dup
IL_000f: ldobj ""T""
IL_0014: box ""T""
IL_0019: brtrue.s IL_001e
IL_001b: pop
IL_001c: ldnull
IL_001d: ret
IL_001e: ldobj ""T""
IL_0023: box ""T""
IL_0028: call ""string Extension.GetValue(object)""
IL_002d: ret
}");
}
[Fact, WorkItem(40690, "https://github.com/dotnet/roslyn/issues/40690")]
public void ConditionalAccess_InstanceMethod_ValueTuple()
{
var i = new BGen<string>((0, ""abc""));
var r = i.Value;
var source = @"
using System;
Console.Write(r);
public class Class<T>
{
public (long, T) Data { get; }
public Class((long, T) data)
{
Data = data;
}
internal string Value
{
get
{
var q2 = Data.Item2?.ToString();
return q2;
}
}
}
";
var verifier = CompileAndVerify(source, expectedOutput: "abc");
verifier.VerifyIL("bug.BGen<__T__>.Value.get", @"
class Program
{
static void Main(string[] args)
{
Console.WriteLine(new Class<string>((0, ""abc"")).Value);
Console.WriteLine(new Class<string>((0, null)).Value);
Console.WriteLine(new Class<int>((0, 0)).Value);
Console.WriteLine(new Class<int?>((0, 0)).Value);
Console.WriteLine(new Class<int?>((0, null)).Value);
}
}";
var verifier = CompileAndVerify(source, expectedOutput: @"abc
0
0
");
verifier.VerifyIL("Class<T>.Value.get", @"
{
// Code size 65 (0x41)
// Code size 42 (0x2a)
.maxstack 2
.locals init (System.ValueTuple<long, __T__> V_0,
__T__ V_1)
.locals init (System.ValueTuple<long, T> V_0)
IL_0000: ldarg.0
IL_0001: call ""System.ValueTuple<long, __T__> bug.BGen<__T__>.Data.get""
IL_0001: call ""System.ValueTuple<long, T> Class<T>.Data.get""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: ldflda ""__T__ System.ValueTuple<long, __T__>.Item2""
IL_000e: ldloca.s V_1
IL_0010: initobj ""__T__""
IL_0016: ldloc.1
IL_0017: box ""__T__""
IL_001c: brtrue.s IL_0031
IL_001e: ldobj ""__T__""
IL_0023: stloc.1
IL_0024: ldloca.s V_1
IL_0026: ldloc.1
IL_0027: box ""__T__""
IL_002c: brtrue.s IL_0031
IL_002e: pop
IL_002f: ldnull
IL_0030: ret
IL_0031: ldobj ""__T__""
IL_0036: box ""__T__""
IL_003b: call ""string bug.Extension.GetValue(object)""
IL_0040: ret
IL_0009: ldflda ""T System.ValueTuple<long, T>.Item2""
IL_000e: dup
IL_000f: ldobj ""T""
IL_0014: box ""T""
IL_0019: brtrue.s IL_001e
IL_001b: pop
IL_001c: ldnull
IL_001d: ret
IL_001e: constrained. ""T""
IL_0024: callvirt ""string object.ToString()""
IL_0029: ret
}");
}
}
......
......@@ -2463,49 +2463,34 @@ static void Main(string[] args)
False");
comp.VerifyIL("Program.Test<T>(System.Func<T>)", @"
{
// Code size 110 (0x6e)
// Code size 72 (0x48)
.maxstack 2
.locals init (T V_0,
T V_1)
.locals init (T V_0)
IL_0000: ldarg.0
IL_0001: callvirt ""T System.Func<T>.Invoke()""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
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
IL_0009: dup
IL_000a: ldobj ""T""
IL_000f: box ""T""
IL_0014: brtrue.s IL_0019
IL_0016: pop
IL_0017: br.s IL_0024
IL_0019: constrained. ""T""
IL_001f: callvirt ""void System.IDisposable.Dispose()""
IL_0024: ldarg.0
IL_0025: callvirt ""T System.Func<T>.Invoke()""
IL_002a: stloc.0
IL_002b: ldloca.s V_0
IL_002d: dup
IL_002e: ldobj ""T""
IL_0033: box ""T""
IL_0038: brtrue.s IL_003c
IL_003a: pop
IL_003b: ret
IL_003c: constrained. ""T""
IL_0042: callvirt ""void System.IDisposable.Dispose()""
IL_0047: ret
}
");
}
......
......@@ -426,14 +426,11 @@ .maxstack 3
).VerifyIL(
"<>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.ToString",
@"{
// Code size 199 (0xc7)
// Code size 138 (0x8a)
.maxstack 7
.locals init (<Length>j__TPar V_0,
<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)
<at1>j__TPar V_1,
<C>j__TPar V_2)
IL_0000: ldnull
IL_0001: ldstr ""{{ Length = {0}, at1 = {1}, C = {2} }}""
IL_0006: ldc.i4.3
......@@ -444,71 +441,50 @@ .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: 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
IL_0017: dup
IL_0018: ldobj ""<Length>j__TPar""
IL_001d: box ""<Length>j__TPar""
IL_0022: brtrue.s IL_0028
IL_0024: pop
IL_0025: ldnull
IL_0026: br.s IL_0033
IL_0028: constrained. ""<Length>j__TPar""
IL_002e: callvirt ""string object.ToString()""
IL_0033: stelem.ref
IL_0034: dup
IL_0035: ldc.i4.1
IL_0036: ldarg.0
IL_0037: ldfld ""<at1>j__TPar <>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.<at1>i__Field""
IL_003c: stloc.1
IL_003d: ldloca.s V_1
IL_003f: dup
IL_0040: ldobj ""<at1>j__TPar""
IL_0045: box ""<at1>j__TPar""
IL_004a: brtrue.s IL_0050
IL_004c: pop
IL_004d: ldnull
IL_004e: br.s IL_005b
IL_0050: constrained. ""<at1>j__TPar""
IL_0056: callvirt ""string object.ToString()""
IL_005b: stelem.ref
IL_005c: dup
IL_005d: ldc.i4.2
IL_005e: ldarg.0
IL_005f: ldfld ""<C>j__TPar <>f__AnonymousType1<<Length>j__TPar, <at1>j__TPar, <C>j__TPar>.<C>i__Field""
IL_0064: stloc.2
IL_0065: ldloca.s V_2
IL_0067: dup
IL_0068: ldobj ""<C>j__TPar""
IL_006d: box ""<C>j__TPar""
IL_0072: brtrue.s IL_0078
IL_0074: pop
IL_0075: ldnull
IL_0076: br.s IL_0083
IL_0078: constrained. ""<C>j__TPar""
IL_007e: callvirt ""string object.ToString()""
IL_0083: stelem.ref
IL_0084: call ""string string.Format(System.IFormatProvider, string, params object[])""
IL_0089: ret
}"
);
}
......@@ -875,14 +851,11 @@ .maxstack 3
).VerifyIL(
"<>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.ToString",
@"{
// Code size 199 (0xc7)
// Code size 138 (0x8a)
.maxstack 7
.locals init (<ToString>j__TPar V_0,
<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)
<Equals>j__TPar V_1,
<GetHashCode>j__TPar V_2)
IL_0000: ldnull
IL_0001: ldstr ""{{ ToString = {0}, Equals = {1}, GetHashCode = {2} }}""
IL_0006: ldc.i4.3
......@@ -893,71 +866,50 @@ .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: 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
IL_0017: dup
IL_0018: ldobj ""<ToString>j__TPar""
IL_001d: box ""<ToString>j__TPar""
IL_0022: brtrue.s IL_0028
IL_0024: pop
IL_0025: ldnull
IL_0026: br.s IL_0033
IL_0028: constrained. ""<ToString>j__TPar""
IL_002e: callvirt ""string object.ToString()""
IL_0033: stelem.ref
IL_0034: dup
IL_0035: ldc.i4.1
IL_0036: ldarg.0
IL_0037: ldfld ""<Equals>j__TPar <>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.<Equals>i__Field""
IL_003c: stloc.1
IL_003d: ldloca.s V_1
IL_003f: dup
IL_0040: ldobj ""<Equals>j__TPar""
IL_0045: box ""<Equals>j__TPar""
IL_004a: brtrue.s IL_0050
IL_004c: pop
IL_004d: ldnull
IL_004e: br.s IL_005b
IL_0050: constrained. ""<Equals>j__TPar""
IL_0056: callvirt ""string object.ToString()""
IL_005b: stelem.ref
IL_005c: dup
IL_005d: ldc.i4.2
IL_005e: ldarg.0
IL_005f: ldfld ""<GetHashCode>j__TPar <>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.<GetHashCode>i__Field""
IL_0064: stloc.2
IL_0065: ldloca.s V_2
IL_0067: dup
IL_0068: ldobj ""<GetHashCode>j__TPar""
IL_006d: box ""<GetHashCode>j__TPar""
IL_0072: brtrue.s IL_0078
IL_0074: pop
IL_0075: ldnull
IL_0076: br.s IL_0083
IL_0078: constrained. ""<GetHashCode>j__TPar""
IL_007e: callvirt ""string object.ToString()""
IL_0083: stelem.ref
IL_0084: call ""string string.Format(System.IFormatProvider, string, params object[])""
IL_0089: ret
}"
).VerifyIL(
"<>f__AnonymousType0<<ToString>j__TPar, <Equals>j__TPar, <GetHashCode>j__TPar>.ToString.get",
......
......@@ -290,9 +290,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
Dim nullCheckOnCopy = conditional.CaptureReceiver OrElse (receiverType.IsReferenceType AndAlso receiverType.TypeKind = TypeKind.TypeParameter)
If nullCheckOnCopy Then
EmitReceiverRef(receiver, isAccessConstrained:=Not receiverType.IsReferenceType, addressKind:=AddressKind.ReadOnly)
receiverTemp = 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
......@@ -316,9 +317,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
_builder.EmitLocalStore(temp)
_builder.EmitLocalAddress(temp)
_builder.EmitLocalLoad(temp)
EmitBox(receiver.Type, receiver.Syntax)
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.
' We currently have an adress on the stack. Duplicate it, and load the value of the address.
_builder.EmitOpCode(ILOpCode.Dup)
EmitLoadIndirect(receiverType, receiver.Syntax)
EmitBox(receiverType, receiver.Syntax)
End If
Else
_builder.EmitOpCode(ILOpCode.Dup)
' here we have loaded two copies of a reference { O, O }
......@@ -362,6 +372,7 @@ 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
......
......@@ -615,32 +615,24 @@ Null
verifier.VerifyIL("Module1.Test8",
<![CDATA[
{
// Code size 62 (0x3e)
// Code size 43 (0x2b)
.maxstack 2
.locals init (T V_0,
T V_1)
.locals init (T V_0)
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: 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
IL_0009: dup
IL_000a: ldobj "T"
IL_000f: box "T"
IL_0014: brtrue.s IL_001a
IL_0016: pop
IL_0017: ldnull
IL_0018: br.s IL_0025
IL_001a: constrained. "T"
IL_0020: callvirt "Function I1.get_P2() As String"
IL_0025: call "Sub Module1.Do(Of String)(String)"
IL_002a: ret
}
]]>)
......@@ -3554,30 +3546,22 @@ Ext4 C1
verifier.VerifyIL("Module1.Test1_6",
<![CDATA[
{
// Code size 54 (0x36)
// Code size 35 (0x23)
.maxstack 2
.locals init (T V_0,
T V_1)
.locals init (T V_0)
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: 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
IL_0009: dup
IL_000a: ldobj "T"
IL_000f: box "T"
IL_0014: brtrue.s IL_0018
IL_0016: pop
IL_0017: ret
IL_0018: ldobj "T"
IL_001d: call "Sub Module1.Ext1(Of T)(T)"
IL_0022: ret
}
]]>)
......@@ -5449,36 +5433,28 @@ hello")
c.VerifyIL("C(Of T).Print()",
<![CDATA[
{
// Code size 78 (0x4e)
// Code size 59 (0x3b)
.maxstack 2
.locals init (T V_0,
T V_1)
.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: 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 Object.ToString() As String"
IL_0038: call "Sub System.Console.WriteLine(String)"
IL_003d: ldarg.0
IL_003e: ldfld "C(Of T).field As T"
IL_0043: box "T"
IL_0048: call "Sub System.Console.WriteLine(Object)"
IL_004d: ret
IL_0009: dup
IL_000a: ldobj "T"
IL_000f: box "T"
IL_0014: brtrue.s IL_001a
IL_0016: pop
IL_0017: ldnull
IL_0018: br.s IL_0025
IL_001a: constrained. "T"
IL_0020: callvirt "Function Object.ToString() As String"
IL_0025: call "Sub System.Console.WriteLine(String)"
IL_002a: ldarg.0
IL_002b: ldfld "C(Of T).field As T"
IL_0030: box "T"
IL_0035: call "Sub System.Console.WriteLine(Object)"
IL_003a: ret
}
]]>)
End Sub
......@@ -5607,32 +5583,24 @@ hello
c.VerifyIL("C(Of T).Print()",
<![CDATA[
{
// Code size 62 (0x3e)
// Code size 43 (0x2b)
.maxstack 2
.locals init (T V_0,
T V_1)
.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: 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 Object.ToString() As String"
IL_0038: call "Sub System.Console.WriteLine(String)"
IL_003d: ret
IL_0009: dup
IL_000a: ldobj "T"
IL_000f: box "T"
IL_0014: brtrue.s IL_001a
IL_0016: pop
IL_0017: ldnull
IL_0018: br.s IL_0025
IL_001a: constrained. "T"
IL_0020: callvirt "Function Object.ToString() As String"
IL_0025: call "Sub System.Console.WriteLine(String)"
IL_002a: ret
}
]]>)
End Sub
......@@ -10215,10 +10183,9 @@ False
CompileAndVerify(compilationDef, options:=TestOptions.ReleaseExe, expectedOutput:=expectedOutput)
End Sub
<Fact()>
<WorkItem(40690, "https://github.com/dotnet/roslyn/issues/40690")>
Public Sub ConditionalAccess_GenericExtension_ValueTuple
Public Sub ConditionalAccess_GenericExtension_ValueTuple()
Dim compilationDef =
<compilation>
<file name="a.vb">
......@@ -10232,10 +10199,10 @@ Public Module Extensions
End Function
End Module
Public Class BGen(Of __T__)
Public ReadOnly Property Data As (Integer, __T__)
Public Class C(Of T)
Public ReadOnly Property Data As (Integer, T)
Public Sub New(data As (Integer, __T__))
Public Sub New(data As (Integer, T))
Me.Data = data
End Sub
......@@ -10245,57 +10212,126 @@ Public Class BGen(Of __T__)
End Get
End Property
End Class
Public Class Main
Public Shared Sub Main()
Console.WriteLine(New C(Of String)((0, "abc")).Value)
Console.WriteLine(New C(Of String)((0, Nothing)).Value)
Console.WriteLine(New C(Of Integer)((0, 0)).Value)
Console.WriteLine(New C(Of Integer?)((0, 0)).Value)
Console.WriteLine(New C(Of Integer?)((0, Nothing)).Value)
End Sub
End Class
</file>
</compilation>
Dim valueTupleRefs As MetadataReference() = New MetadataReference() {ValueTupleRef, SystemRuntimeFacadeRef}
Dim expectedOutput = "abc
0
0
"
Dim verifier = CompileAndVerify(
CreateCompilationWithMscorlib45AndVBRuntime(compilationDef, options:=TestOptions.DebugExe, references:=valueTupleRefs),
expectedOutput:=expectedOutput)
verifier.VerifyIL("C(Of T).get_Value()", "
{
// Code size 52 (0x34)
.maxstack 2
.locals init (String V_0, //Value
System.ValueTuple(Of Integer, T) V_1)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call ""Function C(Of T).get_Data() As (Integer, T)""
IL_0007: stloc.1
IL_0008: ldloca.s V_1
IL_000a: ldflda ""System.ValueTuple(Of Integer, T).Item2 As T""
IL_000f: dup
IL_0010: ldobj ""T""
IL_0015: box ""T""
IL_001a: brtrue.s IL_0020
IL_001c: pop
IL_001d: ldnull
IL_001e: br.s IL_002f
IL_0020: ldobj ""T""
IL_0025: box ""T""
IL_002a: call ""Function Extensions.GetValue(Object) As String""
IL_002f: stloc.0
IL_0030: br.s IL_0032
IL_0032: ldloc.0
IL_0033: ret
}")
End Sub
<Fact()>
<WorkItem(40690, "https://github.com/dotnet/roslyn/issues/40690")>
Public Sub ConditionalAccess_InstanceMethod_ValueTuple()
Dim compilationDef =
<compilation>
<file name="a.vb">
Imports System
Imports System.Runtime.CompilerServices
Public Class C(Of T)
Public ReadOnly Property Data As (Integer, T)
Public Sub New(data As (Integer, T))
Me.Data = data
End Sub
Public ReadOnly Property Value As String
Get
Return Data.Item2?.ToString()
End Get
End Property
End Class
Public Class Main
Public Shared Sub Main()
Dim i = New BGen(Of String)((0, "abc"))
Dim r = i.Value
Console.Write(r)
Console.WriteLine(New C(Of String)((0, "abc")).Value)
Console.WriteLine(New C(Of String)((0, Nothing)).Value)
Console.WriteLine(New C(Of Integer)((0, 0)).Value)
Console.WriteLine(New C(Of Integer?)((0, 0)).Value)
Console.WriteLine(New C(Of Integer?)((0, Nothing)).Value)
End Sub
End Class
</file>
</compilation>
Dim valueTupleRefs As MetadataReference() = New MetadataReference() {ValueTupleRef, SystemRuntimeFacadeRef}
Dim expectedOutput = "abc"
Dim expectedOutput = "abc
0
0
"
Dim verifier = CompileAndVerify(
CreateCompilationWithMscorlib45AndVBRuntime(compilationDef, options:=TestOptions.DebugExe, references:=valueTupleRefs),
expectedOutput:=expectedOutput)
verifier.VerifyIL("BGen(Of __T__).get_Value()", "
verifier.VerifyIL("C(Of T).get_Value()", "
{
// Code size 71 (0x47)
// Code size 48 (0x30)
.maxstack 2
.locals init (String V_0, //Value
System.ValueTuple(Of Integer, __T__) V_1,
__T__ V_2)
System.ValueTuple(Of Integer, T) V_1)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call ""Function BGen(Of __T__).get_Data() As (Integer, __T__)""
IL_0002: call ""Function C(Of T).get_Data() As (Integer, T)""
IL_0007: stloc.1
IL_0008: ldloca.s V_1
IL_000a: ldflda ""System.ValueTuple(Of Integer, __T__).Item2 As __T__""
IL_000f: ldloca.s V_2
IL_0011: initobj ""__T__""
IL_0017: ldloc.2
IL_0018: box ""__T__""
IL_001d: brtrue.s IL_0033
IL_001f: ldobj ""__T__""
IL_0024: stloc.2
IL_0025: ldloca.s V_2
IL_0027: ldloc.2
IL_0028: box ""__T__""
IL_002d: brtrue.s IL_0033
IL_002f: pop
IL_0030: ldnull
IL_0031: br.s IL_0042
IL_0033: ldobj ""__T__""
IL_0038: box ""__T__""
IL_003d: call ""Function Extensions.GetValue(Object) As String""
IL_0042: stloc.0
IL_0043: br.s IL_0045
IL_0045: ldloc.0
IL_0046: ret
IL_000a: ldflda ""System.ValueTuple(Of Integer, T).Item2 As T""
IL_000f: dup
IL_0010: ldobj ""T""
IL_0015: box ""T""
IL_001a: brtrue.s IL_0020
IL_001c: pop
IL_001d: ldnull
IL_001e: br.s IL_002b
IL_0020: constrained. ""T""
IL_0026: callvirt ""Function Object.ToString() As String""
IL_002b: stloc.0
IL_002c: br.s IL_002e
IL_002e: ldloc.0
IL_002f: ret
}")
End Sub
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册