未验证 提交 d844b500 编写于 作者: V Vladimir Sadov 提交者: GitHub

Merge pull request #23397 from VSadov/mGroupConv

Making sure that "in" matches exactly in method group conversions.
......@@ -748,10 +748,11 @@ internal bool MethodGroupIsCompatibleWithDelegate(BoundExpression receiverOpt, b
for (int i = 0; i < numParams; i++)
{
var delegateParameterType = delegateParameters[i].Type;
var methodParameterType = methodParameters[isExtensionMethod ? i + 1 : i].Type;
var delegateParameter = delegateParameters[i];
var methodParameter = methodParameters[isExtensionMethod ? i + 1 : i];
if (!Conversions.HasIdentityOrImplicitReferenceConversion(delegateParameterType, methodParameterType, ref useSiteDiagnostics))
if (delegateParameter.RefKind != methodParameter.RefKind ||
!Conversions.HasIdentityOrImplicitReferenceConversion(delegateParameter.Type, methodParameter.Type, ref useSiteDiagnostics))
{
// No overload for '{0}' matches delegate '{1}'
Error(diagnostics, ErrorCode.ERR_MethDelegateMismatch, errorLocation, method, delegateType);
......@@ -760,14 +761,14 @@ internal bool MethodGroupIsCompatibleWithDelegate(BoundExpression receiverOpt, b
}
}
if (delegateMethod.ReturnsByRef != method.ReturnsByRef)
if (delegateMethod.RefKind != method.RefKind)
{
Error(diagnostics, ErrorCode.ERR_DelegateRefMismatch, errorLocation, method, delegateType);
diagnostics.Add(errorLocation, useSiteDiagnostics);
return false;
}
bool returnsMatch = delegateMethod.ReturnsByRef?
bool returnsMatch = delegateMethod.RefKind != RefKind.None ?
// - Return types identity-convertible
Conversions.HasIdentityConversion(method.ReturnType, delegateMethod.ReturnType):
// - Return types "match"
......
......@@ -356,7 +356,13 @@ private static bool OverloadResolutionResultIsValid<TMember>(ArrayBuilder<Member
return MemberAnalysisResult.UseSiteError();
}
var effectiveParameters = GetEffectiveParametersInNormalForm(constructor, arguments.Arguments.Count, argumentAnalysis.ArgsToParamsOpt, arguments.RefKinds, allowRefOmittedArguments: false);
var effectiveParameters = GetEffectiveParametersInNormalForm(
constructor,
arguments.Arguments.Count,
argumentAnalysis.ArgsToParamsOpt,
arguments.RefKinds,
isMethodGroupConversion: false,
allowRefOmittedArguments: false);
return IsApplicable(
constructor,
......@@ -388,7 +394,13 @@ private static bool OverloadResolutionResultIsValid<TMember>(ArrayBuilder<Member
return MemberAnalysisResult.UseSiteError();
}
var effectiveParameters = GetEffectiveParametersInExpandedForm(constructor, arguments.Arguments.Count, argumentAnalysis.ArgsToParamsOpt, arguments.RefKinds, allowRefOmittedArguments: false);
var effectiveParameters = GetEffectiveParametersInExpandedForm(
constructor,
arguments.Arguments.Count,
argumentAnalysis.ArgsToParamsOpt,
arguments.RefKinds,
isMethodGroupConversion: false,
allowRefOmittedArguments: false);
// A vararg ctor is never applicable in its expanded form because
// it is never a params method.
......@@ -2503,11 +2515,12 @@ internal EffectiveParameters(ImmutableArray<TypeSymbol> types, ImmutableArray<Re
int argumentCount,
ImmutableArray<int> argToParamMap,
ArrayBuilder<RefKind> argumentRefKinds,
bool isMethodGroupConversion,
bool allowRefOmittedArguments)
where TMember : Symbol
{
bool discarded;
return GetEffectiveParametersInNormalForm(member, argumentCount, argToParamMap, argumentRefKinds, allowRefOmittedArguments, hasAnyRefOmittedArgument: out discarded);
return GetEffectiveParametersInNormalForm(member, argumentCount, argToParamMap, argumentRefKinds, isMethodGroupConversion, allowRefOmittedArguments, hasAnyRefOmittedArgument: out discarded);
}
private EffectiveParameters GetEffectiveParametersInNormalForm<TMember>(
......@@ -2515,6 +2528,7 @@ internal EffectiveParameters(ImmutableArray<TypeSymbol> types, ImmutableArray<Re
int argumentCount,
ImmutableArray<int> argToParamMap,
ArrayBuilder<RefKind> argumentRefKinds,
bool isMethodGroupConversion,
bool allowRefOmittedArguments,
out bool hasAnyRefOmittedArgument) where TMember : Symbol
{
......@@ -2551,7 +2565,7 @@ internal EffectiveParameters(ImmutableArray<TypeSymbol> types, ImmutableArray<Re
types.Add(parameter.Type);
RefKind argRefKind = hasAnyRefArg ? argumentRefKinds[arg] : RefKind.None;
RefKind paramRefKind = GetEffectiveParameterRefKind(parameter, argRefKind, allowRefOmittedArguments, ref hasAnyRefOmittedArgument);
RefKind paramRefKind = GetEffectiveParameterRefKind(parameter, argRefKind, isMethodGroupConversion, allowRefOmittedArguments, ref hasAnyRefOmittedArgument);
if (refs == null)
{
......@@ -2571,12 +2585,18 @@ internal EffectiveParameters(ImmutableArray<TypeSymbol> types, ImmutableArray<Re
return new EffectiveParameters(types.ToImmutableAndFree(), refKinds);
}
private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind argRefKind, bool allowRefOmittedArguments, ref bool hasAnyRefOmittedArgument)
private RefKind GetEffectiveParameterRefKind(
ParameterSymbol parameter,
RefKind argRefKind,
bool isMethodGroupConversion,
bool allowRefOmittedArguments,
ref bool hasAnyRefOmittedArgument)
{
var paramRefKind = parameter.RefKind;
// 'None' argument is allowed to match 'In' parameter and should behave like 'None' for the purpose of overload resolution
if (argRefKind == RefKind.None && paramRefKind == RefKind.In)
// unless this is a method group conversion where 'In' must match 'In'
if (!isMethodGroupConversion && argRefKind == RefKind.None && paramRefKind == RefKind.In)
{
return RefKind.None;
}
......@@ -2598,10 +2618,11 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
int argumentCount,
ImmutableArray<int> argToParamMap,
ArrayBuilder<RefKind> argumentRefKinds,
bool isMethodGroupConversion,
bool allowRefOmittedArguments) where TMember : Symbol
{
bool discarded;
return GetEffectiveParametersInExpandedForm(member, argumentCount, argToParamMap, argumentRefKinds, allowRefOmittedArguments, hasAnyRefOmittedArgument: out discarded);
return GetEffectiveParametersInExpandedForm(member, argumentCount, argToParamMap, argumentRefKinds, isMethodGroupConversion, allowRefOmittedArguments, hasAnyRefOmittedArgument: out discarded);
}
private EffectiveParameters GetEffectiveParametersInExpandedForm<TMember>(
......@@ -2609,6 +2630,7 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
int argumentCount,
ImmutableArray<int> argToParamMap,
ArrayBuilder<RefKind> argumentRefKinds,
bool isMethodGroupConversion,
bool allowRefOmittedArguments,
out bool hasAnyRefOmittedArgument) where TMember : Symbol
{
......@@ -2629,7 +2651,7 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
types.Add(parm == parameters.Length - 1 ? elementType : parameter.Type);
var argRefKind = hasAnyRefArg ? argumentRefKinds[arg] : RefKind.None;
var paramRefKind = GetEffectiveParameterRefKind(parameter, argRefKind, allowRefOmittedArguments, ref hasAnyRefOmittedArgument);
var paramRefKind = GetEffectiveParameterRefKind(parameter, argRefKind, isMethodGroupConversion, allowRefOmittedArguments, ref hasAnyRefOmittedArgument);
refs.Add(paramRefKind);
if (paramRefKind != RefKind.None)
......@@ -2689,6 +2711,7 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
arguments.Arguments.Count,
argumentAnalysis.ArgsToParamsOpt,
arguments.RefKinds,
isMethodGroupConversion,
allowRefOmittedArguments,
out hasAnyRefOmittedArgument);
......@@ -2700,6 +2723,7 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
arguments.Arguments.Count,
argumentAnalysis.ArgsToParamsOpt,
arguments.RefKinds,
isMethodGroupConversion,
allowRefOmittedArguments);
// The member passed to the following call is returned in the result (possibly a constructed version of it).
......@@ -2756,6 +2780,7 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
arguments.Arguments.Count,
argumentAnalysis.ArgsToParamsOpt,
arguments.RefKinds,
isMethodGroupConversion: false,
allowRefOmittedArguments,
out hasAnyRefOmittedArgument);
......@@ -2767,6 +2792,7 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
arguments.Arguments.Count,
argumentAnalysis.ArgsToParamsOpt,
arguments.RefKinds,
isMethodGroupConversion: false,
allowRefOmittedArguments);
// The member passed to the following call is returned in the result (possibly a constructed version of it).
......@@ -3115,13 +3141,11 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
// exists from the argument to the type of the corresponding parameter, or
// - for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter.
// RefKind has to match unless
// the ref kind is None and either:
// 1) parameter is an 'In' or
// 2) argument expression is of the type dynamic. This is a bug in Dev11 which we also implement.
// effective RefKind has to match unless argument expression is of the type dynamic.
// This is a bug in Dev11 which we also implement.
// The spec is correct, this is not an intended behavior. We don't fix the bug to avoid a breaking change.
if (!(argRefKind == parRefKind ||
(argRefKind == RefKind.None && (parRefKind == RefKind.In || argument.HasDynamicType()))))
(argRefKind == RefKind.None && argument.HasDynamicType())))
{
return Conversion.NoConversion;
}
......
......@@ -10036,5 +10036,158 @@ void M(C c, in int y)
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "1").WithLocation(14, 10)
);
}
[Fact]
public void MethodGroupConversionVal2In()
{
var code = @"
using System;
class Program
{
static void F(in DateTime x)
{
Console.WriteLine(x);
}
static void Main()
{
Action<DateTime> a = F;
a(DateTime.MaxValue);
}
}
";
CreateStandardCompilation(code).VerifyDiagnostics(
// (13,30): error CS0123: No overload for 'F' matches delegate 'Action<DateTime>'
// Action<DateTime> a = F;
Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "F").WithArguments("F", "System.Action<System.DateTime>").WithLocation(13, 30)
);
}
[Fact]
public void MethodGroupConversionVal2Overloaded()
{
var code = @"
using System;
class Program
{
static void F(in DateTime x)
{
Console.WriteLine('1');
}
static void F(DateTime x)
{
Console.WriteLine('2');
}
static void Main()
{
Action<DateTime> a = F;
a(DateTime.MaxValue);
}
}
";
CompileAndVerify(code, expectedOutput: @"2");
}
[Fact]
public void MethodGroupConversionIn2Overloaded()
{
var code = @"
using System;
class Program
{
delegate void D(in DateTime d);
static void F(in DateTime x)
{
Console.WriteLine('1');
}
static void F(DateTime x)
{
Console.WriteLine('2');
}
static void Main()
{
D a = F;
a(DateTime.MaxValue);
}
}
";
CompileAndVerify(code, expectedOutput: @"1", verify: Verification.Fails);
}
[Fact]
public void MethodGroupConversionRoReadonlyReturn()
{
var code = @"
using System;
class Program
{
delegate int D(in DateTime d);
static ref readonly int F(in DateTime x)
{
Console.WriteLine('1');
return ref (new int[1])[0];
}
static void Main()
{
D a = F;
a(DateTime.MaxValue);
}
}
";
CreateStandardCompilation(code).VerifyDiagnostics
(
// (16,15): error CS8189: Ref mismatch between 'Program.F(in DateTime)' and delegate 'Program.D'
// D a = F;
Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "F").WithArguments("Program.F(in System.DateTime)", "Program.D").WithLocation(16, 15)
);
}
[Fact]
public void MethodGroupConversionRoReadonlyReturnType()
{
var code = @"
using System;
class Program
{
delegate ref readonly object D(in DateTime d);
static ref readonly string F(in DateTime x)
{
Console.WriteLine('1');
return ref (new string[1])[0];
}
static void Main()
{
D a = F;
a(DateTime.MaxValue);
}
}
";
CreateStandardCompilation(code).VerifyDiagnostics
(
// (16,15): error CS0407: 'string Program.F(in DateTime)' has the wrong return type
// D a = F;
Diagnostic(ErrorCode.ERR_BadRetType, "F").WithArguments("Program.F(in System.DateTime)", "string").WithLocation(16, 15)
);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册