提交 7cc216eb 编写于 作者: C Charles Stoner

Skip user-defined conversions when checking extension method 'this' argument

上级 3986cdb6
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -54,67 +52,6 @@ public override Conversion GetMethodGroupConversion(BoundMethodGroup source, Typ
return conversion;
}
protected override Conversion GetImplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
var arguments = source.Arguments;
// check if the type is actually compatible type for a tuple of given cardinality
if (!destination.IsTupleOrCompatibleWithTupleOfCardinality(arguments.Length))
{
return Conversion.NoConversion;
}
ImmutableArray<TypeSymbol> targetElementTypes = destination.GetElementTypesOfTupleOrCompatible();
Debug.Assert(arguments.Length == targetElementTypes.Length);
// check arguments against flattened list of target element types
var argumentConversions = ArrayBuilder<Conversion>.GetInstance(arguments.Length);
for (int i = 0; i < arguments.Length; i++)
{
var argument = arguments[i];
var result = ClassifyImplicitConversionFromExpression(argument, targetElementTypes[i], ref useSiteDiagnostics);
if (!result.Exists)
{
argumentConversions.Free();
return Conversion.NoConversion;
}
argumentConversions.Add(result);
}
return new Conversion(ConversionKind.ImplicitTupleLiteral, argumentConversions.ToImmutableAndFree());
}
protected override Conversion GetExplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics, bool forCast)
{
var arguments = source.Arguments;
// check if the type is actually compatible type for a tuple of given cardinality
if (!destination.IsTupleOrCompatibleWithTupleOfCardinality(arguments.Length))
{
return Conversion.NoConversion;
}
ImmutableArray<TypeSymbol> targetElementTypes = destination.GetElementTypesOfTupleOrCompatible();
Debug.Assert(arguments.Length == targetElementTypes.Length);
// check arguments against flattened list of target element types
var argumentConversions = ArrayBuilder<Conversion>.GetInstance(arguments.Length);
for (int i = 0; i < arguments.Length; i++)
{
var result = ClassifyConversionFromExpression(arguments[i], targetElementTypes[i], ref useSiteDiagnostics, forCast);
if (!result.Exists)
{
argumentConversions.Free();
return Conversion.NoConversion;
}
argumentConversions.Add(result);
}
return new Conversion(ConversionKind.ExplicitTupleLiteral, argumentConversions.ToImmutableAndFree());
}
protected override Conversion GetInterpolatedStringConversion(BoundInterpolatedString source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
// An interpolated string expression may be converted to the types
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Generic;
using Roslyn.Utilities;
using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -31,10 +30,6 @@ protected ConversionsBase(AssemblySymbol corLibrary, int currentRecursionDepth)
protected abstract Conversion GetInterpolatedStringConversion(BoundInterpolatedString source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics);
protected abstract Conversion GetImplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics);
protected abstract Conversion GetExplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics, bool forCast);
internal AssemblySymbol CorLibrary { get { return corLibrary; } }
/// <summary>
......@@ -420,7 +415,7 @@ public Conversion ClassifyStandardConversion(BoundExpression sourceExpression, T
return Conversion.NoConversion;
}
internal Conversion ClassifyStandardImplicitConversion(BoundExpression sourceExpression, TypeSymbol source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
private Conversion ClassifyStandardImplicitConversion(BoundExpression sourceExpression, TypeSymbol source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
Debug.Assert(sourceExpression != null || (object)source != null);
Debug.Assert(sourceExpression == null || (object)sourceExpression.Type == (object)source);
......@@ -1340,10 +1335,72 @@ public static bool HasIdentityConversionToAny<T>(T type, ArrayBuilder<T> targetT
public Conversion ConvertExtensionMethodThisArg(TypeSymbol parameterType, TypeSymbol thisType, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
Debug.Assert((object)thisType != null);
var conversion = this.ClassifyImplicitConversionFromType(thisType, parameterType, ref useSiteDiagnostics);
var conversion = this.ClassifyImplicitExtensionMethodThisArgConversion(null, thisType, parameterType, ref useSiteDiagnostics);
return IsValidExtensionMethodThisArgConversion(conversion) ? conversion : Conversion.NoConversion;
}
// Spec 7.6.5.2: "An extension method ... is eligible if ... [an] implicit identity, reference,
// or boxing conversion exists from expr to the type of the first parameter"
public Conversion ClassifyImplicitExtensionMethodThisArgConversion(BoundExpression sourceExpressionOpt, TypeSymbol sourceType, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
Debug.Assert(sourceExpressionOpt == null || (object)sourceExpressionOpt.Type == sourceType);
Debug.Assert((object)destination != null);
if ((object)sourceType != null)
{
if (HasIdentityConversion(sourceType, destination))
{
return Conversion.Identity;
}
if (HasBoxingConversion(sourceType, destination, ref useSiteDiagnostics))
{
return Conversion.Boxing;
}
if (HasImplicitReferenceConversion(sourceType, destination, ref useSiteDiagnostics))
{
return Conversion.ImplicitReference;
}
}
if (sourceExpressionOpt?.Kind == BoundKind.TupleLiteral)
{
var tupleConversion = GetTupleLiteralConversion(
(BoundTupleLiteral)sourceExpressionOpt,
destination,
ref useSiteDiagnostics,
ConversionKind.ImplicitTupleLiteral,
(ConversionsBase conversions, BoundExpression s, TypeSymbol d, ref HashSet<DiagnosticInfo> u, bool a) => conversions.ClassifyImplicitExtensionMethodThisArgConversion(s, s.Type, d, ref u),
arg: false);
if (tupleConversion.Exists)
{
return tupleConversion;
}
}
if ((object)sourceType != null)
{
var tupleConversion = ClassifyTupleConversion(
sourceType,
destination,
ref useSiteDiagnostics,
ConversionKind.ImplicitTuple,
(ConversionsBase conversions, TypeSymbol s, TypeSymbol d, ref HashSet<DiagnosticInfo> u, bool a) => conversions.ClassifyImplicitExtensionMethodThisArgConversion(null, s, d, ref u),
arg: false);
if (tupleConversion.Exists)
{
return tupleConversion;
}
}
return Conversion.NoConversion;
}
// It should be possible to remove IsValidExtensionMethodThisArgConversion
// since ClassifyImplicitExtensionMethodThisArgConversion should only
// return valid conversions. https://github.com/dotnet/roslyn/issues/19622
// Spec 7.6.5.2: "An extension method ... is eligible if ... [an] implicit identity, reference,
// or boxing conversion exists from expr to the type of the first parameter"
public static bool IsValidExtensionMethodThisArgConversion(Conversion conversion)
......@@ -1368,6 +1425,8 @@ public static bool IsValidExtensionMethodThisArgConversion(Conversion conversion
return true;
default:
// Caller should have not have calculated another conversion.
Debug.Assert(conversion.Kind == ConversionKind.NoConversion);
return false;
}
}
......@@ -1716,35 +1775,97 @@ private Conversion ClassifyImplicitNullableConversion(TypeSymbol source, TypeSym
return Conversion.NoConversion;
}
private Conversion ClassifyImplicitTupleConversion(TypeSymbol source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
private delegate Conversion ClassifyConversionFromExpressionDelegate(ConversionsBase conversions, BoundExpression sourceExpression, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics, bool arg);
private delegate Conversion ClassifyConversionFromTypeDelegate(ConversionsBase conversions, TypeSymbol source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics, bool arg);
private Conversion GetImplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
ImmutableArray<TypeSymbol> sourceTypes;
ImmutableArray<TypeSymbol> destTypes;
return GetTupleLiteralConversion(
source,
destination,
ref useSiteDiagnostics,
ConversionKind.ImplicitTupleLiteral,
(ConversionsBase conversions, BoundExpression s, TypeSymbol d, ref HashSet<DiagnosticInfo> u, bool a) => conversions.ClassifyImplicitConversionFromExpression(s, d, ref u),
arg: false);
}
if (!source.TryGetElementTypesIfTupleOrCompatible(out sourceTypes) ||
!destination.TryGetElementTypesIfTupleOrCompatible(out destTypes) ||
sourceTypes.Length != destTypes.Length)
private Conversion GetExplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics, bool forCast)
{
return GetTupleLiteralConversion(
source,
destination,
ref useSiteDiagnostics,
ConversionKind.ExplicitTupleLiteral,
(ConversionsBase conversions, BoundExpression s, TypeSymbol d, ref HashSet<DiagnosticInfo> u, bool a) => conversions.ClassifyConversionFromExpression(s, d, ref u, a),
forCast);
}
private Conversion GetTupleLiteralConversion(
BoundTupleLiteral source,
TypeSymbol destination,
ref HashSet<DiagnosticInfo> useSiteDiagnostics,
ConversionKind kind,
ClassifyConversionFromExpressionDelegate classifyConversion,
bool arg)
{
var arguments = source.Arguments;
// check if the type is actually compatible type for a tuple of given cardinality
if (!destination.IsTupleOrCompatibleWithTupleOfCardinality(arguments.Length))
{
return Conversion.NoConversion;
}
var nestedConversions = ArrayBuilder<Conversion>.GetInstance(sourceTypes.Length);
for (int i = 0; i < sourceTypes.Length; i++)
ImmutableArray<TypeSymbol> targetElementTypes = destination.GetElementTypesOfTupleOrCompatible();
Debug.Assert(arguments.Length == targetElementTypes.Length);
// check arguments against flattened list of target element types
var argumentConversions = ArrayBuilder<Conversion>.GetInstance(arguments.Length);
for (int i = 0; i < arguments.Length; i++)
{
var conversion = ClassifyImplicitConversionFromType(sourceTypes[i], destTypes[i], ref useSiteDiagnostics);
if (!conversion.Exists)
var argument = arguments[i];
var result = classifyConversion(this, argument, targetElementTypes[i], ref useSiteDiagnostics, arg);
if (!result.Exists)
{
nestedConversions.Free();
argumentConversions.Free();
return Conversion.NoConversion;
}
nestedConversions.Add(conversion);
argumentConversions.Add(result);
}
return new Conversion(ConversionKind.ImplicitTuple, nestedConversions.ToImmutableAndFree());
return new Conversion(kind, argumentConversions.ToImmutableAndFree());
}
private Conversion ClassifyImplicitTupleConversion(TypeSymbol source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
return ClassifyTupleConversion(
source,
destination,
ref useSiteDiagnostics,
ConversionKind.ImplicitTuple,
(ConversionsBase conversions, TypeSymbol s, TypeSymbol d, ref HashSet<DiagnosticInfo> u, bool a) => conversions.ClassifyImplicitConversionFromType(s, d, ref u),
arg: false);
}
private Conversion ClassifyExplicitTupleConversion(TypeSymbol source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics, bool forCast)
{
return ClassifyTupleConversion(
source,
destination,
ref useSiteDiagnostics,
ConversionKind.ExplicitTuple,
(ConversionsBase conversions, TypeSymbol s, TypeSymbol d, ref HashSet<DiagnosticInfo> u, bool a) => conversions.ClassifyConversionFromType(s, d, ref u, a),
forCast);
}
private Conversion ClassifyTupleConversion(
TypeSymbol source,
TypeSymbol destination,
ref HashSet<DiagnosticInfo> useSiteDiagnostics,
ConversionKind kind,
ClassifyConversionFromTypeDelegate classifyConversion,
bool arg)
{
ImmutableArray<TypeSymbol> sourceTypes;
ImmutableArray<TypeSymbol> destTypes;
......@@ -1759,7 +1880,7 @@ private Conversion ClassifyExplicitTupleConversion(TypeSymbol source, TypeSymbol
var nestedConversions = ArrayBuilder<Conversion>.GetInstance(sourceTypes.Length);
for (int i = 0; i < sourceTypes.Length; i++)
{
var conversion = ClassifyConversionFromType(sourceTypes[i], destTypes[i], ref useSiteDiagnostics, forCast);
var conversion = classifyConversion(this, sourceTypes[i], destTypes[i], ref useSiteDiagnostics, arg);
if (!conversion.Exists)
{
nestedConversions.Free();
......@@ -1769,7 +1890,7 @@ private Conversion ClassifyExplicitTupleConversion(TypeSymbol source, TypeSymbol
nestedConversions.Add(conversion);
}
return new Conversion(ConversionKind.ExplicitTuple, nestedConversions.ToImmutableAndFree());
return new Conversion(kind, nestedConversions.ToImmutableAndFree());
}
private Conversion ClassifyExplicitNullableConversion(TypeSymbol source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics, bool forCast)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using System.Collections.Generic;
using System;
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -37,17 +35,5 @@ protected override Conversion GetInterpolatedStringConversion(BoundInterpolatedS
// Conversions involving interpolated strings require a Binder.
throw ExceptionUtilities.Unreachable;
}
protected override Conversion GetImplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
// Tuple conversions require a Binder, recursively
throw ExceptionUtilities.Unreachable;
}
protected override Conversion GetExplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics, bool forCast)
{
// Tuple conversions require a Binder, recursively
throw ExceptionUtilities.Unreachable;
}
}
}
......@@ -2959,9 +2959,19 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
else
{
RefKind parameterRefKind = parameters.ParameterRefKinds.IsDefault ? RefKind.None : parameters.ParameterRefKinds[argumentPosition];
conversion = CheckArgumentForApplicability(candidate, argument, argumentRefKind, parameters.ParameterTypes[argumentPosition], parameterRefKind, ignoreOpenTypes, ref useSiteDiagnostics);
if (arguments.IsExtensionMethodThisArgument(argumentPosition) && !Conversions.IsValidExtensionMethodThisArgConversion(conversion))
bool forExtensionMethodThisArg = arguments.IsExtensionMethodThisArgument(argumentPosition);
conversion = CheckArgumentForApplicability(
candidate,
argument,
argumentRefKind,
parameters.ParameterTypes[argumentPosition],
parameterRefKind,
ignoreOpenTypes,
ref useSiteDiagnostics,
forExtensionMethodThisArg);
if (forExtensionMethodThisArg && !Conversions.IsValidExtensionMethodThisArgConversion(conversion))
{
// Return early, without checking conversions of subsequent arguments,
// if the instance argument is not convertible to the 'this' parameter,
......@@ -3019,7 +3029,8 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
TypeSymbol parameterType,
RefKind parRefKind,
bool ignoreOpenTypes,
ref HashSet<DiagnosticInfo> useSiteDiagnostics)
ref HashSet<DiagnosticInfo> useSiteDiagnostics,
bool forExtensionMethodThisArg)
{
// Spec 7.5.3.1
// For each argument in A, the parameter passing mode of the argument (i.e., value, ref, or out) is identical
......@@ -3060,7 +3071,9 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
if (argRefKind == RefKind.None)
{
var conversion = Conversions.ClassifyImplicitConversionFromExpression(argument, parameterType, ref useSiteDiagnostics);
var conversion = forExtensionMethodThisArg ?
Conversions.ClassifyImplicitExtensionMethodThisArgConversion(argument, argument.Type, parameterType, ref useSiteDiagnostics) :
Conversions.ClassifyImplicitConversionFromExpression(argument, parameterType, ref useSiteDiagnostics);
Debug.Assert((!conversion.Exists) || conversion.IsImplicit, "ClassifyImplicitConversion should only return implicit conversions");
return conversion;
}
......
......@@ -986,32 +986,18 @@ private static bool HadLambdaConversionError(DiagnosticBag diagnostics, Analyzed
if (arguments.IsExtensionMethodThisArgument(arg))
{
Debug.Assert((arg == 0) && (parm == arg));
var conversion = badArg.Result.ConversionForArg(parm);
Debug.Assert(!badArg.Result.ConversionForArg(parm).IsImplicit);
if (conversion.IsImplicit)
{
// CS1928: '{0}' does not contain a definition for '{1}' and the best extension method overload '{2}' has some invalid arguments
diagnostics.Add(
ErrorCode.ERR_BadExtensionArgTypes,
location,
symbols,
argument.Display,
name,
method);
}
else
{
// CS1929: '{0}' does not contain a definition for '{1}' and the best extension method overload '{2}' requires a receiver of type '{3}'
diagnostics.Add(
ErrorCode.ERR_BadInstanceArgType,
sourceLocation,
symbols,
argument.Display,
name,
method,
parameter);
Debug.Assert((object)parameter == UnwrapIfParamsArray(parameter), "If they ever differ, just call the method when constructing the diagnostic.");
}
// CS1929: '{0}' does not contain a definition for '{1}' and the best extension method overload '{2}' requires a receiver of type '{3}'
diagnostics.Add(
ErrorCode.ERR_BadInstanceArgType,
sourceLocation,
symbols,
argument.Display,
name,
method,
parameter);
Debug.Assert((object)parameter == UnwrapIfParamsArray(parameter), "If they ever differ, just call the method when constructing the diagnostic.");
}
else
{
......
......@@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.CSharp {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class CSharpResources {
......@@ -1465,15 +1465,6 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to &apos;{0}&apos; does not contain a definition for &apos;{1}&apos; and the best extension method overload &apos;{2}&apos; has some invalid arguments.
/// </summary>
internal static string ERR_BadExtensionArgTypes {
get {
return ResourceManager.GetString("ERR_BadExtensionArgTypes", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extension method must be static.
/// </summary>
......
......@@ -3151,9 +3151,6 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep
<data name="WRN_CantHaveManifestForModule_Title" xml:space="preserve">
<value>Ignoring /win32manifest for module because it only applies to assemblies</value>
</data>
<data name="ERR_BadExtensionArgTypes" xml:space="preserve">
<value>'{0}' does not contain a definition for '{1}' and the best extension method overload '{2}' has some invalid arguments</value>
</data>
<data name="ERR_BadInstanceArgType" xml:space="preserve">
<value>'{0}' does not contain a definition for '{1}' and the best extension method overload '{2}' requires a receiver of type '{3}'</value>
</data>
......
......@@ -952,7 +952,7 @@ internal enum ErrorCode
//ERR_InvalidCollectionInitializerType = 1925, unused in Roslyn. Occurs so infrequently in real usage that it is not worth reimplementing.
ERR_CantOpenWin32Manifest = 1926,
WRN_CantHaveManifestForModule = 1927,
ERR_BadExtensionArgTypes = 1928,
//ERR_BadExtensionArgTypes = 1928, unused in Roslyn (replaced by ERR_BadInstanceArgType)
ERR_BadInstanceArgType = 1929,
ERR_QueryDuplicateRangeVariable = 1930,
ERR_QueryRangeVariableOverrides = 1931,
......@@ -977,7 +977,7 @@ internal enum ErrorCode
ERR_BadArgTypesForCollectionAdd = 1950,
ERR_ByRefParameterInExpressionTree = 1951,
ERR_VarArgsInExpressionTree = 1952,
// ERR_MemGroupInExpressionTree = 1953, unused in roslyn (replaced by ERR_LambdaInIsAs)
// ERR_MemGroupInExpressionTree = 1953, unused in Roslyn (replaced by ERR_LambdaInIsAs)
ERR_InitializerAddHasParamModifiers = 1954,
ERR_NonInvocableMemberCalled = 1955,
WRN_MultipleRuntimeImplementationMatches = 1956,
......
......@@ -22738,20 +22738,19 @@ static void Main()
var comp = CreateStandardCompilation(source, references: s_valueTupleRefs.Concat(new[] { LinqAssemblyRef }));
comp.VerifyDiagnostics(
// (10,41): error CS1928: '(int, int)' does not contain a definition for 'M' and the best extension method overload 'C.M((int x, long y))' has some invalid arguments
// (10,34): error CS1929: '(int, int)' does not contain a definition for 'M' and the best extension method overload 'C.M((int x, long y))' requires a receiver of type '(int x, long y)'
// System.Console.WriteLine((1, 2).M());
Diagnostic(ErrorCode.ERR_BadExtensionArgTypes, "M").WithArguments("(int, int)", "M", "C.M((int x, long y))").WithLocation(10, 41),
// (16,57): error CS1928: '(int, long)' does not contain a definition for 'M1' and the best extension method overload 'C.M1((int x, long? y))' has some invalid arguments
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "(1, 2)").WithArguments("(int, int)", "M", "C.M((int x, long y))", "(int x, long y)").WithLocation(10, 34),
// (16,34): error CS1929: '(int, long)' does not contain a definition for 'M1' and the best extension method overload 'C.M1((int x, long? y))' requires a receiver of type '(int x, long? y)'
// System.Console.WriteLine((First: 1, Second: 2L).M1());
Diagnostic(ErrorCode.ERR_BadExtensionArgTypes, "M1").WithArguments("(int, long)", "M1", "C.M1((int x, long? y))").WithLocation(16, 57),
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "(First: 1, Second: 2L)").WithArguments("(int, long)", "M1", "C.M1((int x, long? y))", "(int x, long? y)").WithLocation(16, 34),
// (19,44): error CS0117: '(int, <null>)' does not contain a definition for 'M1'
// System.Console.WriteLine((1, null).M1());
Diagnostic(ErrorCode.ERR_NoSuchMember, "M1").WithArguments("(int, <null>)", "M1").WithLocation(19, 44),
// (23,46): error CS1928: '(int A, int B)' does not contain a definition for 'M' and the best extension method overload 'C.M((int x, long y))' has some invalid arguments
Diagnostic(ErrorCode.ERR_NoSuchMember, "M1").WithArguments("(int, <null>)", "M1"),
// (23,34): error CS1929: '(int A, int B)' does not contain a definition for 'M' and the best extension method overload 'C.M((int x, long y))' requires a receiver of type '(int x, long y)'
// System.Console.WriteLine(notAliteral.M());
Diagnostic(ErrorCode.ERR_BadExtensionArgTypes, "M").WithArguments("(int A, int B)", "M", "C.M((int x, long y))").WithLocation(23, 46)
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "notAliteral").WithArguments("(int A, int B)", "M", "C.M((int x, long y))", "(int x, long y)").WithLocation(23, 34)
);
}
[Fact]
......
......@@ -15915,9 +15915,11 @@ static class S
internal static void F(this double d) { }
}";
var compilation = CreateStandardCompilation(text, references: new[] { SystemCoreRef });
// Previously ERR_BadExtensionArgTypes.
compilation.VerifyDiagnostics(
// (5,9): error CS1928: 'float' does not contain a definition for 'F' and the best extension method overload 'S.F(double)' has some invalid arguments
Diagnostic(ErrorCode.ERR_BadExtensionArgTypes, "F").WithArguments("float", "F", "S.F(double)").WithLocation(5, 11));
// (5,9): error CS1929: 'float' does not contain a definition for 'F' and the best extension method overload 'S.F(double)' requires a receiver of type 'double'
// f.F();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "f").WithArguments("float", "F", "S.F(double)", "double").WithLocation(5, 9));
}
[Fact]
......
......@@ -1986,6 +1986,390 @@ static void Main()
Diagnostic(ErrorCode.ERR_NoImplicitConv, "0").WithArguments("int", "R"));
}
[Fact]
public void BoxingConversionsForThisArgument()
{
var source =
@"static class E
{
internal static void F(this object o)
{
System.Console.WriteLine(o);
}
}
class C
{
static void Main()
{
1.F();
'c'.F();
""s"".F();
(1, (2, 3)).F();
}
}";
var comp = CreateCompilationWithMscorlibAndSystemCore(
source,
references: new[] { ValueTupleRef, SystemRuntimeFacadeRef },
options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput:
@"1
c
s
(1, (2, 3))");
}
[Fact]
public void SkipNumericConversionsForThisArgument()
{
var source =
@"static class E
{
internal static void F(this long l) { }
internal static void G(this (long, long) t) { }
internal static void H(this (object, object) t) { }
}
class C
{
static void Main()
{
int i = 1;
var t = (i, i);
E.F(i);
i.F();
E.G(t);
t.G();
E.H(t);
t.H();
}
}";
var comp = CreateCompilationWithMscorlibAndSystemCore(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (14,9): error CS1929: 'int' does not contain a definition for 'F' and the best extension method overload 'E.F(long)' requires a receiver of type 'long'
// i.F();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "i").WithArguments("int", "F", "E.F(long)", "long").WithLocation(14, 9),
// (16,9): error CS1929: '(int, int)' does not contain a definition for 'G' and the best extension method overload 'E.G((long, long))' requires a receiver of type '(long, long)'
// t.G();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "t").WithArguments("(int, int)", "G", "E.G((long, long))", "(long, long)").WithLocation(16, 9));
}
[Fact]
public void SkipNullableConversionsForThisArgument()
{
var source =
@"static class E
{
internal static void F(this int? i) { }
internal static void G(this (int, int)? t) { }
}
class C
{
static void Main()
{
int i = 1;
var t = (i, i);
E.F(i);
i.F();
E.F((int?)i);
((int?)i).F();
E.G(t);
t.G();
E.G(((int, int)?)t);
(((int, int)?)t).G();
}
}";
var comp = CreateCompilationWithMscorlibAndSystemCore(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (13,9): error CS1929: 'int' does not contain a definition for 'F' and the best extension method overload 'E.F(int?)' requires a receiver of type 'int?'
// i.F();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "i").WithArguments("int", "F", "E.F(int?)", "int?").WithLocation(13, 9),
// (17,9): error CS1929: '(int, int)' does not contain a definition for 'G' and the best extension method overload 'E.G((int, int)?)' requires a receiver of type '(int, int)?'
// t.G();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "t").WithArguments("(int, int)", "G", "E.G((int, int)?)", "(int, int)?").WithLocation(17, 9));
}
[Fact]
public void SkipEnumerationConversionsForThisArgument()
{
var source =
@"enum E
{
}
static class C
{
static void F(this E e) { }
static void G(this E? e) { }
static void H(this (E, E?) t) { }
static void Main()
{
const E e = default(E);
F(e);
e.F();
F(0);
0.F();
G(e);
e.G();
G((E?)e);
((E?)e).G();
G(0);
0.G();
H((e, e));
(e, e).H();
H((e, (E?)e));
(e, (E?)e).H();
}
}";
var comp = CreateCompilationWithMscorlibAndSystemCore(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (15,9): error CS1929: 'int' does not contain a definition for 'F' and the best extension method overload 'C.F(E)' requires a receiver of type 'E'
// 0.F();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "0").WithArguments("int", "F", "C.F(E)", "E").WithLocation(15, 9),
// (17,9): error CS1929: 'E' does not contain a definition for 'G' and the best extension method overload 'C.G(E?)' requires a receiver of type 'E?'
// e.G();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "e").WithArguments("E", "G", "C.G(E?)", "E?").WithLocation(17, 9),
// (21,9): error CS1929: 'int' does not contain a definition for 'G' and the best extension method overload 'C.G(E?)' requires a receiver of type 'E?'
// 0.G();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "0").WithArguments("int", "G", "C.G(E?)", "E?").WithLocation(21, 9),
// (23,9): error CS1929: '(E, E)' does not contain a definition for 'H' and the best extension method overload 'C.H((E, E?))' requires a receiver of type '(E, E?)'
// (e, e).H();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "(e, e)").WithArguments("(E, E)", "H", "C.H((E, E?))", "(E, E?)").WithLocation(23, 9));
}
[Fact]
public void SkipConstantExpressionConversionsForThisArgument()
{
var source =
@"static class C
{
static void S08(this sbyte arg) { }
static void S16(this short arg) { }
static void S32(this int arg) { }
static void S64(this long arg) { }
static void U08(this byte arg) { }
static void U16(this ushort arg) { }
static void U32(this uint arg) { }
static void U64(this ulong arg) { }
static void Main()
{
S08(1);
S16(2);
S32(3);
S64(4);
U08(5);
U16(6);
U32(7);
U64(8);
1.S08();
2.S16();
3.S32();
4.S64();
5.U08();
6.U16();
7.U32();
8.U64();
S64(9L);
U64(10L);
9L.S64();
10L.U64();
}
}";
var comp = CreateCompilationWithMscorlibAndSystemCore(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (21,9): error CS1929: 'int' does not contain a definition for 'S08' and the best extension method overload 'C.S08(sbyte)' requires a receiver of type 'sbyte'
// 1.S08();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "1").WithArguments("int", "S08", "C.S08(sbyte)", "sbyte").WithLocation(21, 9),
// (22,9): error CS1929: 'int' does not contain a definition for 'S16' and the best extension method overload 'C.S16(short)' requires a receiver of type 'short'
// 2.S16();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "2").WithArguments("int", "S16", "C.S16(short)", "short").WithLocation(22, 9),
// (24,9): error CS1929: 'int' does not contain a definition for 'S64' and the best extension method overload 'C.S64(long)' requires a receiver of type 'long'
// 4.S64();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "4").WithArguments("int", "S64", "C.S64(long)", "long").WithLocation(24, 9),
// (25,9): error CS1929: 'int' does not contain a definition for 'U08' and the best extension method overload 'C.U08(byte)' requires a receiver of type 'byte'
// 5.U08();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "5").WithArguments("int", "U08", "C.U08(byte)", "byte").WithLocation(25, 9),
// (26,9): error CS1929: 'int' does not contain a definition for 'U16' and the best extension method overload 'C.U16(ushort)' requires a receiver of type 'ushort'
// 6.U16();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "6").WithArguments("int", "U16", "C.U16(ushort)", "ushort").WithLocation(26, 9),
// (27,9): error CS1929: 'int' does not contain a definition for 'U32' and the best extension method overload 'C.U32(uint)' requires a receiver of type 'uint'
// 7.U32();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "7").WithArguments("int", "U32", "C.U32(uint)", "uint").WithLocation(27, 9),
// (28,9): error CS1929: 'int' does not contain a definition for 'U64' and the best extension method overload 'C.U64(ulong)' requires a receiver of type 'ulong'
// 8.U64();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "8").WithArguments("int", "U64", "C.U64(ulong)", "ulong").WithLocation(28, 9),
// (32,9): error CS1929: 'long' does not contain a definition for 'U64' and the best extension method overload 'C.U64(ulong)' requires a receiver of type 'ulong'
// 10L.U64();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "10L").WithArguments("long", "U64", "C.U64(ulong)", "ulong").WithLocation(32, 9));
}
[Fact]
public void SkipConstantExpressionNullableConversionsForThisArgument()
{
var source =
@"static class C
{
static void S08(this sbyte? arg) { }
static void S16(this short? arg) { }
static void S32(this int? arg) { }
static void S64(this long? arg) { }
static void U08(this byte? arg) { }
static void U16(this ushort? arg) { }
static void U32(this uint? arg) { }
static void U64(this ulong? arg) { }
static void Main()
{
S08(1);
S16(2);
S32(3);
S64(4);
U08(5);
U16(6);
U32(7);
U64(8);
1.S08();
2.S16();
3.S32();
4.S64();
5.U08();
6.U16();
7.U32();
8.U64();
S64(9L);
U64(10L);
9L.S64();
10L.U64();
}
}";
var comp = CreateCompilationWithMscorlibAndSystemCore(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (21,9): error CS1929: 'int' does not contain a definition for 'S08' and the best extension method overload 'C.S08(sbyte?)' requires a receiver of type 'sbyte?'
// 1.S08();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "1").WithArguments("int", "S08", "C.S08(sbyte?)", "sbyte?").WithLocation(21, 9),
// (22,9): error CS1929: 'int' does not contain a definition for 'S16' and the best extension method overload 'C.S16(short?)' requires a receiver of type 'short?'
// 2.S16();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "2").WithArguments("int", "S16", "C.S16(short?)", "short?").WithLocation(22, 9),
// (23,9): error CS1929: 'int' does not contain a definition for 'S32' and the best extension method overload 'C.S32(int?)' requires a receiver of type 'int?'
// 3.S32();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "3").WithArguments("int", "S32", "C.S32(int?)", "int?").WithLocation(23, 9),
// (24,9): error CS1929: 'int' does not contain a definition for 'S64' and the best extension method overload 'C.S64(long?)' requires a receiver of type 'long?'
// 4.S64();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "4").WithArguments("int", "S64", "C.S64(long?)", "long?").WithLocation(24, 9),
// (25,9): error CS1929: 'int' does not contain a definition for 'U08' and the best extension method overload 'C.U08(byte?)' requires a receiver of type 'byte?'
// 5.U08();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "5").WithArguments("int", "U08", "C.U08(byte?)", "byte?").WithLocation(25, 9),
// (26,9): error CS1929: 'int' does not contain a definition for 'U16' and the best extension method overload 'C.U16(ushort?)' requires a receiver of type 'ushort?'
// 6.U16();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "6").WithArguments("int", "U16", "C.U16(ushort?)", "ushort?").WithLocation(26, 9),
// (27,9): error CS1929: 'int' does not contain a definition for 'U32' and the best extension method overload 'C.U32(uint?)' requires a receiver of type 'uint?'
// 7.U32();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "7").WithArguments("int", "U32", "C.U32(uint?)", "uint?").WithLocation(27, 9),
// (28,9): error CS1929: 'int' does not contain a definition for 'U64' and the best extension method overload 'C.U64(ulong?)' requires a receiver of type 'ulong?'
// 8.U64();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "8").WithArguments("int", "U64", "C.U64(ulong?)", "ulong?").WithLocation(28, 9),
// (31,9): error CS1929: 'long' does not contain a definition for 'S64' and the best extension method overload 'C.S64(long?)' requires a receiver of type 'long?'
// 9L.S64();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "9L").WithArguments("long", "S64", "C.S64(long?)", "long?").WithLocation(31, 9),
// (32,9): error CS1929: 'long' does not contain a definition for 'U64' and the best extension method overload 'C.U64(ulong?)' requires a receiver of type 'ulong?'
// 10L.U64();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "10L").WithArguments("long", "U64", "C.U64(ulong?)", "ulong?").WithLocation(32, 9));
}
[Fact]
[WorkItem(434957, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=434957")]
public void SkipUserDefinedConversionsForThisArgument()
{
var source =
@"class A
{
public static implicit operator B(A a) => null;
public static implicit operator S(A a) => default(S);
}
class B
{
}
struct S
{
}
static class E
{
internal static void F(this B b) { }
internal static void G(this S? s) { }
}
class C
{
static void Main()
{
var a = new A();
var s = default(S);
E.F(a);
a.F();
E.G(s);
s.G();
E.G(a);
a.G();
}
}";
var comp = CreateCompilationWithMscorlibAndSystemCore(source);
comp.VerifyDiagnostics(
// (24,9): error CS1929: 'A' does not contain a definition for 'F' and the best extension method overload 'E.F(B)' requires a receiver of type 'B'
// a.F();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "a").WithArguments("A", "F", "E.F(B)", "B"),
// (26,9): error CS1929: 'S' does not contain a definition for 'G' and the best extension method overload 'E.G(S?)' requires a receiver of type 'S?'
// s.G();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "s").WithArguments("S", "G", "E.G(S?)", "S?").WithLocation(26, 9),
// (28,9): error CS1929: 'A' does not contain a definition for 'G' and the best extension method overload 'E.G(S?)' requires a receiver of type 'S?'
// a.G();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "a").WithArguments("A", "G", "E.G(S?)", "S?"));
}
[Fact]
[WorkItem(434957, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=434957")]
public void SkipUserDefinedConversionsForThisArgument_TupleElements()
{
var source =
@"class A
{
public static implicit operator B(A a) => null;
public static implicit operator S(A a) => default(S);
}
class B
{
}
struct S
{
}
static class E
{
internal static void F(this (B, B) t) { }
internal static void G(this (B, B)? t) { }
internal static void H(this (S, S?) t) { }
}
class C
{
static void Main()
{
var a = new A();
var b = new B();
var s = default(S);
E.F((a, b));
(a, b).F();
E.G((b, a));
(b, a).G();
E.H((s, s));
(s, s).H();
}
}";
var comp = CreateCompilationWithMscorlibAndSystemCore(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (26,9): error CS1929: '(A, B)' does not contain a definition for 'F' and the best extension method overload 'E.F((B, B))' requires a receiver of type '(B, B)'
// (a, b).F();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "(a, b)").WithArguments("(A, B)", "F", "E.F((B, B))", "(B, B)").WithLocation(26, 9),
// (28,9): error CS1929: '(B, A)' does not contain a definition for 'G' and the best extension method overload 'E.G((B, B)?)' requires a receiver of type '(B, B)?'
// (b, a).G();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "(b, a)").WithArguments("(B, A)", "G", "E.G((B, B)?)", "(B, B)?").WithLocation(28, 9),
// (30,9): error CS1929: '(S, S)' does not contain a definition for 'H' and the best extension method overload 'E.H((S, S?))' requires a receiver of type '(S, S?)'
// (s, s).H();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "(s, s)").WithArguments("(S, S)", "H", "E.H((S, S?))", "(S, S?)").WithLocation(30, 9));
}
#endregion
}
}
......@@ -1984,10 +1984,12 @@ static class S
}";
var compilation = CreateStandardCompilation(source, references: new[] { SystemCoreRef });
compilation.VerifyDiagnostics(
// (6,9): error CS1928: 'int' does not contain a definition for 'E2' and the best extension method overload 'S.E2(double)' has some invalid arguments
Diagnostic(ErrorCode.ERR_BadExtensionArgTypes, "E2").WithArguments("int", "E2", "S.E2(double)").WithLocation(6, 11),
// (7,9): error CS1928: 'int' does not contain a definition for 'E3' and the best extension method overload 'S.E3(long, params object[])' has some invalid arguments
Diagnostic(ErrorCode.ERR_BadExtensionArgTypes, "E3").WithArguments("int", "E3", "S.E3(long, params object[])").WithLocation(7, 11));
// (6,9): error CS1929: 'int' does not contain a definition for 'E2' and the best extension method overload 'S.E2(double)' requires a receiver of type 'double'
// 2.E2();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "2").WithArguments("int", "E2", "S.E2(double)", "double").WithLocation(6, 9),
// (7,9): error CS1929: 'int' does not contain a definition for 'E3' and the best extension method overload 'S.E3(long, params object[])' requires a receiver of type 'long'
// 3.E3();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, "3").WithArguments("int", "E3", "S.E3(long, params object[])", "long").WithLocation(7, 9));
}
[ClrOnlyFact]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册