提交 d67a95f1 编写于 作者: A Ashley Hauck 提交者: GitHub

Merge pull request #21450 from khyperia/fix_generic_locfunc_dynamic

Disallow calling generic local function with dynamic
......@@ -682,6 +682,28 @@ private static bool HasApplicableConditionalMethod(OverloadResolutionResult<Meth
}
}
// If we call an unconstructed generic local function with a dynamic argument in
// a place where it influences the type parameters, we need to dynamically dispatch the call
// (as the function must be constructed at runtime). We cannot do that, so disallow that.
// However, doing a specific analysis of each argument and its corresponding parameter
// to check if it's generic (and allow dynamic in non-generic parameters) may break
// overload resolution in the future, if we ever allow overloaded local functions.
// So, just disallow any mixing of dynamic and inferred generics.
// (Explicitly-provided generic arguments are fine)
if (boundMethodGroup.TypeArgumentsOpt.IsDefaultOrEmpty && localFunction.IsGenericMethod)
{
Error(diagnostics,
ErrorCode.ERR_DynamicLocalFunctionTypeParameter,
syntax, localFunction.Name);
return BindDynamicInvocation(
syntax,
boundMethodGroup,
resolution.AnalyzedArguments,
resolution.OverloadResolutionResult.GetAllApplicableMembers(),
diagnostics,
queryClause);
}
return BindInvocationExpressionContinued(
node: syntax,
expression: expression,
......
......@@ -3724,6 +3724,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot pass argument with dynamic type to generic local function &apos;{0}&apos; with inferred type arguments..
/// </summary>
internal static string ERR_DynamicLocalFunctionTypeParameter {
get {
return ResourceManager.GetString("ERR_DynamicLocalFunctionTypeParameter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to One or more types required to compile a dynamic expression cannot be found. Are you missing a reference?.
/// </summary>
......
......@@ -5108,4 +5108,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_InvalidDebugInfo" xml:space="preserve">
<value>Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}'</value>
</data>
<data name="ERR_DynamicLocalFunctionTypeParameter" xml:space="preserve">
<value>Cannot pass argument with dynamic type to generic local function '{0}' with inferred type arguments.</value>
</data>
</root>
\ No newline at end of file
......@@ -1496,6 +1496,7 @@ internal enum ErrorCode
#region diagnostics introduced for C# 7.2
ERR_FeatureNotAvailableInVersion7_2 = 8320,
WRN_UnreferencedLocalFunction = 8321,
ERR_DynamicLocalFunctionTypeParameter = 8322,
#endregion diagnostics introduced for C# 7.2
}
}
......@@ -3558,6 +3558,121 @@ Action<int> L5(int x)
00222");
}
[Fact]
[WorkItem(21317, "https://github.com/dotnet/roslyn/issues/21317")]
[CompilerTrait(CompilerFeature.Dynamic)]
public void DynamicGenericArg()
{
var src = @"
void L1<T>(T x)
{
Console.WriteLine($""{x}: {typeof(T)}"");
}
dynamic val = 2;
L1<object>(val);
L1<int>(val);
L1<dynamic>(val);
L1<dynamic>(4);
void L2<T>(int x, T y) => Console.WriteLine($""{x}, {y}: {typeof(T)}"");
L2<float>(val, 3.0f);
List<dynamic> listOfDynamic = new List<dynamic> { 1, 2, 3 };
void L3<T>(List<T> x) => Console.WriteLine($""{string.Join("", "", x)}: {typeof(T)}"");
L3(listOfDynamic);
void L4<T>(T x, params int[] y) => Console.WriteLine($""{x}, {string.Join("", "", y)}: {typeof(T)}"");
L4<dynamic>(val, 3, 4);
L4<int>(val, 3, 4);
L4<int>(1, 3, val);
void L5<T>(int x, params T[] y) => Console.WriteLine($""{x}, {string.Join("", "", y)}: {typeof(T)}"");
L5<int>(val, 3, 4);
L5<int>(1, 3, val);
L5<dynamic>(1, 3, val);
";
var output = @"
2: System.Object
2: System.Int32
2: System.Object
4: System.Object
2, 3: System.Single
1, 2, 3: System.Object
2, 3, 4: System.Object
2, 3, 4: System.Int32
1, 3, 2: System.Int32
2, 3, 4: System.Int32
1, 3, 2: System.Int32
1, 3, 2: System.Object
";
VerifyOutputInMain(src, output, "System", "System.Collections.Generic");
}
[Fact]
[WorkItem(21317, "https://github.com/dotnet/roslyn/issues/21317")]
[CompilerTrait(CompilerFeature.Dynamic)]
public void DynamicGenericClassMethod()
{
var src = @"
using System;
class C1<T1>
{
public static void M1<T2>()
{
void F(int x)
{
Console.WriteLine($""C1<{typeof(T1)}>.M1<{typeof(T2)}>.F({x})"");
}
F((dynamic)2);
}
public static void M2()
{
void F(int x)
{
Console.WriteLine($""C1<{typeof(T1)}>.M2.F({x})"");
}
F((dynamic)2);
}
}
class C2
{
public static void M1<T2>()
{
void F(int x)
{
Console.WriteLine($""C2.M1<{typeof(T2)}>.F({x})"");
}
F((dynamic)2);
}
public static void M2()
{
void F(int x)
{
Console.WriteLine($""C2.M2.F({x})"");
}
F((dynamic)2);
}
}
class Program
{
static void Main()
{
C1<int>.M1<float>();
C1<int>.M2();
C2.M1<float>();
C2.M2();
}
}
";
var output = @"
C1<System.Int32>.M1<System.Single>.F(2)
C1<System.Int32>.M2.F(2)
C2.M1<System.Single>.F(2)
C2.M2.F(2)
";
VerifyOutput(src, output);
}
[Fact]
[CompilerTrait(CompilerFeature.Dynamic, CompilerFeature.Params)]
public void DynamicArgsAndParams()
......
......@@ -3136,7 +3136,10 @@ static void M()
comp.VerifyEmitDiagnostics(
// (8,18): error CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type.
// L(m => L(d => d, m), null);
Diagnostic(ErrorCode.ERR_BadDynamicMethodArgLambda, "d => d").WithLocation(8, 18));
Diagnostic(ErrorCode.ERR_BadDynamicMethodArgLambda, "d => d").WithLocation(8, 18),
// (8,16): error CS8322: Cannot pass argument with dynamic type to generic local function 'L' with inferred type arguments.
// L(m => L(d => d, m), null);
Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L(d => d, m)").WithArguments("L").WithLocation(8, 16));
}
[Fact]
......@@ -3159,9 +3162,74 @@ async Task<dynamic> L<T>(Func<dynamic, T> t, object p)
// (8,37): error CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type.
// => await L(async m => L(async d => await d, m), p);
Diagnostic(ErrorCode.ERR_BadDynamicMethodArgLambda, "async d => await d").WithLocation(8, 37),
// (8,35): error CS8322: Cannot pass argument with dynamic type to generic local function 'L' with inferred type arguments.
// => await L(async m => L(async d => await d, m), p);
Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L(async d => await d, m)").WithArguments("L").WithLocation(8, 35),
// (8,32): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
// => await L(async m => L(async d => await d, m), p);
Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "=>").WithLocation(8, 32));
}
[Fact]
[WorkItem(21317, "https://github.com/dotnet/roslyn/issues/21317")]
[CompilerTrait(CompilerFeature.Dynamic)]
public void DynamicGenericArg()
{
var src = @"
using System.Collections.Generic;
class C
{
static void M()
{
dynamic val = 2;
dynamic dynamicList = new List<int>();
void L1<T>(T x) { }
L1(val);
void L2<T>(int x, T y) { }
L2(1, val);
L2(val, 3.0f);
void L3<T>(List<T> x) { }
L3(dynamicList);
void L4<T>(int x, params T[] y) { }
L4(1, 2, val);
L4(val, 3, 4);
void L5<T>(T x, params int[] y) { }
L5(val, 1, 2);
L5(1, 3, val);
}
}
";
VerifyDiagnostics(src,
// (11,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L1'. Try specifying the type arguments explicitly.
// L1(val);
Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L1(val)").WithArguments("L1").WithLocation(11, 9),
// (14,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L2'. Try specifying the type arguments explicitly.
// L2(1, val);
Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L2(1, val)").WithArguments("L2").WithLocation(14, 9),
// (15,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L2'. Try specifying the type arguments explicitly.
// L2(val, 3.0f);
Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L2(val, 3.0f)").WithArguments("L2").WithLocation(15, 9),
// (18,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L3'. Try specifying the type arguments explicitly.
// L3(dynamicList);
Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L3(dynamicList)").WithArguments("L3").WithLocation(18, 9),
// (21,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L4'. Try specifying the type arguments explicitly.
// L4(1, 2, val);
Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L4(1, 2, val)").WithArguments("L4").WithLocation(21, 9),
// (22,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L4'. Try specifying the type arguments explicitly.
// L4(val, 3, 4);
Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L4(val, 3, 4)").WithArguments("L4").WithLocation(22, 9),
// (25,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L5'. Try specifying the type arguments explicitly.
// L5(val, 1, 2);
Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L5(val, 1, 2)").WithArguments("L5").WithLocation(25, 9),
// (26,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L5'. Try specifying the type arguments explicitly.
// L5(1, 3, val);
Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L5(1, 3, val)").WithArguments("L5").WithLocation(26, 9)
);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册