未验证 提交 04cca4ae 编写于 作者: J Julien Couvreur 提交者: GitHub

Merge pull request #35664 from gafter/dev16.1-35584

Fix bug where pattern-matching treats a type parameter as if it is a reference (which it might not be)
......@@ -176,9 +176,11 @@ void addArg(RefKind refKind, BoundExpression expression)
case BoundDagTypeEvaluation t:
{
TypeSymbol inputType = input.Type;
if (inputType.IsDynamic() || inputType.ContainsTypeParameter())
if (inputType.IsDynamic())
{
// Avoid using dynamic conversions for pattern-matching.
inputType = _factory.SpecialType(SpecialType.System_Object);
input = _factory.Convert(inputType, input);
}
TypeSymbol type = t.Type;
......@@ -335,20 +337,38 @@ private BoundExpression MakeEqual(BoundExpression loweredLiteral, BoundExpressio
out BoundExpression sideEffect,
out BoundExpression testExpression)
{
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
// case 1: type test followed by cast to that type
if (test is BoundDagTypeTest typeDecision &&
evaluation is BoundDagTypeEvaluation typeEvaluation &&
evaluation is BoundDagTypeEvaluation typeEvaluation1 &&
typeDecision.Type.IsReferenceType &&
typeEvaluation.Type.Equals(typeDecision.Type, TypeCompareKind.AllIgnoreOptions) &&
typeEvaluation.Input == typeDecision.Input
)
typeEvaluation1.Type.Equals(typeDecision.Type, TypeCompareKind.AllIgnoreOptions) &&
typeEvaluation1.Input == typeDecision.Input)
{
BoundExpression input = _tempAllocator.GetTemp(test.Input);
BoundExpression output = _tempAllocator.GetTemp(new BoundDagTemp(evaluation.Syntax, typeEvaluation.Type, evaluation));
sideEffect = _factory.AssignmentExpression(output, _factory.As(input, typeEvaluation.Type));
BoundExpression output = _tempAllocator.GetTemp(new BoundDagTemp(evaluation.Syntax, typeEvaluation1.Type, evaluation));
sideEffect = _factory.AssignmentExpression(output, _factory.As(input, typeEvaluation1.Type));
testExpression = _factory.ObjectNotEqual(output, _factory.Null(output.Type));
return true;
}
// case 2: null check followed by cast to a base type
if (test is BoundDagNonNullTest nonNullTest &&
evaluation is BoundDagTypeEvaluation typeEvaluation2 &&
_factory.Compilation.Conversions.ClassifyBuiltInConversion(test.Input.Type, typeEvaluation2.Type, ref useSiteDiagnostics) is Conversion conv &&
(conv.IsIdentity || conv.Kind == ConversionKind.ImplicitReference || conv.IsBoxing) &&
typeEvaluation2.Input == nonNullTest.Input)
{
BoundExpression input = _tempAllocator.GetTemp(test.Input);
var baseType = typeEvaluation2.Type;
BoundExpression output = _tempAllocator.GetTemp(new BoundDagTemp(evaluation.Syntax, baseType, evaluation));
sideEffect = _factory.AssignmentExpression(output, _factory.Convert(baseType, input));
testExpression = _factory.ObjectNotEqual(output, _factory.Null(baseType));
_localRewriter._diagnostics.Add(test.Syntax, useSiteDiagnostics);
return true;
}
sideEffect = testExpression = null;
return false;
}
......
......@@ -1544,21 +1544,23 @@ .maxstack 2
}");
compVerifier.VerifyIL("Program.Test2<T>(T)",
@"{
// Code size 30 (0x1e)
// Code size 35 (0x23)
.maxstack 2
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: isinst ""int""
IL_000b: brfalse.s IL_001c
IL_000b: brfalse.s IL_0021
IL_000d: ldarg.0
IL_000e: box ""T""
IL_0013: unbox.any ""int""
IL_0018: ldc.i4.0
IL_0019: ceq
IL_001b: ret
IL_001c: ldc.i4.0
IL_001d: ret
}");
IL_0013: isinst ""int""
IL_0018: unbox.any ""int""
IL_001d: ldc.i4.0
IL_001e: ceq
IL_0020: ret
IL_0021: ldc.i4.0
IL_0022: ret
}
");
compVerifier.VerifyIL("Program.Test3<T>(T)",
@"{
// Code size 29 (0x1d)
......@@ -1598,21 +1600,23 @@ static bool Test(S s)
var compVerifier = CompileAndVerify(compilation);
compVerifier.VerifyIL("C<T>.Test(C<T>.S)",
@"{
// Code size 30 (0x1e)
// Code size 35 (0x23)
.maxstack 2
IL_0000: ldarg.0
IL_0001: box ""C<T>.S""
IL_0006: isinst ""int""
IL_000b: brfalse.s IL_001c
IL_000b: brfalse.s IL_0021
IL_000d: ldarg.0
IL_000e: box ""C<T>.S""
IL_0013: unbox.any ""int""
IL_0018: ldc.i4.1
IL_0019: ceq
IL_001b: ret
IL_001c: ldc.i4.0
IL_001d: ret
}");
IL_0013: isinst ""int""
IL_0018: unbox.any ""int""
IL_001d: ldc.i4.1
IL_001e: ceq
IL_0020: ret
IL_0021: ldc.i4.0
IL_0022: ret
}
");
}
[Fact]
......@@ -2385,5 +2389,212 @@ .locals init (bool V_0)
}
}
}
[Fact, WorkItem(35584, "https://github.com/dotnet/roslyn/issues/35584")]
public void MatchToTypeParameterUnbox_01()
{
var source = @"
class Program
{
public static void Main() => System.Console.WriteLine(P<int>(0));
public static string P<T>(T t) => (t is object o) ? o.ToString() : string.Empty;
}
";
var expectedOutput = @"0";
foreach (var options in new[] { TestOptions.DebugExe, TestOptions.ReleaseExe })
{
var compilation = CreateCompilation(source, options: options);
compilation.VerifyDiagnostics();
var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
if (options.OptimizationLevel == OptimizationLevel.Debug)
{
compVerifier.VerifyIL("Program.P<T>",
@"{
// Code size 24 (0x18)
.maxstack 1
.locals init (object V_0) //o
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brtrue.s IL_0011
IL_000a: ldsfld ""string string.Empty""
IL_000f: br.s IL_0017
IL_0011: ldloc.0
IL_0012: callvirt ""string object.ToString()""
IL_0017: ret
}
");
}
else
{
compVerifier.VerifyIL("Program.P<T>",
@"{
// Code size 23 (0x17)
.maxstack 1
.locals init (object V_0) //o
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brtrue.s IL_0010
IL_000a: ldsfld ""string string.Empty""
IL_000f: ret
IL_0010: ldloc.0
IL_0011: callvirt ""string object.ToString()""
IL_0016: ret
}
");
}
}
}
[Fact, WorkItem(35584, "https://github.com/dotnet/roslyn/issues/35584")]
public void MatchToTypeParameterUnbox_02()
{
var source =
@"using System;
class Program
{
public static void Main()
{
var generic = new Generic<int>(0);
}
}
public class Generic<T>
{
public Generic(T value)
{
if (value is object obj && obj == null)
{
throw new Exception(""Kaboom!"");
}
}
}
";
var expectedOutput = @"";
foreach (var options in new[] { TestOptions.DebugExe, TestOptions.ReleaseExe })
{
var compilation = CreateCompilation(source, options: options);
compilation.VerifyDiagnostics();
var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
if (options.OptimizationLevel == OptimizationLevel.Debug)
{
compVerifier.VerifyIL("Generic<T>..ctor(T)",
@"{
// Code size 42 (0x2a)
.maxstack 2
.locals init (object V_0, //obj
bool V_1)
IL_0000: ldarg.0
IL_0001: call ""object..ctor()""
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.1
IL_0009: box ""T""
IL_000e: stloc.0
IL_000f: ldloc.0
IL_0010: brfalse.s IL_0018
IL_0012: ldloc.0
IL_0013: ldnull
IL_0014: ceq
IL_0016: br.s IL_0019
IL_0018: ldc.i4.0
IL_0019: stloc.1
IL_001a: ldloc.1
IL_001b: brfalse.s IL_0029
IL_001d: nop
IL_001e: ldstr ""Kaboom!""
IL_0023: newobj ""System.Exception..ctor(string)""
IL_0028: throw
IL_0029: ret
}
");
}
else
{
compVerifier.VerifyIL("Generic<T>..ctor(T)",
@"{
// Code size 31 (0x1f)
.maxstack 1
.locals init (object V_0) //obj
IL_0000: ldarg.0
IL_0001: call ""object..ctor()""
IL_0006: ldarg.1
IL_0007: box ""T""
IL_000c: stloc.0
IL_000d: ldloc.0
IL_000e: brfalse.s IL_001e
IL_0010: ldloc.0
IL_0011: brtrue.s IL_001e
IL_0013: ldstr ""Kaboom!""
IL_0018: newobj ""System.Exception..ctor(string)""
IL_001d: throw
IL_001e: ret
}
");
}
}
}
[Fact, WorkItem(35584, "https://github.com/dotnet/roslyn/issues/35584")]
public void MatchToTypeParameterUnbox_03()
{
var source =
@"using System;
class Program
{
public static void Main() => System.Console.WriteLine(P<Enum>(null));
public static string P<T>(T t) where T: Enum => (t is ValueType o) ? o.ToString() : ""1"";
}
";
var expectedOutput = @"1";
foreach (var options in new[] { TestOptions.DebugExe, TestOptions.ReleaseExe })
{
var compilation = CreateCompilation(source, options: options);
compilation.VerifyDiagnostics();
var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
if (options.OptimizationLevel == OptimizationLevel.Debug)
{
compVerifier.VerifyIL("Program.P<T>",
@"{
// Code size 24 (0x18)
.maxstack 1
.locals init (System.ValueType V_0) //o
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brtrue.s IL_0011
IL_000a: ldstr ""1""
IL_000f: br.s IL_0017
IL_0011: ldloc.0
IL_0012: callvirt ""string object.ToString()""
IL_0017: ret
}
");
}
else
{
compVerifier.VerifyIL("Program.P<T>",
@"{
// Code size 23 (0x17)
.maxstack 1
.locals init (System.ValueType V_0) //o
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brtrue.s IL_0010
IL_000a: ldstr ""1""
IL_000f: ret
IL_0010: ldloc.0
IL_0011: callvirt ""string object.ToString()""
IL_0016: ret
}
");
}
}
}
}
}
......@@ -7899,23 +7899,26 @@ public static void M(int? x)
expectedOutput: "1");
compVerifier.VerifyIL("Program.M",
@"{
// Code size 21 (0x15)
// Code size 17 (0x11)
.maxstack 1
IL_0000: ldarga.s V_0
IL_0002: call ""bool int?.HasValue.get""
IL_0007: brfalse.s IL_0014
IL_0009: ldarg.0
IL_000a: box ""int?""
IL_000f: call ""void System.Console.Write(object)""
IL_0014: ret
}"
.locals init (System.IComparable V_0) //i
IL_0000: ldarg.0
IL_0001: box ""int?""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0010
IL_000a: ldloc.0
IL_000b: call ""void System.Console.Write(object)""
IL_0010: ret
}
"
);
compVerifier = CompileAndVerify(source,
options: TestOptions.DebugDll.WithOutputKind(OutputKind.ConsoleApplication),
expectedOutput: "1");
compVerifier.VerifyIL("Program.M",
@"{
// Code size 35 (0x23)
// Code size 29 (0x1d)
.maxstack 1
.locals init (System.IComparable V_0, //i
int? V_1,
......@@ -7925,20 +7928,20 @@ .maxstack 1
IL_0002: stloc.2
IL_0003: ldloc.2
IL_0004: stloc.1
IL_0005: ldloca.s V_1
IL_0007: call ""bool int?.HasValue.get""
IL_000c: brfalse.s IL_0022
IL_000e: ldloc.1
IL_000f: box ""int?""
IL_0014: stloc.0
IL_0015: br.s IL_0017
IL_0017: br.s IL_0019
IL_0019: ldloc.0
IL_001a: call ""void System.Console.Write(object)""
IL_001f: nop
IL_0020: br.s IL_0022
IL_0022: ret
}"
IL_0005: ldloc.1
IL_0006: box ""int?""
IL_000b: stloc.0
IL_000c: ldloc.0
IL_000d: brtrue.s IL_0011
IL_000f: br.s IL_001c
IL_0011: br.s IL_0013
IL_0013: ldloc.0
IL_0014: call ""void System.Console.Write(object)""
IL_0019: nop
IL_001a: br.s IL_001c
IL_001c: ret
}
"
);
}
......@@ -8478,39 +8481,43 @@ public static int M2<T>(T o)
expectedOutput: "2300");
compVerifier.VerifyIL("Program.M1<T>",
@"{
// Code size 31 (0x1f)
// Code size 36 (0x24)
.maxstack 1
.locals init (int V_0) //t
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: isinst ""int""
IL_000b: brfalse.s IL_001b
IL_000b: brfalse.s IL_0020
IL_000d: ldarg.0
IL_000e: box ""T""
IL_0013: unbox.any ""int""
IL_0018: stloc.0
IL_0019: br.s IL_001d
IL_001b: ldc.i4.0
IL_001c: ret
IL_001d: ldloc.0
IL_001e: ret
}"
IL_0013: isinst ""int""
IL_0018: unbox.any ""int""
IL_001d: stloc.0
IL_001e: br.s IL_0022
IL_0020: ldc.i4.0
IL_0021: ret
IL_0022: ldloc.0
IL_0023: ret
}
"
);
compVerifier.VerifyIL("Program.M2<T>",
@"{
// Code size 27 (0x1b)
// Code size 32 (0x20)
.maxstack 1
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: isinst ""int""
IL_000b: brfalse.s IL_0019
IL_000b: brfalse.s IL_001e
IL_000d: ldarg.0
IL_000e: box ""T""
IL_0013: unbox.any ""int""
IL_0018: ret
IL_0019: ldc.i4.0
IL_001a: ret
}"
IL_0013: isinst ""int""
IL_0018: unbox.any ""int""
IL_001d: ret
IL_001e: ldc.i4.0
IL_001f: ret
}
"
);
compVerifier = CompileAndVerify(source,
options: TestOptions.DebugDll.WithOutputKind(OutputKind.ConsoleApplication),
......@@ -8518,7 +8525,7 @@ .maxstack 1
expectedOutput: "2300");
compVerifier.VerifyIL("Program.M1<T>",
@"{
// Code size 37 (0x25)
// Code size 42 (0x2a)
.maxstack 1
.locals init (int V_0, //t
int V_1)
......@@ -8526,24 +8533,26 @@ .maxstack 1
IL_0001: ldarg.0
IL_0002: box ""T""
IL_0007: isinst ""int""
IL_000c: brfalse.s IL_001c
IL_000c: brfalse.s IL_0021
IL_000e: ldarg.0
IL_000f: box ""T""
IL_0014: unbox.any ""int""
IL_0019: stloc.0
IL_001a: br.s IL_001f
IL_001c: ldc.i4.0
IL_001d: br.s IL_0020
IL_001f: ldloc.0
IL_0020: stloc.1
IL_0021: br.s IL_0023
IL_0023: ldloc.1
IL_0024: ret
}"
IL_0014: isinst ""int""
IL_0019: unbox.any ""int""
IL_001e: stloc.0
IL_001f: br.s IL_0024
IL_0021: ldc.i4.0
IL_0022: br.s IL_0025
IL_0024: ldloc.0
IL_0025: stloc.1
IL_0026: br.s IL_0028
IL_0028: ldloc.1
IL_0029: ret
}
"
);
compVerifier.VerifyIL("Program.M2<T>",
@"{
// Code size 44 (0x2c)
// Code size 49 (0x31)
.maxstack 1
.locals init (int V_0, //t
T V_1,
......@@ -8557,22 +8566,24 @@ .maxstack 1
IL_0005: ldloc.1
IL_0006: box ""T""
IL_000b: isinst ""int""
IL_0010: brfalse.s IL_0026
IL_0010: brfalse.s IL_002b
IL_0012: ldloc.1
IL_0013: box ""T""
IL_0018: unbox.any ""int""
IL_001d: stloc.0
IL_001e: br.s IL_0020
IL_0020: br.s IL_0022
IL_0022: ldloc.0
IL_0023: stloc.3
IL_0024: br.s IL_002a
IL_0026: ldc.i4.0
IL_0027: stloc.3
IL_0028: br.s IL_002a
IL_002a: ldloc.3
IL_002b: ret
}"
IL_0018: isinst ""int""
IL_001d: unbox.any ""int""
IL_0022: stloc.0
IL_0023: br.s IL_0025
IL_0025: br.s IL_0027
IL_0027: ldloc.0
IL_0028: stloc.3
IL_0029: br.s IL_002f
IL_002b: ldc.i4.0
IL_002c: stloc.3
IL_002d: br.s IL_002f
IL_002f: ldloc.3
IL_0030: ret
}
"
);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册