提交 6401fb78 编写于 作者: V VSadov

Adjusted codegen for disposal of iterators to use constrained call with type parameters.

Even though there is no semantical difference between box/callvirt and constrained/callvirt here, we do not want to cause unnecessary boxing.

Compiler was handling this case correctly for structs, but missed the case of generic type parameters.
(old compiler did use constrained with generic type parameters as well)

Fixes #2111
上级 60775a62
......@@ -319,9 +319,9 @@ private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement n
/// <returns>A BoundExpression representing the call.</returns>
private BoundExpression SynthesizeCall(CSharpSyntaxNode syntax, BoundExpression receiver, MethodSymbol method, Conversion receiverConversion, TypeSymbol convertedReceiverType)
{
if (receiver.Type.TypeKind == TypeKind.Struct && method.ContainingType.IsInterface)
if (!receiver.Type.IsReferenceType && method.ContainingType.IsInterface)
{
Debug.Assert(receiverConversion.IsBoxing);
Debug.Assert(receiverConversion.IsImplicit && !receiverConversion.IsUserDefined);
// NOTE: The spec says that disposing of a struct enumerator won't cause any
// unnecessary boxing to occur. However, Dev10 extends this improvement to the
......
......@@ -1819,7 +1819,62 @@ .maxstack 1
");
}
[Fact]
[Fact, WorkItem(2094, "https://github.com/dotnet/roslyn/issues/2111")]
public void TestForEachValueTypeTypeParameterEnumeratorNoStruct()
{
var source = @"
using System.Collections.Generic;
class C<T> where T : IEnumerator<T>
{
void M()
{
foreach (var c in this) { }
}
public T GetEnumerator()
{
return default(T);
}
}
";
CompileAndVerify(source).VerifyIL("C<T>.M", @"
{
// Code size 63 (0x3f)
.maxstack 1
.locals init (T V_0)
IL_0000: ldarg.0
IL_0001: call ""T C<T>.GetEnumerator()""
IL_0006: stloc.0
.try
{
IL_0007: br.s IL_0017
IL_0009: ldloca.s V_0
IL_000b: constrained. ""T""
IL_0011: callvirt ""T System.Collections.Generic.IEnumerator<T>.Current.get""
IL_0016: pop
IL_0017: ldloca.s V_0
IL_0019: constrained. ""T""
IL_001f: callvirt ""bool System.Collections.IEnumerator.MoveNext()""
IL_0024: brtrue.s IL_0009
IL_0026: leave.s IL_003e
}
finally
{
IL_0028: ldloc.0
IL_0029: box ""T""
IL_002e: brfalse.s IL_003d
IL_0030: ldloca.s V_0
IL_0032: constrained. ""T""
IL_0038: callvirt ""void System.IDisposable.Dispose()""
IL_003d: endfinally
}
IL_003e: ret
}
");
}
[Fact, WorkItem(2094, "https://github.com/dotnet/roslyn/issues/2111")]
public void TestForEachValueTypeTypeParameterEnumerator()
{
var source = @"
......@@ -1842,7 +1897,7 @@ public T GetEnumerator()
// CONSIDER: Dev10 does have a null check, but it seems unnecessary.
CompileAndVerify(source).VerifyIL("C<T>.M", @"
{
// Code size 53 (0x35)
// Code size 55 (0x37)
.maxstack 1
.locals init (T V_0)
IL_0000: ldarg.0
......@@ -1859,16 +1914,16 @@ .locals init (T V_0)
IL_0019: constrained. ""T""
IL_001f: callvirt ""bool System.Collections.IEnumerator.MoveNext()""
IL_0024: brtrue.s IL_0009
IL_0026: leave.s IL_0034
IL_0026: leave.s IL_0036
}
finally
{
IL_0028: ldloc.0
IL_0029: box ""T""
IL_002e: callvirt ""void System.IDisposable.Dispose()""
IL_0033: endfinally
IL_0028: ldloca.s V_0
IL_002a: constrained. ""T""
IL_0030: callvirt ""void System.IDisposable.Dispose()""
IL_0035: endfinally
}
IL_0034: ret
IL_0036: ret
}
");
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册