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

LambdaReturnInferenceCacheComparer should treat Dynamic and Object as different types.

Fixes #5363.
上级 baf1380c
...@@ -243,7 +243,8 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol> ...@@ -243,7 +243,8 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol>
considerTypeConstraints: false, // valid invoke is never generic considerTypeConstraints: false, // valid invoke is never generic
considerCallingConvention: false, // valid invoke is never static considerCallingConvention: false, // valid invoke is never static
considerRefOutDifference: true, considerRefOutDifference: true,
considerCustomModifiers: true); considerCustomModifiers: true,
ignoreDynamic: false);
// Compare the "unqualified" part of the member name (no explicit part) // Compare the "unqualified" part of the member name (no explicit part)
private readonly bool _considerName; private readonly bool _considerName;
...@@ -266,6 +267,9 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol> ...@@ -266,6 +267,9 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol>
// Consider custom modifiers on/in parameters and return types (if return is considered). // Consider custom modifiers on/in parameters and return types (if return is considered).
private readonly bool _considerCustomModifiers; private readonly bool _considerCustomModifiers;
// Ignore Object vs. Dynamic difference
private readonly bool _ignoreDynamic;
private MemberSignatureComparer( private MemberSignatureComparer(
bool considerName, bool considerName,
bool considerExplicitlyImplementedInterfaces, bool considerExplicitlyImplementedInterfaces,
...@@ -273,7 +277,8 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol> ...@@ -273,7 +277,8 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol>
bool considerTypeConstraints, bool considerTypeConstraints,
bool considerCallingConvention, bool considerCallingConvention,
bool considerRefOutDifference, bool considerRefOutDifference,
bool considerCustomModifiers) bool considerCustomModifiers,
bool ignoreDynamic = true)
{ {
Debug.Assert(!considerExplicitlyImplementedInterfaces || considerName, "Doesn't make sense to consider interfaces separately from name."); Debug.Assert(!considerExplicitlyImplementedInterfaces || considerName, "Doesn't make sense to consider interfaces separately from name.");
...@@ -284,6 +289,7 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol> ...@@ -284,6 +289,7 @@ internal class MemberSignatureComparer : IEqualityComparer<Symbol>
_considerCallingConvention = considerCallingConvention; _considerCallingConvention = considerCallingConvention;
_considerRefOutDifference = considerRefOutDifference; _considerRefOutDifference = considerRefOutDifference;
_considerCustomModifiers = considerCustomModifiers; _considerCustomModifiers = considerCustomModifiers;
_ignoreDynamic = ignoreDynamic;
} }
#region IEqualityComparer<Symbol> Members #region IEqualityComparer<Symbol> Members
...@@ -328,12 +334,13 @@ public bool Equals(Symbol member1, Symbol member2) ...@@ -328,12 +334,13 @@ public bool Equals(Symbol member1, Symbol member2)
var typeMap1 = GetTypeMap(member1); var typeMap1 = GetTypeMap(member1);
var typeMap2 = GetTypeMap(member2); var typeMap2 = GetTypeMap(member2);
if (_considerReturnType && !HaveSameReturnTypes(member1, typeMap1, member2, typeMap2, _considerCustomModifiers)) if (_considerReturnType && !HaveSameReturnTypes(member1, typeMap1, member2, typeMap2, _considerCustomModifiers, _ignoreDynamic))
{ {
return false; 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; return false;
} }
...@@ -426,10 +433,10 @@ public int GetHashCode(Symbol member) ...@@ -426,10 +433,10 @@ public int GetHashCode(Symbol member)
public static bool HaveSameReturnTypes(MethodSymbol member1, MethodSymbol member2, bool considerCustomModifiers) 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; TypeSymbol unsubstitutedReturnType1;
ImmutableArray<CustomModifier> returnTypeCustomModifiers1; ImmutableArray<CustomModifier> returnTypeCustomModifiers1;
...@@ -463,8 +470,8 @@ private static bool HaveSameReturnTypes(Symbol member1, TypeMap typeMap1, Symbol ...@@ -463,8 +470,8 @@ private static bool HaveSameReturnTypes(Symbol member1, TypeMap typeMap1, Symbol
// the runtime compares custom modifiers using (effectively) SequenceEqual // the runtime compares custom modifiers using (effectively) SequenceEqual
return considerCustomModifiers ? return considerCustomModifiers ?
returnType1.Equals(returnType2, ignoreDynamic: true) : returnType1.Equals(returnType2, ignoreDynamic: ignoreDynamic) :
returnType1.Type.Equals(returnType2.Type, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: true); returnType1.Type.Equals(returnType2.Type, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: ignoreDynamic);
} }
private static TypeMap GetTypeMap(Symbol member) private static TypeMap GetTypeMap(Symbol member)
...@@ -588,7 +595,8 @@ private static void SubstituteConstraintTypes(ImmutableArray<TypeSymbol> types, ...@@ -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); Debug.Assert(params1.Length == params2.Length);
...@@ -605,12 +613,12 @@ private static bool HaveSameParameterTypes(ImmutableArray<ParameterSymbol> param ...@@ -605,12 +613,12 @@ private static bool HaveSameParameterTypes(ImmutableArray<ParameterSymbol> param
// the runtime compares custom modifiers using (effectively) SequenceEqual // the runtime compares custom modifiers using (effectively) SequenceEqual
if (considerCustomModifiers) if (considerCustomModifiers)
{ {
if (!type1.Equals(type2, ignoreDynamic: true) || (param1.CountOfCustomModifiersPrecedingByRef != param2.CountOfCustomModifiersPrecedingByRef)) if (!type1.Equals(type2, ignoreDynamic: ignoreDynamic) || (param1.CountOfCustomModifiersPrecedingByRef != param2.CountOfCustomModifiersPrecedingByRef))
{ {
return false; 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; return false;
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
namespace Microsoft.CodeAnalysis.CSharp.UnitTests namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{ {
public partial class SyntaxBinderTests : CompilingTestBase public partial class LambdaTests : CompilingTestBase
{ {
[Fact, WorkItem(608181, "DevDiv")] [Fact, WorkItem(608181, "DevDiv")]
public void BadInvocationInLambda() public void BadInvocationInLambda()
...@@ -1320,5 +1320,81 @@ static void Main() ...@@ -1320,5 +1320,81 @@ static void Main()
// Expression<Func<int, int>> x = y => y = y; // Expression<Func<int, int>> x = y => y = y;
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "y = y").WithLocation(9, 45)); 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.
先完成此消息的编辑!
想要评论请 注册