提交 8cc19a0b 编写于 作者: A AlekseyTs

LambdaReturnInferenceCacheComparer should treat Dynamic and Object as different types.

Fixes #5363.
上级 baf1380c
......@@ -243,7 +243,8 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol>
considerTypeConstraints: false, // valid invoke is never generic
considerCallingConvention: false, // valid invoke is never static
considerRefOutDifference: true,
considerCustomModifiers: true);
considerCustomModifiers: true,
ignoreDynamic: false);
// Compare the "unqualified" part of the member name (no explicit part)
private readonly bool _considerName;
......@@ -266,6 +267,9 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol>
// Consider custom modifiers on/in parameters and return types (if return is considered).
private readonly bool _considerCustomModifiers;
// Ignore Object vs. Dynamic difference
private readonly bool _ignoreDynamic;
private MemberSignatureComparer(
bool considerName,
bool considerExplicitlyImplementedInterfaces,
......@@ -273,7 +277,8 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol>
bool considerTypeConstraints,
bool considerCallingConvention,
bool considerRefOutDifference,
bool considerCustomModifiers)
bool considerCustomModifiers,
bool ignoreDynamic = true)
{
Debug.Assert(!considerExplicitlyImplementedInterfaces || considerName, "Doesn't make sense to consider interfaces separately from name.");
......@@ -284,6 +289,7 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol>
_considerCallingConvention = considerCallingConvention;
_considerRefOutDifference = considerRefOutDifference;
_considerCustomModifiers = considerCustomModifiers;
_ignoreDynamic = ignoreDynamic;
}
#region IEqualityComparer<Symbol> Members
......@@ -328,12 +334,13 @@ public bool Equals(Symbol member1, Symbol member2)
var typeMap1 = GetTypeMap(member1);
var typeMap2 = GetTypeMap(member2);
if (_considerReturnType && !HaveSameReturnTypes(member1, typeMap1, member2, typeMap2, _considerCustomModifiers))
if (_considerReturnType && !HaveSameReturnTypes(member1, typeMap1, member2, typeMap2, _considerCustomModifiers, _ignoreDynamic))
{
return false;
}
if (member1.GetParameterCount() > 0 && !HaveSameParameterTypes(member1.GetParameters(), typeMap1, member2.GetParameters(), typeMap2, _considerRefOutDifference, _considerCustomModifiers))
if (member1.GetParameterCount() > 0 && !HaveSameParameterTypes(member1.GetParameters(), typeMap1, member2.GetParameters(), typeMap2,
_considerRefOutDifference, _considerCustomModifiers, _ignoreDynamic))
{
return false;
}
......@@ -426,10 +433,10 @@ public int GetHashCode(Symbol member)
public static bool HaveSameReturnTypes(MethodSymbol member1, MethodSymbol member2, bool considerCustomModifiers)
{
return HaveSameReturnTypes(member1, GetTypeMap(member1), member2, GetTypeMap(member2), considerCustomModifiers);
return HaveSameReturnTypes(member1, GetTypeMap(member1), member2, GetTypeMap(member2), considerCustomModifiers, ignoreDynamic: true);
}
private static bool HaveSameReturnTypes(Symbol member1, TypeMap typeMap1, Symbol member2, TypeMap typeMap2, bool considerCustomModifiers)
private static bool HaveSameReturnTypes(Symbol member1, TypeMap typeMap1, Symbol member2, TypeMap typeMap2, bool considerCustomModifiers, bool ignoreDynamic)
{
TypeSymbol unsubstitutedReturnType1;
ImmutableArray<CustomModifier> returnTypeCustomModifiers1;
......@@ -463,8 +470,8 @@ private static bool HaveSameReturnTypes(Symbol member1, TypeMap typeMap1, Symbol
// the runtime compares custom modifiers using (effectively) SequenceEqual
return considerCustomModifiers ?
returnType1.Equals(returnType2, ignoreDynamic: true) :
returnType1.Type.Equals(returnType2.Type, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: true);
returnType1.Equals(returnType2, ignoreDynamic: ignoreDynamic) :
returnType1.Type.Equals(returnType2.Type, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: ignoreDynamic);
}
private static TypeMap GetTypeMap(Symbol member)
......@@ -588,7 +595,8 @@ private static void SubstituteConstraintTypes(ImmutableArray<TypeSymbol> types,
}
}
private static bool HaveSameParameterTypes(ImmutableArray<ParameterSymbol> params1, TypeMap typeMap1, ImmutableArray<ParameterSymbol> params2, TypeMap typeMap2, bool considerRefOutDifference, bool considerCustomModifiers)
private static bool HaveSameParameterTypes(ImmutableArray<ParameterSymbol> params1, TypeMap typeMap1, ImmutableArray<ParameterSymbol> params2, TypeMap typeMap2,
bool considerRefOutDifference, bool considerCustomModifiers, bool ignoreDynamic)
{
Debug.Assert(params1.Length == params2.Length);
......@@ -605,12 +613,12 @@ private static bool HaveSameParameterTypes(ImmutableArray<ParameterSymbol> param
// the runtime compares custom modifiers using (effectively) SequenceEqual
if (considerCustomModifiers)
{
if (!type1.Equals(type2, ignoreDynamic: true) || (param1.CountOfCustomModifiersPrecedingByRef != param2.CountOfCustomModifiersPrecedingByRef))
if (!type1.Equals(type2, ignoreDynamic: ignoreDynamic) || (param1.CountOfCustomModifiersPrecedingByRef != param2.CountOfCustomModifiersPrecedingByRef))
{
return false;
}
}
else if (!type1.Type.Equals(type2.Type, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: true))
else if (!type1.Type.Equals(type2.Type, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: ignoreDynamic))
{
return false;
}
......
......@@ -13,7 +13,7 @@
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public partial class SyntaxBinderTests : CompilingTestBase
public partial class LambdaTests : CompilingTestBase
{
[Fact, WorkItem(608181, "DevDiv")]
public void BadInvocationInLambda()
......@@ -1320,5 +1320,81 @@ static void Main()
// Expression<Func<int, int>> x = y => y = y;
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "y = y").WithLocation(9, 45));
}
[Fact, WorkItem(5363, "https://github.com/dotnet/roslyn/issues/5363")]
public void ReturnInferenceCache_Dynamic_vs_Object_01()
{
var source =
@"
using System;
using System.Collections;
using System.Collections.Generic;
public static class Program
{
public static void Main(string[] args)
{
IEnumerable<dynamic> dynX = null;
// CS1061 'object' does not contain a definition for 'Text'...
// tooltip on 'var' shows IColumn instead of IEnumerable<dynamic>
var result = dynX.Select(_ => _.Text);
}
public static IColumn Select<TResult>(this IColumn source, Func<object, TResult> selector)
{
throw new NotImplementedException();
}
public static IEnumerable<S> Select<T, S>(this IEnumerable<T> source, Func<T, S> selector)
{
System.Console.WriteLine(""Select<T, S>"");
return null;
}
}
public interface IColumn { }
";
var compilation = CreateCompilationWithMscorlib(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.ReleaseExe);
CompileAndVerify(compilation, expectedOutput: "Select<T, S>");
}
[Fact, WorkItem(5363, "https://github.com/dotnet/roslyn/issues/5363")]
public void ReturnInferenceCache_Dynamic_vs_Object_02()
{
var source =
@"
using System;
using System.Collections;
using System.Collections.Generic;
public static class Program
{
public static void Main(string[] args)
{
IEnumerable<dynamic> dynX = null;
// CS1061 'object' does not contain a definition for 'Text'...
// tooltip on 'var' shows IColumn instead of IEnumerable<dynamic>
var result = dynX.Select(_ => _.Text);
}
public static IEnumerable<S> Select<T, S>(this IEnumerable<T> source, Func<T, S> selector)
{
System.Console.WriteLine(""Select<T, S>"");
return null;
}
public static IColumn Select<TResult>(this IColumn source, Func<object, TResult> selector)
{
throw new NotImplementedException();
}
}
public interface IColumn { }
";
var compilation = CreateCompilationWithMscorlib(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.ReleaseExe);
CompileAndVerify(compilation, expectedOutput: "Select<T, S>");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册