Skip to content

Commit

Permalink
Fix for dotnet#20226
Browse files Browse the repository at this point in the history
  • Loading branch information
VSadov committed Jun 17, 2017
1 parent 2faad6f commit ef29793
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 12 deletions.
15 changes: 12 additions & 3 deletions src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -326,12 +326,12 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
ImmutableArray<MethodSymbol> originalUserDefinedConversions = elementConversion.OriginalUserDefinedConversions;
if (originalUserDefinedConversions.Length > 1)
{
diagnostics.Add(ErrorCode.ERR_AmbigUDConv, _syntax.ForEachKeyword.GetLocation(), originalUserDefinedConversions[0], originalUserDefinedConversions[1], inferredType, iterationVariableType);
diagnostics.Add(ErrorCode.ERR_AmbigUDConv, foreachKeyword.GetLocation(), originalUserDefinedConversions[0], originalUserDefinedConversions[1], inferredType, iterationVariableType);
}
else
{
SymbolDistinguisher distinguisher = new SymbolDistinguisher(this.Compilation, inferredType, iterationVariableType);
diagnostics.Add(ErrorCode.ERR_NoExplicitConv, _syntax.ForEachKeyword.GetLocation(), distinguisher.First, distinguisher.Second);
diagnostics.Add(ErrorCode.ERR_NoExplicitConv, foreachKeyword.GetLocation(), distinguisher.First, distinguisher.Second);
}
hasErrors = true;
}
Expand All @@ -346,7 +346,16 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
builder.CollectionConversion = this.Conversions.ClassifyConversionFromExpression(collectionExpr, builder.CollectionType, ref useSiteDiagnostics);
builder.CurrentConversion = this.Conversions.ClassifyConversionFromType(builder.CurrentPropertyGetter.ReturnType, builder.ElementType, ref useSiteDiagnostics);

builder.EnumeratorConversion = this.Conversions.ClassifyConversionFromType(builder.GetEnumeratorMethod.ReturnType, GetSpecialType(SpecialType.System_Object, diagnostics, _syntax), ref useSiteDiagnostics);
var getEnumeratorType = builder.GetEnumeratorMethod.ReturnType;
// we never convert struct enumerators to object - it is done only for null-checks.
builder.EnumeratorConversion = getEnumeratorType.IsValueType?
Conversion.Identity:
this.Conversions.ClassifyConversionFromType(builder.GetEnumeratorMethod.ReturnType, GetSpecialType(SpecialType.System_Object, diagnostics, _syntax), ref useSiteDiagnostics);

if (getEnumeratorType.IsRestrictedType() && (IsDirectlyInIterator || IsInAsyncMethod()))
{
diagnostics.Add(ErrorCode.ERR_BadSpecialByRefIterator, foreachKeyword.GetLocation(), builder.CollectionType);
}

diagnostics.Add(_syntax.ForEachKeyword.GetLocation(), useSiteDiagnostics);

Expand Down
9 changes: 9 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -3617,6 +3617,9 @@ Give the compiler some way to differentiate the methods. For example, you can gi
<data name="ERR_BadSpecialByRefLocal" xml:space="preserve">
<value>Parameters or locals of type '{0}' cannot be declared in async methods or lambda expressions.</value>
</data>
<data name="ERR_BadSpecialByRefIterator" xml:space="preserve">
<value>foreach statement cannot operate on variables of type '{0}' in async or iterator methods.</value>
</data>
<data name="ERR_SecurityCriticalOrSecuritySafeCriticalOnAsync" xml:space="preserve">
<value>Security attribute '{0}' cannot be applied to an Async method.</value>
</data>
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1514,5 +1514,7 @@ internal enum ErrorCode
ERR_AutoPropsInRoStruct = 8515,
ERR_FieldlikeEventsInRoStruct = 8516,
ERR_RefStructInterfaceImpl = 8517,
ERR_BadSpecialByRefIterator = 8518,

}
}
15 changes: 6 additions & 9 deletions src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1319,7 +1319,7 @@ struct Enumerator
Assert.False(info.NeedsDisposeMethod); // Definitely not disposable
Assert.Equal(ConversionKind.Identity, info.CollectionConversion.Kind);
Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
Assert.Equal(ConversionKind.Boxing, info.EnumeratorConversion.Kind);
Assert.Equal(ConversionKind.Identity, info.EnumeratorConversion.Kind);

Assert.Equal(ConversionKind.ImplicitNumeric, boundNode.ElementConversion.Kind);
Assert.Equal("System.Int64 x", boundNode.IterationVariables.Single().ToTestDisplayString());
Expand Down Expand Up @@ -1847,7 +1847,7 @@ struct Enumerator
Assert.False(info.NeedsDisposeMethod); // Definitely not disposable
Assert.Equal(ConversionKind.Identity, info.CollectionConversion.Kind);
Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
Assert.Equal(ConversionKind.Boxing, info.EnumeratorConversion.Kind);
Assert.Equal(ConversionKind.Identity, info.EnumeratorConversion.Kind);

Assert.Equal(ConversionKind.ImplicitNumeric, boundNode.ElementConversion.Kind);
Assert.Equal("System.Int64 x", boundNode.IterationVariables.Single().ToTestDisplayString());
Expand Down Expand Up @@ -3188,13 +3188,10 @@ static void Main()

var comp4 = CreateCompilation(source4, new[] { comp2.ToMetadataReference(), comp3.ToMetadataReference() });
comp4.VerifyDiagnostics(
// (6,9): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'MissingBaseType1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
// foreach (var x in new Enumerable())
Diagnostic(ErrorCode.ERR_NoTypeDef, @"foreach (var x in new Enumerable())
{ }").WithArguments("System.ValueType", "MissingBaseType1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 9),
// (6,9): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'MissingBaseType1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
// foreach (var x in new Enumerable())
Diagnostic(ErrorCode.ERR_NoTypeDef, "foreach").WithArguments("System.ValueType", "MissingBaseType1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 9)
// (6,9): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'MissingBaseType1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
// foreach (var x in new Enumerable())
Diagnostic(ErrorCode.ERR_NoTypeDef, @"foreach (var x in new Enumerable())
{ }").WithArguments("System.ValueType", "MissingBaseType1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 9)
);
}
}
Expand Down
128 changes: 128 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,134 @@ public void Dispose() { }
);
}

[WorkItem(20226, "https://github.com/dotnet/roslyn/issues/20226")]
[Fact]
public void RefIteratorInAsync()
{
var text = @"
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
}
static async Task<int> Test()
{
var obj = new C1();
foreach (var i in obj)
{
await Task.Yield();
System.Console.WriteLine(i);
}
return 123;
}
}
class C1
{
public S1 GetEnumerator()
{
return new S1();
}
public ref struct S1
{
public int Current => throw new NotImplementedException();
public bool MoveNext()
{
throw new NotImplementedException();
}
}
}
";

CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);

comp.VerifyDiagnostics(
// (15,9): error CS8518: foreach statement cannot operate on variables of type 'C1' in async or iterator methods.
// foreach (var i in obj)
Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C1").WithLocation(15, 9)
);
}

[WorkItem(20226, "https://github.com/dotnet/roslyn/issues/20226")]
[Fact]
public void RefIteratorInIterator()
{
var text = @"
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
// this is valid
Action a = () =>
{
foreach (var i in new C1())
{
}
};
a();
}
static IEnumerable<int> Test()
{
// this is valid
Action a = () =>
{
foreach (var i in new C1())
{
}
};
a();
// this is an error
foreach (var i in new C1())
{
}
yield return 1;
}
}
class C1
{
public S1 GetEnumerator()
{
return new S1();
}
public ref struct S1
{
public int Current => throw new NotImplementedException();
public bool MoveNext()
{
throw new NotImplementedException();
}
}
}
";

CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);

comp.VerifyDiagnostics(
// (33,9): error CS8518: foreach statement cannot operate on variables of type 'C1' in async or iterator methods.
// foreach (var i in new C1())
Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C1").WithLocation(33, 9)
);
}

[Fact]
public void Properties()
Expand Down

0 comments on commit ef29793

Please sign in to comment.