From a7c9ddfd507bc47a5cb32526f2a44bf0542fa6e4 Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Fri, 9 Feb 2018 16:34:48 -0800 Subject: [PATCH 1/5] Implement improved overload candidates, aka "Bestest Betternes". - Refine candidate set based on static/instance receiver, or static context - Refine candidate methods whose type parameter constraints are violated. - For a method group conversion, remove methods with the wrong return type or ref mode. Implements https://github.com/dotnet/csharplang/issues/98 See also https://github.com/dotnet/roslyn/issues/24675 for a proposal to improve the quality of diagnostics for the method group conversion. This change occasionally exposes this opportunity for diagnostic improvement (search for references to https://github.com/dotnet/roslyn/issues/24675 in the source to find examples). --- .../Portable/Binder/Binder.ValueChecks.cs | 12 + .../CSharp/Portable/Binder/Binder.cs | 2 +- .../Portable/Binder/Binder_Conversions.cs | 9 +- .../Portable/Binder/Binder_Expressions.cs | 96 ++-- .../Portable/Binder/Binder_Invocation.cs | 13 +- .../Portable/Binder/ForEachLoopBinder.cs | 10 +- .../CSharp/Portable/Binder/InMethodBinder.cs | 4 - .../Semantics/Conversions/Conversions.cs | 29 +- .../MemberAnalysisResult.cs | 58 ++- .../MemberResolutionKind.cs | 23 +- .../OverloadResolution/MethodTypeInference.cs | 18 +- .../OverloadResolution/OverloadResolution.cs | 203 +++++++- .../OverloadResolutionResult.cs | 137 +++++- .../Portable/CSharpResources.Designer.cs | 2 +- .../CSharp/Portable/CSharpResources.resx | 2 +- .../MemberSemanticModel.NodeMapBuilder.cs | 8 +- .../CSharp/Portable/Errors/MessageID.cs | 2 + .../CSharp/Portable/LanguageVersion.cs | 5 + .../Portable/Symbols/ConstraintsHelper.cs | 8 +- .../Portable/xlf/CSharpResources.cs.xlf | 4 +- .../Portable/xlf/CSharpResources.de.xlf | 4 +- .../Portable/xlf/CSharpResources.es.xlf | 4 +- .../Portable/xlf/CSharpResources.fr.xlf | 4 +- .../Portable/xlf/CSharpResources.it.xlf | 4 +- .../Portable/xlf/CSharpResources.ja.xlf | 4 +- .../Portable/xlf/CSharpResources.ko.xlf | 4 +- .../Portable/xlf/CSharpResources.pl.xlf | 4 +- .../Portable/xlf/CSharpResources.pt-BR.xlf | 4 +- .../Portable/xlf/CSharpResources.ru.xlf | 4 +- .../Portable/xlf/CSharpResources.tr.xlf | 4 +- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 4 +- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 4 +- .../Emit/CodeGen/CodeGenRefReturnTests.cs | 53 ++- .../CSharp/Test/Emit/CodeGen/CodeGenTests.cs | 32 +- .../CSharp/Test/Emit/PDB/PDBTests.cs | 2 +- ...rationTests_ArrayCreationAndInitializer.cs | 17 +- ...rationTests_IDelegateCreationExpression.cs | 88 ++-- .../IOperationTests_IInvocationOperation.cs | 18 +- .../Semantic/Semantics/BetterCandidates.cs | 433 ++++++++++++++++++ .../Test/Semantic/Semantics/BindingTests.cs | 20 +- .../Semantics/ConditionalOperatorTests.cs | 13 +- .../Test/Semantic/Semantics/DynamicTests.cs | 38 +- .../Test/Semantic/Semantics/ForEachTests.cs | 5 +- .../Semantics/InheritanceBindingTests.cs | 24 +- .../ObjectAndCollectionInitializerTests.cs | 16 +- .../Semantics/OverloadResolutionTests.cs | 51 ++- .../Test/Semantic/Semantics/QueryTests.cs | 45 +- .../Semantics/ScriptSemanticsTests.cs | 4 +- .../Semantics/SemanticAnalyzerTests.cs | 11 +- .../Semantic/Semantics/SemanticErrorTests.cs | 351 +++++++++----- .../Test/Semantic/Semantics/UnsafeTests.cs | 10 +- .../CSharp/Test/Symbol/BadSymbolReference.cs | 6 + .../Compilation/GetSemanticInfoTests.cs | 2 +- .../SemanticModelGetDeclaredSymbolAPITests.cs | 11 +- .../SemanticModelGetSemanticInfoTests.cs | 139 ++++-- .../Test/Symbol/Symbols/ConversionTests.cs | 4 +- .../Symbol/Symbols/ExtensionMethodTests.cs | 33 +- .../Symbol/Symbols/GenericConstraintTests.cs | 120 ++--- .../Symbols/SymbolDistinguisherTests.cs | 12 +- .../Test/Symbol/Symbols/SymbolErrorTests.cs | 73 +-- .../Test/Utilities/CSharp/TestOptions.cs | 1 + 61 files changed, 1782 insertions(+), 543 deletions(-) create mode 100644 src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index e499285c84a80..945242123cdaf 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -259,6 +259,18 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind return ToBadExpression(expr, resultKind); } + internal static bool IsTypeOrValueExpression(BoundExpression expression) + { + switch (expression?.Kind) + { + case BoundKind.TypeOrValueExpression: + case BoundKind.QueryClause when ((BoundQueryClause)expression).Value.Kind == BoundKind.TypeOrValueExpression: + return true; + default: + return false; + } + } + /// /// The purpose of this method is to determine if the expression satisfies desired capabilities. /// If it is not then this code gives an appropriate error message. diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.cs index 46c6af1a94164..84890dc597c16 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.cs @@ -347,7 +347,7 @@ internal bool BindingTopLevelScriptCode get { var containingMember = this.ContainingMemberOrLambda; - switch (containingMember.Kind) + switch (containingMember?.Kind) { case SymbolKind.Method: // global statements diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 7bc3346493e5b..19ccf391d8a84 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -455,8 +455,7 @@ private static bool IsMethodGroupWithTypeOrValueReceiver(BoundNode node) return false; } - BoundNode receiverOpt = ((BoundMethodGroup)node).ReceiverOpt; - return receiverOpt != null && receiverOpt.Kind == BoundKind.TypeOrValueExpression; + return Binder.IsTypeOrValueExpression(((BoundMethodGroup)node).ReceiverOpt); } private BoundMethodGroup FixMethodGroupWithTypeOrValue(BoundMethodGroup group, Conversion conversion, DiagnosticBag diagnostics) @@ -572,7 +571,7 @@ private bool MemberGroupFinalValidationAccessibilityChecks(BoundExpression recei //note that the same assert does not hold for all properties. Some properties and (all indexers) are not referenceable by name, yet //their binding brings them through here, perhaps needlessly. - if (receiverOpt != null && receiverOpt.Kind == BoundKind.TypeOrValueExpression) + if (IsTypeOrValueExpression(receiverOpt)) { // TypeOrValue expression isn't replaced only if the invocation is late bound, in which case it can't be extension method. // None of the checks below apply if the receiver can't be classified as a type or value. @@ -678,7 +677,7 @@ private static bool IsMemberAccessedThroughVariableOrValue(BoundExpression recei return !IsMemberAccessedThroughType(receiverOpt); } - private static bool IsMemberAccessedThroughType(BoundExpression receiverOpt) + internal static bool IsMemberAccessedThroughType(BoundExpression receiverOpt) { if (receiverOpt == null) { @@ -696,7 +695,7 @@ private static bool IsMemberAccessedThroughType(BoundExpression receiverOpt) /// /// Was the receiver expression compiler-generated? /// - private static bool WasImplicitReceiver(BoundExpression receiverOpt) + internal static bool WasImplicitReceiver(BoundExpression receiverOpt) { if (receiverOpt == null) return true; if (!receiverOpt.WasCompilerGenerated) return false; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index b5e2811d66d11..a9357d3249e17 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -26,12 +26,12 @@ internal partial class Binder /// The reference was explicitly specified in syntax. /// True if "this" is not available due to the current method/property/field initializer being static. /// True if a reference to "this" is available. - private bool HasThis(bool isExplicit, out bool inStaticContext) + internal bool HasThis(bool isExplicit, out bool inStaticContext) { - var member = this.ContainingMemberOrLambda.ContainingNonLambdaMember(); - if (member.IsStatic) + var memberOpt = this.ContainingMemberOrLambda?.ContainingNonLambdaMember(); + if (memberOpt?.IsStatic == true) { - inStaticContext = member.Kind == SymbolKind.Field || member.Kind == SymbolKind.Method || member.Kind == SymbolKind.Property; + inStaticContext = memberOpt.Kind == SymbolKind.Field || memberOpt.Kind == SymbolKind.Method || memberOpt.Kind == SymbolKind.Property; return false; } @@ -42,7 +42,7 @@ private bool HasThis(bool isExplicit, out bool inStaticContext) return false; } - var containingType = member.ContainingType; + var containingType = memberOpt?.ContainingType; bool inTopLevelScriptMember = (object)containingType != null && containingType.IsScriptClass; // "this" is not allowed in field initializers (that are not script variable initializers): @@ -4860,8 +4860,10 @@ private bool TryPerformConstructorOverloadResolution( } else { - result.ReportDiagnostics(this, errorLocation, diagnostics, - errorName, null, analyzedArguments, candidateConstructors, typeContainingConstructors, null); + result.ReportDiagnostics( + binder: this, location: errorLocation, nodeOpt: null, diagnostics: diagnostics, + name: errorName, receiver: null, invokedExpression: null, arguments: analyzedArguments, + memberGroup: candidateConstructors, typeContainingConstructor: typeContainingConstructors, delegateTypeBeingInvoked: null); } } @@ -5823,7 +5825,10 @@ private MethodGroupResolution BindExtensionMethod( AnalyzedArguments analyzedArguments, BoundExpression left, ImmutableArray typeArguments, - bool isMethodGroupConversion) + bool isMethodGroupConversion, + RefKind returnRefKind = default, + TypeSymbol returnType = null +) { var firstResult = new MethodGroupResolution(); AnalyzedArguments actualArguments = null; @@ -5872,7 +5877,17 @@ private MethodGroupResolution BindExtensionMethod( var overloadResolutionResult = OverloadResolutionResult.GetInstance(); bool allowRefOmittedArguments = methodGroup.Receiver.IsExpressionOfComImportType(); HashSet useSiteDiagnostics = null; - OverloadResolution.MethodInvocationOverloadResolution(methodGroup.Methods, methodGroup.TypeArguments, actualArguments, overloadResolutionResult, ref useSiteDiagnostics, isMethodGroupConversion, allowRefOmittedArguments); + OverloadResolution.MethodInvocationOverloadResolution( + methods: methodGroup.Methods, + typeArguments: methodGroup.TypeArguments, + receiver: methodGroup.Receiver, + arguments: actualArguments, + result: overloadResolutionResult, + useSiteDiagnostics: ref useSiteDiagnostics, + isMethodGroupConversion: isMethodGroupConversion, + allowRefOmittedArguments: allowRefOmittedArguments, + returnRefKind: returnRefKind, + returnType: returnType); diagnostics.Add(expression, useSiteDiagnostics); var sealedDiagnostics = diagnostics.ToReadOnlyAndFree(); var result = new MethodGroupResolution(methodGroup, null, overloadResolutionResult, actualArguments, methodGroup.ResultKind, sealedDiagnostics); @@ -6737,7 +6752,7 @@ private BoundExpression BindIndexerOrIndexedPropertyAccess( OverloadResolutionResult overloadResolutionResult = OverloadResolutionResult.GetInstance(); bool allowRefOmittedArguments = receiverOpt.IsExpressionOfComImportType(); HashSet useSiteDiagnostics = null; - this.OverloadResolution.PropertyOverloadResolution(propertyGroup, analyzedArguments, overloadResolutionResult, allowRefOmittedArguments, ref useSiteDiagnostics); + this.OverloadResolution.PropertyOverloadResolution(propertyGroup, receiverOpt, analyzedArguments, overloadResolutionResult, allowRefOmittedArguments, ref useSiteDiagnostics); diagnostics.Add(syntax, useSiteDiagnostics); BoundExpression propertyAccess; @@ -6768,13 +6783,15 @@ private BoundExpression BindIndexerOrIndexedPropertyAccess( var name = candidate.IsIndexer ? SyntaxFacts.GetText(SyntaxKind.ThisKeyword) : candidate.Name; overloadResolutionResult.ReportDiagnostics( - this, - syntax.Location, - diagnostics, - name, - null, - analyzedArguments, - candidates, + binder: this, + location: syntax.Location, + nodeOpt: syntax, + diagnostics: diagnostics, + name: name, + receiver: null, + invokedExpression: null, + arguments: analyzedArguments, + memberGroup: candidates, typeContainingConstructor: null, delegateTypeBeingInvoked: null); } @@ -6866,9 +6883,13 @@ internal MethodGroupResolution ResolveMethodGroup( AnalyzedArguments analyzedArguments, bool isMethodGroupConversion, ref HashSet useSiteDiagnostics, - bool inferWithDynamic = false) + bool inferWithDynamic = false, + RefKind returnRefKind = default, + TypeSymbol returnType = null) { - return ResolveMethodGroup(node, node.Syntax, node.Name, analyzedArguments, isMethodGroupConversion, ref useSiteDiagnostics, inferWithDynamic: inferWithDynamic); + return ResolveMethodGroup( + node, node.Syntax, node.Name, analyzedArguments, isMethodGroupConversion, ref useSiteDiagnostics, + inferWithDynamic: inferWithDynamic, returnRefKind: returnRefKind, returnType: returnType); } internal MethodGroupResolution ResolveMethodGroup( @@ -6879,11 +6900,14 @@ internal MethodGroupResolution ResolveMethodGroup( bool isMethodGroupConversion, ref HashSet useSiteDiagnostics, bool inferWithDynamic = false, - bool allowUnexpandedForm = true) + bool allowUnexpandedForm = true, + RefKind returnRefKind = default, + TypeSymbol returnType = null) { var methodResolution = ResolveMethodGroupInternal( node, expression, methodName, analyzedArguments, isMethodGroupConversion, ref useSiteDiagnostics, - inferWithDynamic: inferWithDynamic, allowUnexpandedForm: allowUnexpandedForm); + inferWithDynamic: inferWithDynamic, allowUnexpandedForm: allowUnexpandedForm, + returnRefKind: returnRefKind, returnType: returnType); if (methodResolution.IsEmpty && !methodResolution.HasAnyErrors) { Debug.Assert(node.LookupError == null); @@ -6904,11 +6928,14 @@ private MethodGroupResolution ResolveMethodGroupInternal( bool isMethodGroupConversion, ref HashSet useSiteDiagnostics, bool inferWithDynamic = false, - bool allowUnexpandedForm = true) + bool allowUnexpandedForm = true, + RefKind returnRefKind = default, + TypeSymbol returnType = null) { var methodResolution = ResolveDefaultMethodGroup( methodGroup, analyzedArguments, isMethodGroupConversion, ref useSiteDiagnostics, - inferWithDynamic: inferWithDynamic, allowUnexpandedForm: allowUnexpandedForm); + inferWithDynamic: inferWithDynamic, allowUnexpandedForm: allowUnexpandedForm, + returnRefKind: returnRefKind, returnType: returnType); // If the method group's receiver is dynamic then there is no point in looking for extension methods; // it's going to be a dynamic invocation. @@ -6917,7 +6944,9 @@ private MethodGroupResolution ResolveMethodGroupInternal( return methodResolution; } - var extensionMethodResolution = BindExtensionMethod(expression, methodName, analyzedArguments, methodGroup.ReceiverOpt, methodGroup.TypeArgumentsOpt, isMethodGroupConversion); + var extensionMethodResolution = BindExtensionMethod( + expression, methodName, analyzedArguments, methodGroup.ReceiverOpt, methodGroup.TypeArgumentsOpt, isMethodGroupConversion, + returnRefKind: returnRefKind, returnType: returnType); bool preferExtensionMethodResolution = false; if (extensionMethodResolution.HasAnyApplicableMethod) @@ -6969,7 +6998,9 @@ private MethodGroupResolution ResolveDefaultMethodGroup( bool isMethodGroupConversion, ref HashSet useSiteDiagnostics, bool inferWithDynamic = false, - bool allowUnexpandedForm = true) + bool allowUnexpandedForm = true, + RefKind returnRefKind = default, + TypeSymbol returnType = null) { var methods = node.Methods; if (methods.Length == 0) @@ -7015,9 +7046,18 @@ private MethodGroupResolution ResolveDefaultMethodGroup( var result = OverloadResolutionResult.GetInstance(); bool allowRefOmittedArguments = methodGroup.Receiver.IsExpressionOfComImportType(); OverloadResolution.MethodInvocationOverloadResolution( - methodGroup.Methods, methodGroup.TypeArguments, analyzedArguments, - result, ref useSiteDiagnostics, isMethodGroupConversion, allowRefOmittedArguments, - inferWithDynamic: inferWithDynamic, allowUnexpandedForm: allowUnexpandedForm); + methods: methodGroup.Methods, + typeArguments: methodGroup.TypeArguments, + receiver: methodGroup.Receiver, + arguments: analyzedArguments, + result: result, + useSiteDiagnostics: ref useSiteDiagnostics, + isMethodGroupConversion: isMethodGroupConversion, + allowRefOmittedArguments: allowRefOmittedArguments, + inferWithDynamic: inferWithDynamic, + allowUnexpandedForm: allowUnexpandedForm, + returnRefKind: returnRefKind, + returnType: returnType); return new MethodGroupResolution(methodGroup, null, result, analyzedArguments, methodGroup.ResultKind, sealedDiagnostics); } } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs index ce729d50da236..76564690dd19e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs @@ -497,7 +497,13 @@ private BoundExpression BindDelegateInvocation( methodGroup.PopulateWithSingleMethod(boundExpression, delegateType.DelegateInvokeMethod); var overloadResolutionResult = OverloadResolutionResult.GetInstance(); HashSet useSiteDiagnostics = null; - OverloadResolution.MethodInvocationOverloadResolution(methodGroup.Methods, methodGroup.TypeArguments, analyzedArguments, overloadResolutionResult, ref useSiteDiagnostics); + OverloadResolution.MethodInvocationOverloadResolution( + methods: methodGroup.Methods, + typeArguments: methodGroup.TypeArguments, + receiver: methodGroup.Receiver, + arguments: analyzedArguments, + result: overloadResolutionResult, + useSiteDiagnostics: ref useSiteDiagnostics); diagnostics.Add(node, useSiteDiagnostics); // If overload resolution on the "Invoke" method found an applicable candidate, and one of the arguments @@ -943,8 +949,9 @@ private BoundCall BindInvocationExpressionContinued( { // Since there were no argument errors to report, we report an error on the invocation itself. string name = (object)delegateTypeOpt == null ? methodName : null; - result.ReportDiagnostics(this, GetLocationForOverloadResolutionDiagnostic(node, expression), diagnostics, name, - methodGroup.Receiver, analyzedArguments, methodGroup.Methods.ToImmutable(), + result.ReportDiagnostics( + binder: this, location: GetLocationForOverloadResolutionDiagnostic(node, expression), nodeOpt: node, diagnostics: diagnostics, name: name, + receiver: methodGroup.Receiver, invokedExpression: expression, arguments: analyzedArguments, memberGroup: methodGroup.Methods.ToImmutable(), typeContainingConstructor: null, delegateTypeBeingInvoked: delegateTypeOpt, queryClause: queryClause); } diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs index b87a3b4eba052..609dfba587f03 100644 --- a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs @@ -807,7 +807,15 @@ private MethodSymbol PerformForEachPatternOverloadResolution(TypeSymbol patternT OverloadResolutionResult overloadResolutionResult = OverloadResolutionResult.GetInstance(); HashSet useSiteDiagnostics = null; - this.OverloadResolution.MethodInvocationOverloadResolution(candidateMethods, typeArguments, arguments, overloadResolutionResult, ref useSiteDiagnostics); + // We create a dummy receiver of the invocation so MethodInvocationOverloadResolution knows it was invoked from an instance, not a type + var dummyReceiver = new BoundImplicitReceiver(_syntax.Expression, patternType); + this.OverloadResolution.MethodInvocationOverloadResolution( + methods: candidateMethods, + typeArguments: typeArguments, + receiver: dummyReceiver, + arguments: arguments, + result: overloadResolutionResult, + useSiteDiagnostics: ref useSiteDiagnostics); diagnostics.Add(_syntax.Expression, useSiteDiagnostics); MethodSymbol result = null; diff --git a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs index 25786784debab..eb68a032e2c06 100644 --- a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs @@ -238,12 +238,8 @@ protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo res internal static bool ReportConflictWithParameter(Symbol parameter, Symbol newSymbol, string name, Location newLocation, DiagnosticBag diagnostics) { var oldLocation = parameter.Locations[0]; -#if PATTERNS_FIXED Debug.Assert(oldLocation != newLocation || oldLocation == Location.None || newLocation.SourceTree?.GetRoot().ContainsDiagnostics == true, "same nonempty location refers to different symbols?"); -#else - if (oldLocation == newLocation) return false; -#endif SymbolKind parameterKind = parameter.Kind; // Quirk of the way we represent lambda parameters. diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs index 8753c001b9551..051303c722d0e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs @@ -71,7 +71,8 @@ private static MethodGroupResolution ResolveDelegateMethodGroup(Binder binder, B { var analyzedArguments = AnalyzedArguments.GetInstance(); GetDelegateArguments(source.Syntax, analyzedArguments, delegateInvokeMethodOpt.Parameters, binder.Compilation); - var resolution = binder.ResolveMethodGroup(source, analyzedArguments, isMethodGroupConversion: true, ref useSiteDiagnostics, inferWithDynamic: true); + var resolution = binder.ResolveMethodGroup(source, analyzedArguments, useSiteDiagnostics: ref useSiteDiagnostics, inferWithDynamic: true, + isMethodGroupConversion: true, returnRefKind: delegateInvokeMethodOpt.RefKind, returnType: delegateInvokeMethodOpt.ReturnType); analyzedArguments.Free(); return resolution; } @@ -165,10 +166,13 @@ public static bool ReportDelegateMethodGroupDiagnostics(Binder binder, BoundMeth { var overloadDiagnostics = DiagnosticBag.GetInstance(); - result.ReportDiagnostics(binder, expr.Syntax.Location, overloadDiagnostics, - expr.Name, - resolution.MethodGroup.Receiver, resolution.AnalyzedArguments, resolution.MethodGroup.Methods.ToImmutable(), - typeContainingConstructor: null, delegateTypeBeingInvoked: null, isMethodGroupConversion: true); + result.ReportDiagnostics( + binder: binder, location: expr.Syntax.Location, nodeOpt: expr.Syntax, diagnostics: overloadDiagnostics, + name: expr.Name, + receiver: resolution.MethodGroup.Receiver, invokedExpression: expr.Syntax, arguments: resolution.AnalyzedArguments, + memberGroup: resolution.MethodGroup.Methods.ToImmutable(), + typeContainingConstructor: null, delegateTypeBeingInvoked: null, + isMethodGroupConversion: true, returnRefKind: invokeMethodOpt?.RefKind, delegateType: targetType); if (!overloadDiagnostics.IsEmptyWithoutResolution) { @@ -189,12 +193,21 @@ public Conversion MethodGroupConversion(SyntaxNode syntax, MethodGroup methodGro { var analyzedArguments = AnalyzedArguments.GetInstance(); var result = OverloadResolutionResult.GetInstance(); + var delegateInvokeMethod = delegateType.DelegateInvokeMethod; - Debug.Assert((object)delegateType.DelegateInvokeMethod != null && !delegateType.DelegateInvokeMethod.HasUseSiteError, + Debug.Assert((object)delegateInvokeMethod != null && !delegateInvokeMethod.HasUseSiteError, "This method should only be called for valid delegate types"); - GetDelegateArguments(syntax, analyzedArguments, delegateType.DelegateInvokeMethod.Parameters, Compilation); + GetDelegateArguments(syntax, analyzedArguments, delegateInvokeMethod.Parameters, Compilation); _binder.OverloadResolution.MethodInvocationOverloadResolution( - methodGroup.Methods, methodGroup.TypeArguments, analyzedArguments, result, ref useSiteDiagnostics, isMethodGroupConversion: true); + methods: methodGroup.Methods, + typeArguments: methodGroup.TypeArguments, + receiver: methodGroup.Receiver, + arguments: analyzedArguments, + result: result, + useSiteDiagnostics: ref useSiteDiagnostics, + isMethodGroupConversion: true, + returnRefKind: delegateInvokeMethod.RefKind, + returnType: delegateInvokeMethod.ReturnType); var conversion = ToConversion(result, methodGroup, delegateType); analyzedArguments.Free(); diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs index f04fae2774315..c1992fed26e64 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs @@ -1,8 +1,11 @@ // 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.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp @@ -14,6 +17,7 @@ internal struct MemberAnalysisResult public readonly ImmutableArray ConversionsOpt; public readonly ImmutableArray BadArgumentsOpt; public readonly ImmutableArray ArgsToParamsOpt; + public readonly ArrayBuilder ConstraintFailureDiagnosticsOpt; public readonly int BadParameter; public readonly MemberResolutionKind Kind; @@ -25,17 +29,18 @@ internal struct MemberAnalysisResult public readonly bool HasAnyRefOmittedArgument; private MemberAnalysisResult(MemberResolutionKind kind) - : this(kind, default(ImmutableArray), default(ImmutableArray), default(ImmutableArray)) + : this(kind, constraintFailureDiagnosticsOpt: default) { } private MemberAnalysisResult( MemberResolutionKind kind, - ImmutableArray badArgumentsOpt, - ImmutableArray argsToParamsOpt, - ImmutableArray conversionsOpt, + ImmutableArray badArgumentsOpt = default, + ImmutableArray argsToParamsOpt = default, + ImmutableArray conversionsOpt = default, int missingParameter = -1, - bool hasAnyRefOmittedArgument = false) + bool hasAnyRefOmittedArgument = false, + ArrayBuilder constraintFailureDiagnosticsOpt = null) { this.Kind = kind; this.BadArgumentsOpt = badArgumentsOpt; @@ -43,6 +48,7 @@ private MemberAnalysisResult( this.ConversionsOpt = conversionsOpt; this.BadParameter = missingParameter; this.HasAnyRefOmittedArgument = hasAnyRefOmittedArgument; + this.ConstraintFailureDiagnosticsOpt = constraintFailureDiagnosticsOpt; } public override bool Equals(object obj) @@ -164,45 +170,34 @@ public static MemberAnalysisResult NameUsedForPositional(int argumentPosition) { return new MemberAnalysisResult( MemberResolutionKind.NameUsedForPositional, - ImmutableArray.Create(argumentPosition), - default(ImmutableArray), - default(ImmutableArray)); + badArgumentsOpt: ImmutableArray.Create(argumentPosition)); } public static MemberAnalysisResult BadNonTrailingNamedArgument(int argumentPosition) { return new MemberAnalysisResult( MemberResolutionKind.BadNonTrailingNamedArgument, - ImmutableArray.Create(argumentPosition), - default(ImmutableArray), - default(ImmutableArray)); + badArgumentsOpt: ImmutableArray.Create(argumentPosition)); } public static MemberAnalysisResult NoCorrespondingParameter(int argumentPosition) { return new MemberAnalysisResult( MemberResolutionKind.NoCorrespondingParameter, - ImmutableArray.Create(argumentPosition), - default(ImmutableArray), - default(ImmutableArray)); + badArgumentsOpt: ImmutableArray.Create(argumentPosition)); } public static MemberAnalysisResult NoCorrespondingNamedParameter(int argumentPosition) { return new MemberAnalysisResult( MemberResolutionKind.NoCorrespondingNamedParameter, - ImmutableArray.Create(argumentPosition), - default(ImmutableArray), - default(ImmutableArray)); + badArgumentsOpt: ImmutableArray.Create(argumentPosition)); } public static MemberAnalysisResult RequiredParameterMissing(int parameterPosition) { return new MemberAnalysisResult( MemberResolutionKind.RequiredParameterMissing, - default(ImmutableArray), - default(ImmutableArray), - default(ImmutableArray), missingParameter: parameterPosition); } @@ -242,16 +237,28 @@ public static MemberAnalysisResult TypeInferenceExtensionInstanceArgumentFailed( return new MemberAnalysisResult(MemberResolutionKind.TypeInferenceExtensionInstanceArgument); } + public static MemberAnalysisResult StaticInstanceMismatch() + { + return new MemberAnalysisResult(MemberResolutionKind.StaticInstanceMismatch); + } + public static MemberAnalysisResult ConstructedParameterFailedConstraintsCheck(int parameterPosition) { return new MemberAnalysisResult( MemberResolutionKind.ConstructedParameterFailedConstraintCheck, - default(ImmutableArray), - default(ImmutableArray), - default(ImmutableArray), missingParameter: parameterPosition); } + public static MemberAnalysisResult WrongRefKind() + { + return new MemberAnalysisResult(MemberResolutionKind.WrongRefKind); + } + + public static MemberAnalysisResult WrongReturnType() + { + return new MemberAnalysisResult(MemberResolutionKind.WrongReturnType); + } + public static MemberAnalysisResult LessDerived() { return new MemberAnalysisResult(MemberResolutionKind.LessDerived); @@ -276,5 +283,10 @@ public static MemberAnalysisResult Worst() { return new MemberAnalysisResult(MemberResolutionKind.Worst); } + + internal static MemberAnalysisResult ConstraintFailure(ArrayBuilder constraintFailureDiagnostics) + { + return new MemberAnalysisResult(MemberResolutionKind.ConstraintFailure, constraintFailureDiagnosticsOpt: constraintFailureDiagnostics); + } } } diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberResolutionKind.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberResolutionKind.cs index d4cb85d243311..7d92f3075402a 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberResolutionKind.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberResolutionKind.cs @@ -93,10 +93,31 @@ internal enum MemberResolutionKind : byte TypeInferenceExtensionInstanceArgument, /// - /// The candidate member was rejected because it a constraint on a type parameter was not satisfied. + /// The candidate member was rejected because a constraint on the type of a parameter was not satisfied. /// ConstructedParameterFailedConstraintCheck, + /// + /// The candidate method's type arguments do not satisfy their constraints. + /// + ConstraintFailure, + + /// + /// The candidate member was rejected because it was an instance member accessed from a type, + /// or a static member accessed from an instance. + /// + StaticInstanceMismatch, + + /// + /// The candidate method in a delegate conversion was rejected because the ref kind of its return does not match the delegate. + /// + WrongRefKind, + + /// + /// The candidate method in a delegate conversion was rejected because its return type does not match the return type of the delegate. + /// + WrongReturnType, + /// /// The candidate member was rejected because another member further down in the inheritance hierarchy was /// present. diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs index d6169a8534b8e..ed26a29d69481 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs @@ -1320,10 +1320,11 @@ private bool MethodGroupReturnTypeInference(Binder binder, BoundExpression sourc // this part of the code is only called if the targetType has an unfixed type argument in the output // type, which is not the case for invalid delegate invoke methods. - Debug.Assert((object)delegateType.DelegateInvokeMethod != null && !delegateType.DelegateInvokeMethod.HasUseSiteError, + var delegateInvokeMethod = delegateType.DelegateInvokeMethod; + Debug.Assert((object)delegateInvokeMethod != null && !delegateType.DelegateInvokeMethod.HasUseSiteError, "This method should only be called for valid delegate types"); - TypeSymbol delegateReturnType = delegateType.DelegateInvokeMethod.ReturnType; + TypeSymbol delegateReturnType = delegateInvokeMethod.ReturnType; if ((object)delegateReturnType == null || delegateReturnType.SpecialType == SpecialType.System_Void) { return false; @@ -1337,7 +1338,7 @@ private bool MethodGroupReturnTypeInference(Binder binder, BoundExpression sourc return false; } - var returnType = MethodGroupReturnType(binder, (BoundMethodGroup)source, fixedDelegateParameters, ref useSiteDiagnostics); + var returnType = MethodGroupReturnType(binder, (BoundMethodGroup)source, fixedDelegateParameters, delegateInvokeMethod.RefKind, ref useSiteDiagnostics); if ((object)returnType == null || returnType.SpecialType == SpecialType.System_Void) { return false; @@ -1348,12 +1349,19 @@ private bool MethodGroupReturnTypeInference(Binder binder, BoundExpression sourc return true; } - private static TypeSymbol MethodGroupReturnType(Binder binder, BoundMethodGroup source, ImmutableArray delegateParameters, ref HashSet useSiteDiagnostics) + private static TypeSymbol MethodGroupReturnType( + Binder binder, BoundMethodGroup source, + ImmutableArray delegateParameters, + RefKind delegateRefKind, + ref HashSet useSiteDiagnostics) { var analyzedArguments = AnalyzedArguments.GetInstance(); Conversions.GetDelegateArguments(source.Syntax, analyzedArguments, delegateParameters, binder.Compilation); - var resolution = binder.ResolveMethodGroup(source, analyzedArguments, isMethodGroupConversion: true, useSiteDiagnostics: ref useSiteDiagnostics); + var resolution = binder.ResolveMethodGroup(source, analyzedArguments, useSiteDiagnostics: ref useSiteDiagnostics, + isMethodGroupConversion: true, returnRefKind: delegateRefKind, + // Since we are trying to infer the return type, it is not an input to resolving the method group + returnType: null); TypeSymbol type = null; diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs index 4ed48bd45b8a1..c0d498145b709 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs @@ -1,5 +1,6 @@ // 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; @@ -110,60 +111,77 @@ public void ObjectCreationOverloadResolution(ImmutableArray constr public void MethodInvocationOverloadResolution( ArrayBuilder methods, ArrayBuilder typeArguments, + BoundExpression receiver, AnalyzedArguments arguments, OverloadResolutionResult result, ref HashSet useSiteDiagnostics, bool isMethodGroupConversion = false, bool allowRefOmittedArguments = false, bool inferWithDynamic = false, - bool allowUnexpandedForm = true) + bool allowUnexpandedForm = true, + RefKind returnRefKind = default, + TypeSymbol returnType = null) { MethodOrPropertyOverloadResolution( - methods, typeArguments, arguments, result, isMethodGroupConversion, + methods, typeArguments, receiver, arguments, result, isMethodGroupConversion, allowRefOmittedArguments, ref useSiteDiagnostics, inferWithDynamic: inferWithDynamic, - allowUnexpandedForm: allowUnexpandedForm); + allowUnexpandedForm: allowUnexpandedForm, + returnRefKind: returnRefKind, + returnType: returnType); } // Perform overload resolution on the given property group, with the given arguments and // names. The names can be null if no names were supplied to any arguments. public void PropertyOverloadResolution( ArrayBuilder indexers, + BoundExpression receiverOpt, AnalyzedArguments arguments, OverloadResolutionResult result, bool allowRefOmittedArguments, ref HashSet useSiteDiagnostics) { ArrayBuilder typeArguments = ArrayBuilder.GetInstance(); - MethodOrPropertyOverloadResolution(indexers, typeArguments, arguments, result, isMethodGroupConversion: false, allowRefOmittedArguments: allowRefOmittedArguments, useSiteDiagnostics: ref useSiteDiagnostics); + MethodOrPropertyOverloadResolution( + indexers, typeArguments, receiverOpt, arguments, result, isMethodGroupConversion: false, + allowRefOmittedArguments: allowRefOmittedArguments, useSiteDiagnostics: ref useSiteDiagnostics); typeArguments.Free(); } internal void MethodOrPropertyOverloadResolution( ArrayBuilder members, ArrayBuilder typeArguments, + BoundExpression receiver, AnalyzedArguments arguments, OverloadResolutionResult result, bool isMethodGroupConversion, bool allowRefOmittedArguments, ref HashSet useSiteDiagnostics, bool inferWithDynamic = false, - bool allowUnexpandedForm = true) + bool allowUnexpandedForm = true, + RefKind returnRefKind = default, + TypeSymbol returnType = null) where TMember : Symbol { var results = result.ResultsBuilder; // First, attempt overload resolution not getting complete results. PerformMemberOverloadResolution( - results, members, typeArguments, arguments, false, isMethodGroupConversion, - allowRefOmittedArguments, ref useSiteDiagnostics, inferWithDynamic: inferWithDynamic, - allowUnexpandedForm: allowUnexpandedForm); + results: results, members: members, typeArguments: typeArguments, + receiver: receiver, arguments: arguments, completeResults: false, + isMethodGroupConversion: isMethodGroupConversion, returnRefKind: returnRefKind, returnType: returnType, + allowRefOmittedArguments: allowRefOmittedArguments, useSiteDiagnostics: ref useSiteDiagnostics, + inferWithDynamic: inferWithDynamic, allowUnexpandedForm: allowUnexpandedForm); if (!OverloadResolutionResultIsValid(results, arguments.HasDynamicArgument)) { // We didn't get a single good result. Get full results of overload resolution and return those. result.Clear(); - PerformMemberOverloadResolution(results, members, typeArguments, arguments, true, isMethodGroupConversion, - allowRefOmittedArguments, ref useSiteDiagnostics, allowUnexpandedForm: allowUnexpandedForm); + PerformMemberOverloadResolution( + results: results, members: members, typeArguments: typeArguments, + receiver: receiver, arguments: arguments, completeResults: true, + isMethodGroupConversion: isMethodGroupConversion, returnRefKind: returnRefKind, returnType: returnType, + allowRefOmittedArguments: allowRefOmittedArguments, useSiteDiagnostics: ref useSiteDiagnostics, + allowUnexpandedForm: allowUnexpandedForm); } } @@ -205,9 +223,12 @@ private void PerformMemberOverloadResolution( ArrayBuilder> results, ArrayBuilder members, ArrayBuilder typeArguments, + BoundExpression receiver, AnalyzedArguments arguments, bool completeResults, bool isMethodGroupConversion, + RefKind returnRefKind, + TypeSymbol returnType, bool allowRefOmittedArguments, ref HashSet useSiteDiagnostics, bool inferWithDynamic = false, @@ -236,7 +257,7 @@ private void PerformMemberOverloadResolution( for (int i = 0; i < members.Count; i++) { AddMemberToCandidateSet( - members[i], results, members, typeArguments, arguments, completeResults, + members[i], results, members, typeArguments, receiver, arguments, completeResults, isMethodGroupConversion, allowRefOmittedArguments, containingTypeMapOpt, inferWithDynamic: inferWithDynamic, useSiteDiagnostics: ref useSiteDiagnostics, allowUnexpandedForm: allowUnexpandedForm); } @@ -252,6 +273,18 @@ private void PerformMemberOverloadResolution( // SPEC: The set of candidate methods is reduced to contain only methods from the most derived types. RemoveLessDerivedMembers(results, ref useSiteDiagnostics); + if (Compilation.LanguageVersion.AllowImprovedOverloadCandidates()) + { + RemoveStaticInstanceMismatches(results, arguments, receiver); + + RemoveConstraintViolations(results); + + if (isMethodGroupConversion) + { + RemoveDelegateConversionsWithWrongReturnType(results, ref useSiteDiagnostics, returnRefKind, returnType); + } + } + // NB: As in dev12, we do this AFTER removing less derived members. // Also note that less derived members are not actually removed - they are simply flagged. ReportUseSiteDiagnostics(results, ref useSiteDiagnostics); @@ -273,6 +306,149 @@ private void PerformMemberOverloadResolution( // as that is not part of overload resolution. } + private void RemoveStaticInstanceMismatches( + ArrayBuilder> results, + AnalyzedArguments arguments, + BoundExpression receiverOpt) where TMember : Symbol + { + // When the feature 'ImprovedOverloadCandidates' is enabled, we do not include instance members when the receiver + // is a type, or static members when the receiver is an instance. This does not apply to extension method invocations, + // because extension methods are only considered when the receiver is an instance. It also does not apply when the + // receiver is a TypeOrValueExpression, which is used to handle the receiver of a Color-Color ambiguity, where either + // an instance or a static member would be acceptable. + if (arguments.IsExtensionMethodInvocation || Binder.IsTypeOrValueExpression(receiverOpt)) + { + return; + } + + bool isImplicitReceiver = Binder.WasImplicitReceiver(receiverOpt); + // isStaticContext includes both places where `this` isn't available, and places where it + // cannot be used (e.g. a field initializer or a constructor-initializer) + bool isStaticContext = !_binder.HasThis(!isImplicitReceiver, out bool inStaticContext) || inStaticContext; + if (isImplicitReceiver && !isStaticContext) + { + return; + } + + // We are in a context where only instance (or only static) methods are permitted. We reject the others. + bool keepStatic = isImplicitReceiver && isStaticContext || Binder.IsMemberAccessedThroughType(receiverOpt); + + for (int f = 0; f < results.Count; ++f) + { + var result = results[f]; + TMember member = result.Member; + if (result.Result.IsValid && member.IsStatic != keepStatic) + { + results[f] = new MemberResolutionResult(member, result.LeastOverriddenMember, MemberAnalysisResult.StaticInstanceMismatch()); + } + } + } + + private void RemoveConstraintViolations(ArrayBuilder> results) where TMember : Symbol + { + // When the feature 'ImprovedOverloadCandidates' is enabled, we do not include methods for which the type arguments + // violate the constraints of the method's type parameters. + + // Constraint violations apply to method in a method group, not to properties in a "property group". + if (typeof(TMember) != typeof(MethodSymbol)) + { + return; + } + + for (int f = 0; f < results.Count; ++f) + { + var result = results[f]; + var member = (MethodSymbol)(Symbol)result.Member; + // a constraint failure on the method trumps (for reporting purposes) a previously-detected + // constraint failure on the constructed type of a parameter + if ((result.Result.IsValid || result.Result.Kind == MemberResolutionKind.ConstructedParameterFailedConstraintCheck) && + FailsConstraintChecks(member, out ArrayBuilder constraintFailureDiagnosticsOpt)) + { + results[f] = new MemberResolutionResult( + result.Member, result.LeastOverriddenMember, MemberAnalysisResult.ConstraintFailure(constraintFailureDiagnosticsOpt)); + } + } + } + + private bool FailsConstraintChecks(MethodSymbol method, out ArrayBuilder constraintFailureDiagnosticsOpt) + { + if (method.Arity == 0 || method.OriginalDefinition == (object)method) + { + constraintFailureDiagnosticsOpt = null; + return false; + } + + var diagnosticsBuilder = ArrayBuilder.GetInstance(); + ArrayBuilder useSiteDiagnosticsBuilder = null; + var constraintsSatisfied = ConstraintsHelper.CheckMethodConstraints( + method, + this.Conversions, + this.Compilation, + diagnosticsBuilder, + ref useSiteDiagnosticsBuilder); + + if (!constraintsSatisfied) + { + if (useSiteDiagnosticsBuilder != null) + { + diagnosticsBuilder.AddRange(useSiteDiagnosticsBuilder); + useSiteDiagnosticsBuilder.Free(); + } + + constraintFailureDiagnosticsOpt = diagnosticsBuilder; + return true; + } + + diagnosticsBuilder.Free(); + useSiteDiagnosticsBuilder?.Free(); + constraintFailureDiagnosticsOpt = null; + return false; + } + + /// + /// Remove candidates to a delegate conversion where the method's return ref kind or return type is wrong. + /// + /// The ref kind of the delegate's return, if known. This is only unknown in + /// error scenarios, such as a delegate type that has no invoke method. + /// The return type of the delegate, if known. It isn't + /// known when we're attempting to infer the return type of a method group for type inference. + private void RemoveDelegateConversionsWithWrongReturnType( + ArrayBuilder> results, + ref HashSet useSiteDiagnostics, + RefKind? returnRefKind, + TypeSymbol returnType) where TMember : Symbol + { + // When the feature 'ImprovedOverloadCandidates' is enabled, then a delegate conversion overload resolution + // rejects candidates that have the wrong return ref kind or return type. + + // Delegate conversions apply to method in a method group, not to properties in a "property group". + Debug.Assert(typeof(TMember) == typeof(MethodSymbol)); + + for (int f = 0; f < results.Count; ++f) + { + var result = results[f]; + if (!result.Result.IsValid) + { + continue; + } + + var method = (MethodSymbol)(Symbol)result.Member; + bool returnsMatch = returnType == null || + method.ReturnType.Equals(returnType, TypeCompareKind.AllIgnoreOptions) || + returnRefKind == RefKind.None && Conversions.HasIdentityOrImplicitReferenceConversion(method.ReturnType, returnType, ref useSiteDiagnostics); + if (!returnsMatch) + { + results[f] = new MemberResolutionResult( + result.Member, result.LeastOverriddenMember, MemberAnalysisResult.WrongReturnType()); + } + else if (method.RefKind != returnRefKind) + { + results[f] = new MemberResolutionResult( + result.Member, result.LeastOverriddenMember, MemberAnalysisResult.WrongRefKind()); + } + } + } + private static Dictionary> PartitionMembersByContainingType(ArrayBuilder members) where TMember : Symbol { Dictionary> containingTypeMap = new Dictionary>(); @@ -424,6 +600,7 @@ private void AddMemberToCandidateSet( ArrayBuilder> results, ArrayBuilder members, ArrayBuilder typeArguments, + BoundExpression receiverOpt, AnalyzedArguments arguments, bool completeResults, bool isMethodGroupConversion, @@ -2943,7 +3120,9 @@ private MemberResolutionResult IsApplicable( // // Suppose there is a call M("", null). Type inference infers that T is string. // M is then not an applicable candidate *NOT* because string violates the - // constraint on T. That is not checked until "final validation". Rather, the + // constraint on T. That is not checked until "final validation" (although when + // feature 'ImprovedOverloadCandidates' is enabled in later language versions + // it is checked on the candidate before overload resolution). Rather, the // method is not a candidate because string violates the constraint *on U*. // The constructed method has formal parameter type X, which is not legal. // In the case given, the generic method is eliminated and the object version wins. diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs index ad08d7943b7bf..19d9a49fe5175 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; +using System; #if DEBUG using System.Text; @@ -184,15 +185,19 @@ private static ThreeState TryGetBestResult(ArrayBuilder( Binder binder, Location location, + SyntaxNode nodeOpt, DiagnosticBag diagnostics, string name, BoundExpression receiver, + SyntaxNode invokedExpression, AnalyzedArguments arguments, ImmutableArray memberGroup, // the T is just a convenience for the caller NamedTypeSymbol typeContainingConstructor, NamedTypeSymbol delegateTypeBeingInvoked, CSharpSyntaxNode queryClause = null, - bool isMethodGroupConversion = false) where T : Symbol + bool isMethodGroupConversion = false, + RefKind? returnRefKind = null, + TypeSymbol delegateType = null) where T : Symbol { Debug.Assert(!this.Succeeded, "Don't ask for diagnostic info on a successful overload resolution result."); @@ -257,15 +262,35 @@ internal void ReportDiagnostics( // do so, then odds are extremely good that the failure is the ultimate cause // of the overload resolution failing to find any applicable method. Report // the errors out of each lambda argument, if there were any. + // NOTE: There isn't a MemberResolutionKind for this error condition. if (HadLambdaConversionError(diagnostics, arguments)) { return; } - // NOTE: There isn't a MemberResolutionKind for this error condition. + // If there is any instance(or alternatively static) method accessed through a + // type(or alternatively expression) then the first such method is the best bad method. + // To retain existing behavior, we use the location of the invoked expression for the error. + + if (HadStaticInstanceMismatch(diagnostics, symbols, invokedExpression?.GetLocation() ?? location, binder, receiver, nodeOpt)) + { + return; + } + + // When overload resolution is being done to resolve a method group conversion (to a delegate type), + // if there is any method being converted to a delegate type, but the method's return + // ref kind does not match the delegate, then the first such method is the best bad method. + // Otherwise if there is any method whose return type does not match the delegate, then the + // first such method is the best bad method + + if (isMethodGroupConversion && returnRefKind != null && + HadReturnMismatch(location, diagnostics, returnRefKind.GetValueOrDefault(), delegateType)) + { + return; + } - // If there is any such method that has a bad conversion or out/ref mismatch + // Otherwise, f there is any such method that has a bad conversion or out/ref mismatch // then the first such method found is the best bad method. if (HadBadArguments(diagnostics, binder.Compilation, name, arguments, symbols, location, binder.Flags, isMethodGroupConversion)) @@ -277,10 +302,19 @@ internal void ReportDiagnostics( AssertNone(MemberResolutionKind.BadArguments); // Otherwise, if there is any such method where type inference succeeded but inferred - // a type that violates its own constraints then the first such method is + // type arguments that violate the constraints on the method, then the first such method is + // the best bad method. + + if (HadConstraintFailure(location, diagnostics)) + { + return; + } + + // Otherwise, if there is any such method where type inference succeeded but inferred + // a parameter type that violates its own constraints then the first such method is // the best bad method. - if (ConstraintsCheckFailed(binder.Conversions, binder.Compilation, diagnostics, location)) + if (HadConstructedParameterFailedConstraintCheck(binder.Conversions, binder.Compilation, diagnostics, location)) { return; } @@ -528,6 +562,90 @@ private bool InaccessibleTypeArgument( return true; } + private bool HadStaticInstanceMismatch( + DiagnosticBag diagnostics, + ImmutableArray symbols, + Location location, + Binder binder, + BoundExpression receiverOpt, + SyntaxNode nodeOpt) + { + var staticInstanceMismatch = GetFirstMemberKind(MemberResolutionKind.StaticInstanceMismatch); + if (staticInstanceMismatch.IsNull) + { + return false; + } + + Symbol symbol = staticInstanceMismatch.Member; + + // Certain compiler-generated invocations produce custom diagnostics. + if (receiverOpt?.Kind == BoundKind.QueryClause) + { + // Could not find an implementation of the query pattern for source type '{0}'. '{1}' not found. + diagnostics.Add(ErrorCode.ERR_QueryNoProvider, location, receiverOpt.Type, symbol.Name); + } + else if (binder.Flags.Includes(BinderFlags.CollectionInitializerAddMethod)) + { + diagnostics.Add(ErrorCode.ERR_InitializerAddHasWrongSignature, location, symbol); + } + else if (nodeOpt?.Kind() == SyntaxKind.AwaitExpression && symbol.Name == WellKnownMemberNames.GetAwaiter) + { + diagnostics.Add(ErrorCode.ERR_BadAwaitArg, location, receiverOpt.Type); + } + else + { + ErrorCode errorCode = + symbol.IsStatic ? ErrorCode.ERR_ObjectProhibited : + Binder.WasImplicitReceiver(receiverOpt) && binder.InFieldInitializer && !binder.BindingTopLevelScriptCode ? ErrorCode.ERR_FieldInitRefNonstatic : + ErrorCode.ERR_ObjectRequired; + // error CS0176: Member 'Program.M(B)' cannot be accessed with an instance reference; qualify it with a type name instead + // -or- + // error CS0120: An object reference is required for the non-static field, method, or property 'Program.M(B)' + diagnostics.Add(new DiagnosticInfoWithSymbols( + errorCode, + new object[] { symbol }, + symbols), location); + } + + return true; + } + + private bool HadReturnMismatch(Location location, DiagnosticBag diagnostics, RefKind refKind, TypeSymbol delegateType) + { + var mismatch = GetFirstMemberKind(MemberResolutionKind.WrongRefKind); + if (!mismatch.IsNull) + { + diagnostics.Add(ErrorCode.ERR_DelegateRefMismatch, location, mismatch.Member, delegateType); + return true; + } + + mismatch = GetFirstMemberKind(MemberResolutionKind.WrongReturnType); + if (!mismatch.IsNull) + { + var method = (MethodSymbol)(Symbol)mismatch.Member; + diagnostics.Add(ErrorCode.ERR_BadRetType, location, method, method.ReturnType); + return true; + } + + return false; + } + + private bool HadConstraintFailure(Location location, DiagnosticBag diagnostics) + { + var constraintFailure = GetFirstMemberKind(MemberResolutionKind.ConstraintFailure); + if (constraintFailure.IsNull) + { + return false; + } + + foreach (var pair in constraintFailure.Result.ConstraintFailureDiagnosticsOpt) + { + diagnostics.Add(new CSDiagnostic(pair.DiagnosticInfo, location)); + } + + return true; + } + private bool TypeInferenceFailed( Binder binder, DiagnosticBag diagnostics, @@ -738,7 +856,7 @@ private static void ReportBadParameterCount( return; } - private bool ConstraintsCheckFailed( + private bool HadConstructedParameterFailedConstraintCheck( ConversionsBase conversions, Compilation compilation, DiagnosticBag diagnostics, @@ -763,8 +881,11 @@ private bool ConstraintsCheckFailed( // rather that the constraint on *Nullable* is violated; Nullable is not a legal // type, and so this is not an applicable candidate. // - // Checking whether constraints are violated *on T in Q* happens *after* overload resolution - // successfully chooses a unique best method. + // In language versions before the feature 'ImprovedOverloadCandidates' was added to the language, + // checking whether constraints are violated *on T in Q* occurs *after* overload resolution + // successfully chooses a unique best method; but with the addition of the + // feature 'ImprovedOverloadCandidates', constraint checks on the method's own type arguments + // occurs during candidate selection. // // Note that this failure need not involve type inference; Q(null, null) would also be // illegal for the same reason. diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 4f5b1d799f80c..4a02efdaa4c87 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -4841,7 +4841,7 @@ internal static string ERR_FloatOverflow { } /// - /// Looks up a localized string similar to foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. + /// Looks up a localized string similar to foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. /// internal static string ERR_ForEachMissingMember { get { diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 3178e2140048f..b7d744c72165f 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -2604,7 +2604,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep #r is only allowed in scripts - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' Invalid type for parameter {0} in XML comment cref attribute: '{1}' diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.NodeMapBuilder.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.NodeMapBuilder.cs index 302d7bbc5040e..62ad5fa5cc387 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.NodeMapBuilder.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.NodeMapBuilder.cs @@ -49,7 +49,7 @@ public static void AddToMap(BoundNode root, Dictionary= MessageID.IDS_FeatureAttributesOnBackingFields.RequiredVersion(); } + + internal static bool AllowImprovedOverloadCandidates(this LanguageVersion self) + { + return self >= MessageID.IDS_FeatureImprovedOverloadCandidates.RequiredVersion(); + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs index e6076dff7deea..2c22277f35828 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs @@ -613,8 +613,7 @@ public static bool CheckConstraints( ConversionsBase conversions, SyntaxNode syntaxNode, Compilation currentCompilation, - DiagnosticBag diagnostics, - BitVector skipParameters = default(BitVector)) + DiagnosticBag diagnostics) { if (!RequiresChecking(method)) { @@ -623,7 +622,7 @@ public static bool CheckConstraints( var diagnosticsBuilder = ArrayBuilder.GetInstance(); ArrayBuilder useSiteDiagnosticsBuilder = null; - var result = CheckMethodConstraints(method, conversions, currentCompilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder, skipParameters); + var result = CheckMethodConstraints(method, conversions, currentCompilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder); if (useSiteDiagnosticsBuilder != null) { @@ -688,7 +687,7 @@ private static bool CheckTypeConstraints( ref useSiteDiagnosticsBuilder); } - private static bool CheckMethodConstraints( + public static bool CheckMethodConstraints( MethodSymbol method, ConversionsBase conversions, Compilation currentCompilation, @@ -774,6 +773,7 @@ private static bool CheckConstraints( HashSet ignoreTypeConstraintsDependentOnTypeParametersOpt) { Debug.Assert(substitution != null); + // The type parameters must be original definitions of type parameters from the containing symbol. Debug.Assert(ReferenceEquals(typeParameter.ContainingSymbol, containingSymbol.OriginalDefinition)); diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 295b41afcae2e..acc94c24d0715 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -4141,8 +4141,8 @@ Blok catch() po bloku catch (System.Exception e) může zachytit výjimky, kter - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - Příkaz foreach nejde použít pro proměnné typu {0}, protože {0} neobsahuje veřejnou definici pro {1}. + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + Příkaz foreach nejde použít pro proměnné typu {0}, protože {0} neobsahuje veřejnou definici pro {1}. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index f83a782a786fa..7b87e16901634 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -4141,8 +4141,8 @@ Ein catch()-Block nach einem catch (System.Exception e)-Block kann nicht-CLS-Aus - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - Eine foreach-Anweisung kann nicht für Variablen vom Typ "{0}" verwendet werden, da "{0}" keine öffentliche Definition für "{1}" enthält. + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + Eine foreach-Anweisung kann nicht für Variablen vom Typ "{0}" verwendet werden, da "{0}" keine öffentliche Definition für "{1}" enthält. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 8d4feb9eacc7e..263153c19ae24 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -4141,8 +4141,8 @@ Un bloque catch() después de un bloque catch (System.Exception e) puede abarcar - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - La instrucción foreach no puede funcionar en variables de tipo '{0}' porque '{0}' no contiene ninguna definición pública para '{1}' + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + La instrucción foreach no puede funcionar en variables de tipo '{0}' porque '{0}' no contiene ninguna definición pública para '{1}' diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 4bd455eb0860a..2f256d8c4bad6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -4141,8 +4141,8 @@ Un bloc catch() après un bloc catch (System.Exception e) peut intercepter des e - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - L'instruction foreach ne peut pas fonctionner sur des variables de type '{0}', car '{0}' ne contient pas de définition publique pour '{1}' + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + L'instruction foreach ne peut pas fonctionner sur des variables de type '{0}', car '{0}' ne contient pas de définition publique pour '{1}' diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 6b71e3ed4adcf..4ab1dc95b0aba 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -4141,8 +4141,8 @@ Un blocco catch() dopo un blocco catch (System.Exception e) è in grado di rilev - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - L'istruzione foreach non può funzionare con variabili di tipo '{0}' perché '{0}' non contiene una definizione pubblica per '{1}' + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + L'istruzione foreach non può funzionare con variabili di tipo '{0}' perché '{0}' non contiene una definizione pubblica per '{1}' diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index b0ba89a18fde3..935b77d9d8397 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -4141,8 +4141,8 @@ AssemblyInfo.cs ファイルで RuntimeCompatibilityAttribute が false に設 - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - foreach ステートメントは、'{0}' が '{1}' のパブリック定義を含んでいないため、型 '{0}' の変数に対して使用できません。 + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + foreach ステートメントは、'{0}' が '{1}' のパブリック定義を含んでいないため、型 '{0}' の変数に対して使用できません。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 5964ba1d21d98..053a848aee946 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -4141,8 +4141,8 @@ catch (System.Exception e) 블록 뒤의 catch() 블록은 RuntimeCompatibilityA - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - {0}'에는 '{1}'에 대한 공용 정의가 포함되어 있지 않아 '{0}' 형식 변수에서 foreach 문을 수행할 수 없습니다. + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + {0}'에는 '{1}'에 대한 공용 정의가 포함되어 있지 않아 '{0}' 형식 변수에서 foreach 문을 수행할 수 없습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 3fa8d88eb9e3c..f4a8f3e6859de 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -4141,8 +4141,8 @@ Blok catch() po bloku catch (System.Exception e) może przechwytywać wyjątki n - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - Instrukcja foreach nie może operować na zmiennych typu „{0}”, ponieważ „{0}” nie zawiera definicji publicznej elementu „{1}” + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + Instrukcja foreach nie może operować na zmiennych typu „{0}”, ponieważ „{0}” nie zawiera definicji publicznej elementu „{1}” diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 8da7eec0a3595..201e1b77935a2 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -4141,8 +4141,8 @@ Um bloco catch() depois de um bloco catch (System.Exception e) poderá capturar - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - Instrução foreach não pode operar em variáveis do tipo "{0}" porque "{0}" não contém uma definição pública para "{1}" + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + Instrução foreach não pode operar em variáveis do tipo "{0}" porque "{0}" não contém uma definição pública para "{1}" diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 395bfa09caa9e..d44eeb2c221e0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -4141,8 +4141,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - Оператор foreach не работает с переменными типа "{0}", так как "{0}" не содержит открытого определения для "{1}". + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + Оператор foreach не работает с переменными типа "{0}", так как "{0}" не содержит открытого определения для "{1}". diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index d0f8bdb24ce06..cc734920e8e4a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -4141,8 +4141,8 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - {0}' bir '{1}' ortak tanım içermediğinden veya erişilemez olduğundan foreach deyimi '{0}' türündeki değişkenlerde çalışamaz + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + {0}' bir '{1}' ortak tanım içermediğinden veya erişilemez olduğundan foreach deyimi '{0}' türündeki değişkenlerde çalışamaz diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index a6567020b924a..4278b44d63ace 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -4141,8 +4141,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - “{0}”不包含“{1}”的公共定义,因此 foreach 语句不能作用于“{0}”类型的变量 + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + “{0}”不包含“{1}”的公共定义,因此 foreach 语句不能作用于“{0}”类型的变量 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 862c51a1a77e7..a6f7959aff069 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -4141,8 +4141,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}' - foreach 陳述式不可用在類型 '{0}' 的變數上,因為 '{0}' 未包含 '{1}' 的公用定義。 + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}' + foreach 陳述式不可用在類型 '{0}' 的變數上,因為 '{0}' 未包含 '{1}' 的公用定義。 diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs index d584968000e0e..c2d03b4960c36 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs @@ -2784,7 +2784,7 @@ static void Main() } }"; - CreateStandardCompilation(source).VerifyDiagnostics( + CreateStandardCompilation(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (24,13): error CS8189: Ref mismatch between 'A.F()' and delegate 'D' // B.F(o.F, 2); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A.F()", "D").WithLocation(24, 13), @@ -2792,6 +2792,17 @@ static void Main() // B.F(new D(o.F), 3); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A.F()", "D").WithLocation(26, 24) ); + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. + CreateStandardCompilation(source).VerifyDiagnostics( + // (24,13): error CS1503: Argument 1: cannot convert from 'method group' to 'D' + // B.F(o.F, 2); + Diagnostic(ErrorCode.ERR_BadArgType, "o.F").WithArguments("1", "method group", "D").WithLocation(24, 13), + // (26,13): error CS0123: No overload for 'F' matches delegate 'D' + // B.F(new D(o.F), 3); + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D(o.F)").WithArguments("F", "D").WithLocation(26, 13) + ); } [Fact] @@ -2828,7 +2839,7 @@ static void Main() } }"; - CreateStandardCompilation(source).VerifyDiagnostics( + CreateStandardCompilation(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (23,13): error CS8189: Ref mismatch between 'A.F()' and delegate 'D' // B.F(o.F, 2); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A.F()", "D").WithLocation(23, 13), @@ -2836,6 +2847,17 @@ static void Main() // B.F(new D(o.F), 3); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A.F()", "D").WithLocation(25, 24) ); + // NOTE: we now have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. + CreateStandardCompilation(source).VerifyDiagnostics( + // (23,13): error CS1503: Argument 1: cannot convert from 'method group' to 'D' + // B.F(o.F, 2); + Diagnostic(ErrorCode.ERR_BadArgType, "o.F").WithArguments("1", "method group", "D").WithLocation(23, 13), + // (25,13): error CS0123: No overload for 'F' matches delegate 'D' + // B.F(new D(o.F), 3); + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D(o.F)").WithArguments("F", "D").WithLocation(25, 13) + ); } [Fact] @@ -3301,7 +3323,7 @@ static void Main() "; - CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib45AndCSruntime(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics( // (10,30): error CS0407: 'string Program.M1()' has the wrong return type // RefFunc1 f = M1; Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string"), @@ -3309,14 +3331,23 @@ static void Main() // f = new RefFunc1(M1); Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string").WithLocation(13, 34) ); + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. + CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics( + // (10,30): error CS0407: 'string Program.M1()' has the wrong return type + // RefFunc1 f = M1; + Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string").WithLocation(10, 30), + // (13,13): error CS0123: No overload for 'M1' matches delegate 'Program.RefFunc1' + // f = new RefFunc1(M1); + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new RefFunc1(M1)").WithArguments("M1", "Program.RefFunc1").WithLocation(13, 13) + ); } [Fact] public void RefMethodGroupConversionError_WithResolution() { var source = @" -using System; - class Base { public static Base Instance = new Base(); @@ -3347,10 +3378,12 @@ static void Main() "; - CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics( - // (24,38): error CS0407: 'Derived1 Program.M1(Derived1)' has the wrong return type + CreateCompilationWithMscorlib45AndCSruntime(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics( + // (22,38): error CS0407: 'Derived1 Program.M1(Derived1)' has the wrong return type // RefFunc1 f = M1; - Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1(Derived1)", "Derived1").WithLocation(24, 38) + Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1(Derived1)", "Derived1").WithLocation(22, 38) + ); + CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics( ); } @@ -3433,7 +3466,7 @@ static void Main() "; - CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib45AndCSruntime(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics( // (25,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Test(Program.RefFunc1)' and 'Program.Test(Program.RefFunc1)' // Test(M1); Diagnostic(ErrorCode.ERR_AmbigCall, "Test").WithArguments("Program.Test(Program.RefFunc1)", "Program.Test(Program.RefFunc1)").WithLocation(25, 9), @@ -3441,6 +3474,8 @@ static void Main() // Test(M3); Diagnostic(ErrorCode.ERR_AmbigCall, "Test").WithArguments("Program.Test(Program.RefFunc1)", "Program.Test(Program.RefFunc1)").WithLocation(26, 9) ); + CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics( + ); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs index aee9ee75f6608..e6ae7d9701be3 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs @@ -15375,7 +15375,7 @@ static void Main() CreateCompilationWithMscorlib45AndCSruntime(source).VerifyDiagnostics( // (6,16): error CS0236: A field initializer cannot reference the non-static field, method, or property 'M.Test(object)' // object a = Test((dynamic)2); - Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "Test((dynamic)2)").WithArguments("M.Test(object)").WithLocation(6, 16) + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "Test").WithArguments("M.Test(object)").WithLocation(6, 16) ); } @@ -15466,7 +15466,7 @@ static void Main() CreateCompilationWithMscorlib45AndCSruntime(source).VerifyDiagnostics( // (16,31): error CS0120: An object reference is required for the non-static field, method, or property 'M.Test(object)' // public M() : base((object)Test((dynamic)2)) - Diagnostic(ErrorCode.ERR_ObjectRequired, "Test((dynamic)2)").WithArguments("M.Test(object)").WithLocation(16, 31) + Diagnostic(ErrorCode.ERR_ObjectRequired, "Test").WithArguments("M.Test(object)").WithLocation(16, 31) ); } @@ -15499,7 +15499,7 @@ static void Main() CreateCompilationWithMscorlib45AndCSruntime(source).VerifyDiagnostics( // (8,31): error CS0120: An object reference is required for the non-static field, method, or property 'M.Test(object)' // Console.Write((object)Test((dynamic)2)); - Diagnostic(ErrorCode.ERR_ObjectRequired, "Test((dynamic)2)").WithArguments("M.Test(object)").WithLocation(8, 31) + Diagnostic(ErrorCode.ERR_ObjectRequired, "Test").WithArguments("M.Test(object)").WithLocation(8, 31) ); } @@ -15527,7 +15527,7 @@ static void Main() CreateCompilationWithMscorlib45AndCSruntime(source).VerifyDiagnostics( // (4,31): error CS0236: A field initializer cannot reference the non-static field, method, or property 'M.Test(object)' // static object o = (object)Test((dynamic)2); - Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "Test((dynamic)2)").WithArguments("M.Test(object)").WithLocation(4, 31) + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "Test").WithArguments("M.Test(object)").WithLocation(4, 31) ); } @@ -15586,22 +15586,22 @@ static void Main() CreateCompilationWithMscorlib45AndCSruntime(source).VerifyDiagnostics( // (16,29): error CS0236: A field initializer cannot reference the non-static field, method, or property 'C.InstanceMethod(int)' // static int field = (int)InstanceMethod((dynamic)2); - Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "InstanceMethod((dynamic)2)").WithArguments("C.InstanceMethod(int)").WithLocation(16, 29), + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(16, 29), // (30,30): error CS0236: A field initializer cannot reference the non-static field, method, or property 'C.InstanceMethod(int)' // int instanceField = (int)InstanceMethod((dynamic)2); - Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "InstanceMethod((dynamic)2)").WithArguments("C.InstanceMethod(int)").WithLocation(30, 30), + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(30, 30), // (21,25): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod(int)' // return (int)InstanceMethod((dynamic)2); - Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod((dynamic)2)").WithArguments("C.InstanceMethod(int)").WithLocation(21, 25), + Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(21, 25), // (26,21): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod(int)' // return (int)InstanceMethod((dynamic)2); - Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod((dynamic)2)").WithArguments("C.InstanceMethod(int)").WithLocation(26, 21), + Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(26, 21), // (31,33): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod(int)' // public C(int x) : base((int)InstanceMethod((dynamic)x)) - Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod((dynamic)x)").WithArguments("C.InstanceMethod(int)").WithLocation(31, 33), + Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(31, 33), // (34,28): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod(int)' // public C() : this((int)InstanceMethod((dynamic)2)) - Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod((dynamic)2)").WithArguments("C.InstanceMethod(int)").WithLocation(34, 28) + Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(34, 28) ); } @@ -15665,22 +15665,22 @@ static void Main() CreateCompilationWithMscorlib45AndCSruntime(source).VerifyDiagnostics( // (16,29): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod(int)' // static int field = (int)C.InstanceMethod((dynamic)2); - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod((dynamic)2)").WithArguments("C.InstanceMethod(int)").WithLocation(16, 29), + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(16, 29), // (30,30): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod(int)' // int instanceField = (int)C.InstanceMethod((dynamic)2); - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod((dynamic)2)").WithArguments("C.InstanceMethod(int)").WithLocation(30, 30), + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(30, 30), // (21,25): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod(int)' // return (int)C.InstanceMethod((dynamic)2); - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod((dynamic)2)").WithArguments("C.InstanceMethod(int)").WithLocation(21, 25), + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(21, 25), // (26,21): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod(int)' // return (int)C.InstanceMethod((dynamic)2); - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod((dynamic)2)").WithArguments("C.InstanceMethod(int)").WithLocation(26, 21), + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(26, 21), // (31,33): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod(int)' // public C(int x) : base((int)C.InstanceMethod((dynamic)x)) - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod((dynamic)x)").WithArguments("C.InstanceMethod(int)").WithLocation(31, 33), + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(31, 33), // (34,28): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod(int)' // public C() : this((int)C.InstanceMethod((dynamic)2)) - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod((dynamic)2)").WithArguments("C.InstanceMethod(int)").WithLocation(34, 28) + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(34, 28) ); } diff --git a/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs b/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs index cce43c77e3739..705f7179b0389 100644 --- a/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs +++ b/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs @@ -7421,7 +7421,7 @@ int G(out int x) Diagnostic(ErrorCode.ERR_ExpressionVariableInConstructorOrFieldInitializer, "var v1").WithLocation(9, 19), // (9,13): error CS0236: A field initializer cannot reference the non-static field, method, or property 'C.G(out int)' // int F = G(out var v1); - Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "G(out var v1)").WithArguments("C.G(out int)").WithLocation(9, 13), + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "G").WithArguments("C.G(out int)").WithLocation(9, 13), // (13,16): error CS8200: Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers. // : base(out var v3) Diagnostic(ErrorCode.ERR_ExpressionVariableInConstructorOrFieldInitializer, "var v3").WithLocation(13, 16), diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ArrayCreationAndInitializer.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ArrayCreationAndInitializer.cs index 0dd69fd800ec3..cac4cb458768a 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ArrayCreationAndInitializer.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ArrayCreationAndInitializer.cs @@ -858,23 +858,26 @@ public static void F() var a = /**/new string[M()]/**/; } - public object M() => null; + public static object M() => null; } "; string expectedOperationTree = @" IArrayCreationOperation (OperationKind.ArrayCreation, Type: System.String[], IsInvalid) (Syntax: 'new string[M()]') Dimension Sizes(1): - IInvocationOperation ( System.Object C.M()) (OperationKind.Invocation, Type: System.Object, IsInvalid) (Syntax: 'M()') - Instance Receiver: - IInstanceReferenceOperation (OperationKind.InstanceReference, Type: C, IsInvalid, IsImplicit) (Syntax: 'M') - Arguments(0) + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'M()') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + IInvocationOperation (System.Object C.M()) (OperationKind.Invocation, Type: System.Object, IsInvalid) (Syntax: 'M()') + Instance Receiver: + null + Arguments(0) Initializer: null "; var expectedDiagnostics = new DiagnosticDescription[] { - // CS0120: An object reference is required for the non-static field, method, or property 'C.M()' + // file.cs(6,27): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // var a = /**/new string[M()]/**/; - Diagnostic(ErrorCode.ERR_ObjectRequired, "M").WithArguments("C.M()").WithLocation(6, 38) + Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "new string[M()]").WithArguments("object", "int").WithLocation(6, 27) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IDelegateCreationExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IDelegateCreationExpression.cs index 8213f9fef86b1..b3362cea23423 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IDelegateCreationExpression.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IDelegateCreationExpression.cs @@ -1,6 +1,7 @@ // 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.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -521,7 +522,8 @@ void Main() Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "int").WithLocation(7, 30) }; - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics, + parseOptions: TestOptions.WithoutImprovedOverloadCandidates); } [CompilerTrait(CompilerFeature.IOperation)] @@ -540,19 +542,26 @@ void Main() } "; - string expectedOperationTree = @" + VerifyOperationTreeAndDiagnosticsForTest(source, @" IMethodReferenceOperation: System.Int32 Program.M1() (OperationKind.MethodReference, Type: null, IsInvalid) (Syntax: 'M1') Instance Receiver: IInstanceReferenceOperation (OperationKind.InstanceReference, Type: Program, IsInvalid, IsImplicit) (Syntax: 'M1') -"; - var expectedDiagnostics = new DiagnosticDescription[] +", new DiagnosticDescription[] { // CS0407: 'int Program.M1()' has the wrong return type // Action a = /**/M1/**/; Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "int").WithLocation(7, 30) - }; - - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates); + VerifyOperationTreeAndDiagnosticsForTest(source, @" +IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: 'M1') + Children(1): + IInstanceReferenceOperation (OperationKind.InstanceReference, Type: Program, IsInvalid, IsImplicit) (Syntax: 'M1') +", new DiagnosticDescription[] + { + // CS0407: 'int Program.M1()' has the wrong return type + // Action a = /**/M1/**/; + Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "int").WithLocation(7, 30) + }); } [CompilerTrait(CompilerFeature.IOperation)] @@ -742,7 +751,8 @@ void Main() Diagnostic(ErrorCode.ERR_BadRetType, "(Action)M1").WithArguments("Program.M1()", "int").WithLocation(7, 30) }; - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics, + parseOptions: TestOptions.WithoutImprovedOverloadCandidates); } [Fact] @@ -760,20 +770,31 @@ void Main() int M1() => 1; } "; - string expectedOperationTree = @" + VerifyOperationTreeAndDiagnosticsForTest(source, @" IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Action, IsInvalid) (Syntax: '(Action)p.M1') Target: IMethodReferenceOperation: System.Int32 Program.M1() (OperationKind.MethodReference, Type: null, IsInvalid) (Syntax: 'p.M1') Instance Receiver: ILocalReferenceOperation: p (OperationKind.LocalReference, Type: Program, IsInvalid) (Syntax: 'p') -"; - var expectedDiagnostics = new DiagnosticDescription[] { +", new DiagnosticDescription[] { // CS0407: 'int Program.M1()' has the wrong return type // Action a = /**/(Action)p.M1/**/; Diagnostic(ErrorCode.ERR_BadRetType, "(Action)p.M1").WithArguments("Program.M1()", "int").WithLocation(8, 30) - }; - - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates); + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. + VerifyOperationTreeAndDiagnosticsForTest(source, @" +IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Action, IsInvalid) (Syntax: '(Action)p.M1') + Target: + IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: 'p.M1') + Children(1): + ILocalReferenceOperation: p (OperationKind.LocalReference, Type: Program, IsInvalid) (Syntax: 'p') +", new DiagnosticDescription[] { + // file.cs(8,30): error CS0030: Cannot convert type 'method' to 'Action' + // Action a = /**/(Action)p.M1/**/; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(Action)p.M1").WithArguments("method", "System.Action").WithLocation(8, 30) + }); } [CompilerTrait(CompilerFeature.IOperation)] @@ -1049,14 +1070,17 @@ static void M1() string expectedOperationTree = @" IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Action, IsInvalid) (Syntax: 'new Action(this.M1)') Target: - IMethodReferenceOperation: void Program.M1() (Static) (OperationKind.MethodReference, Type: null, IsInvalid) (Syntax: 'this.M1') - Instance Receiver: - IInstanceReferenceOperation (OperationKind.InstanceReference, Type: Program, IsInvalid) (Syntax: 'this') + IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: 'this.M1') + Children(1): + IInstanceReferenceOperation (OperationKind.InstanceReference, Type: Program, IsInvalid) (Syntax: 'this') "; + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. var expectedDiagnostics = new DiagnosticDescription[] { - // (7,41): error CS0176: Member 'Program.M1()' cannot be accessed with an instance reference; qualify it with a type name instead + // file.cs(7,30): error CS0123: No overload for 'M1' matches delegate 'Action' // Action a = /**/new Action(this.M1)/**/; - Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.M1").WithArguments("Program.M1()").WithLocation(7, 41) + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Action(this.M1)").WithArguments("M1", "System.Action").WithLocation(7, 30) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); @@ -1136,20 +1160,31 @@ void Main() int M1() => 1; } "; - string expectedOperationTree = @" + VerifyOperationTreeAndDiagnosticsForTest(source, @" IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Action, IsInvalid) (Syntax: 'new Action(M1)') Target: IMethodReferenceOperation: System.Int32 Program.M1() (OperationKind.MethodReference, Type: null, IsInvalid) (Syntax: 'M1') Instance Receiver: IInstanceReferenceOperation (OperationKind.InstanceReference, Type: Program, IsInvalid, IsImplicit) (Syntax: 'M1') -"; - var expectedDiagnostics = new DiagnosticDescription[] { +", new DiagnosticDescription[] { // CS0407: 'int Program.M1()' has the wrong return type // Action a = /**/new Action(M1)/**/; Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "int").WithLocation(7, 41) - }; - - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates); + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. + VerifyOperationTreeAndDiagnosticsForTest(source, @" +IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Action, IsInvalid) (Syntax: 'new Action(M1)') + Target: + IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: 'M1') + Children(1): + IInstanceReferenceOperation (OperationKind.InstanceReference, Type: Program, IsInvalid, IsImplicit) (Syntax: 'M1') +", new DiagnosticDescription[] { + // file.cs(7,30): error CS0123: No overload for 'M1' matches delegate 'Action' + // Action a = /**/new Action(M1)/**/; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Action(M1)").WithArguments("M1", "System.Action").WithLocation(7, 30) + }); } [CompilerTrait(CompilerFeature.IOperation)] @@ -1477,7 +1512,8 @@ void Main() Diagnostic(ErrorCode.ERR_BadRetType, "(Action)M1").WithArguments("Program.M1()", "int").WithLocation(7, 41) }; - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics, + parseOptions: TestOptions.WithoutImprovedOverloadCandidates); } [CompilerTrait(CompilerFeature.IOperation)] diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IInvocationOperation.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IInvocationOperation.cs index 8b2c52a7ecdf0..220d722179c88 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IInvocationOperation.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IInvocationOperation.cs @@ -25,13 +25,12 @@ public static void M2() } "; string expectedOperationTree = @" -IInvocationOperation ( void C.M1()) (OperationKind.Invocation, Type: System.Void, IsInvalid) (Syntax: 'c.M1()') - Instance Receiver: - ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C, IsInvalid) (Syntax: 'c') - Arguments(0) +IInvalidOperation (OperationKind.Invalid, Type: System.Void, IsInvalid) (Syntax: 'c.M1()') + Children(1): + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C, IsInvalid) (Syntax: 'c') "; var expectedDiagnostics = new DiagnosticDescription[] { - // CS0176: Member 'C.M1()' cannot be accessed with an instance reference; qualify it with a type name instead + // file.cs(9,19): error CS0176: Member 'C.M1()' cannot be accessed with an instance reference; qualify it with a type name instead // /**/c.M1()/**/; Diagnostic(ErrorCode.ERR_ObjectProhibited, "c.M1").WithArguments("C.M1()").WithLocation(9, 19) }; @@ -81,13 +80,12 @@ public static void M2() } "; string expectedOperationTree = @" -IInvocationOperation (void C.M1()) (OperationKind.Invocation, Type: System.Void, IsInvalid) (Syntax: 'C.M1()') - Instance Receiver: - null - Arguments(0) +IInvalidOperation (OperationKind.Invalid, Type: System.Void, IsInvalid) (Syntax: 'C.M1()') + Children(1): + IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: 'C') "; var expectedDiagnostics = new DiagnosticDescription[] { - // CS0120: An object reference is required for the non-static field, method, or property 'C.M1()' + // file.cs(8,19): error CS0120: An object reference is required for the non-static field, method, or property 'C.M1()' // /**/C.M1()/**/; Diagnostic(ErrorCode.ERR_ObjectRequired, "C.M1").WithArguments("C.M1()").WithLocation(8, 19) }; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs new file mode 100644 index 0000000000000..3c5d7ac585b57 --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs @@ -0,0 +1,433 @@ +// 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.Collections.Generic; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; +using System.Linq; +using System.Diagnostics; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + /// + /// Tests for improved overload candidate selection. + /// See also https://github.com/dotnet/csharplang/issues/98. + /// + public class BetterCandidates : CompilingTestBase + { + private CSharpCompilation CreateCompilationWithoutBetterCandidates(string source, CSharpCompilationOptions options = null) + { + return CreateStandardCompilation(source, options: options, parseOptions: TestOptions.WithoutImprovedOverloadCandidates); + } + private CSharpCompilation CreateCompilationWithBetterCandidates(string source, CSharpCompilationOptions options = null) + { + Debug.Assert(TestOptions.Regular.LanguageVersion >= MessageID.IDS_FeatureImprovedOverloadCandidates.RequiredVersion()); + return CreateStandardCompilation(source, options: options, parseOptions: TestOptions.Regular); + } + + //When a method group contains both instance and static members, we discard the instance members if invoked with a static receiver. + [Fact] + public void TestStaticReceiver01() + { + var source = +@"class Program +{ + public static void Main() + { + Program.M(null); + } + public static void M(A a) { System.Console.WriteLine(1); } + public void M(B b) { System.Console.WriteLine(2); } +} +class A {} +class B {} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (5,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(A)' and 'Program.M(B)' + // Program.M(null); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(A)", "Program.M(B)").WithLocation(5, 17) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(); + CompileAndVerify(compilation, expectedOutput: "1"); + } + + //When a method group contains both instance and static members, we discard the static members if invoked with an instance receiver. + [Fact] + public void TestInstanceReceiver01() + { + var source = +@"class Program +{ + public static void Main() + { + Program p = new Program(); + p.M(null); + } + public static void M(A a) { System.Console.WriteLine(1); } + public void M(B b) { System.Console.WriteLine(2); } +} +class A {} +class B {} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (6,11): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(A)' and 'Program.M(B)' + // p.M(null); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(A)", "Program.M(B)").WithLocation(6, 11) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(); + CompileAndVerify(compilation, expectedOutput: "2"); + } + + //When a method group contains no receiver in a static context, we include only static members. + // Type 1: in a static method + [Fact] + public void TestStaticContext01() + { + var source = +@"class Program +{ + public static void Main() + { + M(null); + } + public static void M(A a) { System.Console.WriteLine(1); } + public void M(B b) { System.Console.WriteLine(2); } +} +class A {} +class B {} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (5,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(A)' and 'Program.M(B)' + // M(null); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(A)", "Program.M(B)").WithLocation(5, 9) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + ); + CompileAndVerify(compilation, expectedOutput: "1"); + } + + //When a method group contains no receiver in a static context, we include only static members. + // Type 2: in a field initializer + [Fact] + public void TestStaticContext02() + { + var source = +@"class Program +{ + public static void Main() + { + new Program(); + } + public static int M(A a) { System.Console.WriteLine(1); return 1; } + public int M(B b) { System.Console.WriteLine(2); return 2; } + int X = M(null); +} +class A {} +class B {} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (9,13): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(A)' and 'Program.M(B)' + // int X = M(null); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(A)", "Program.M(B)").WithLocation(9, 13) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + ); + CompileAndVerify(compilation, expectedOutput: "1"); + } + + //When a method group contains no receiver in a static context, we include only static members. + // Type 4: in a constructor-initializer + [Fact] + public void TestStaticContext04() + { + var source = +@"class Program +{ + public static void Main() + { + new Program(); + } + public Program() : this(M(null)) {} + public Program(int x) {} + public static int M(A a) { System.Console.WriteLine(1); return 1; } + public int M(B b) { System.Console.WriteLine(2); return 2; } +} +class A {} +class B {} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (7,29): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(A)' and 'Program.M(B)' + // public Program() : this(M(null)) {} + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(A)", "Program.M(B)").WithLocation(7, 29) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + ); + CompileAndVerify(compilation, expectedOutput: "1"); + } + + //When a method group contains no receiver in a static context, we include only static members. + // Type 5: in an attribute argument + [Fact] + public void TestStaticContext05() + { + var source = +@"public class Program +{ + public static int M(A a) { System.Console.WriteLine(1); return 1; } + public int M(B b) { System.Console.WriteLine(2); return 2; } + + [My(M(null))] + public int x; +} +public class A {} +public class B {} +public class MyAttribute : System.Attribute +{ + public MyAttribute(int value) {} +} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseDll).VerifyDiagnostics( + // (6,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(A)' and 'Program.M(B)' + // [My(M(null))] + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(A)", "Program.M(B)").WithLocation(6, 9) + ); + CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseDll).VerifyDiagnostics( + // (6,9): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [My(M(null))] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "M(null)").WithLocation(6, 9) + ); + } + + //When a method group contains no receiver, we include both static and instance members in an other-than-static context. i.e. discard nothing. + [Fact] + public void TestInstanceContext01() + { + var source = +@"public class Program +{ + public void M() + { + M(null); + } + + public static int M(A a) => 1; + public int M(B b) => 2; +} +public class A {} +public class B {} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseDll).VerifyDiagnostics( + // (5,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(A)' and 'Program.M(B)' + // M(null); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(A)", "Program.M(B)").WithLocation(5, 9) + ); + CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseDll).VerifyDiagnostics( + // (5,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(A)' and 'Program.M(B)' + // M(null); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(A)", "Program.M(B)").WithLocation(5, 9) + ); + } + + //When a method group receiver is ambiguously an instance or type due to a color-color situation, we include both instance and static candidates. + [Fact] + public void TestAmbiguousContext01() + { + var source = +@"public class Color +{ + public void M() + { + Color Color = null; + Color.M(null); + } + + public static int M(A a) => 1; + public int M(B b) => 2; +} +public class A {} +public class B {} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseDll).VerifyDiagnostics( + // (6,15): error CS0121: The call is ambiguous between the following methods or properties: 'Color.M(A)' and 'Color.M(B)' + // Color.M(null); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Color.M(A)", "Color.M(B)").WithLocation(6, 15) + ); + CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseDll).VerifyDiagnostics( + // (6,15): error CS0121: The call is ambiguous between the following methods or properties: 'Color.M(A)' and 'Color.M(B)' + // Color.M(null); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Color.M(A)", "Color.M(B)").WithLocation(6, 15) + ); + } + + //When a method group contains some generic methods whose type parameters do not satisfy their constraints, these members are removed from the candidate set. + [Fact] + public void TestConstraintFailed01() + { + var source = +@"public class Program +{ + static void Main() + { + M(new A(), 0); + } + + static void M(T t1, int i) where T: B { System.Console.WriteLine(1); } + static void M(T t1, short s) { System.Console.WriteLine(2); } +} +public class A {} +public class B {} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (5,9): error CS0311: The type 'A' cannot be used as type parameter 'T' in the generic type or method 'Program.M(T, int)'. There is no implicit reference conversion from 'A' to 'B'. + // M(new A(), 0); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("Program.M(T, int)", "B", "T", "A").WithLocation(5, 9) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + ); + CompileAndVerify(compilation, expectedOutput: "2"); + } + + //When a method group contains some generic methods whose type parameters do not satisfy their constraints, these members are removed from the candidate set. + // Test that this permits overload resolution to use type parameter constraints "as a tie-breaker" to guide overload resolution. + [Fact] + public void TestConstraintFailed02() + { + var source = +@"public class Program +{ + static void Main() + { + M(new A(), null); + M(new B(), null); + } + + static void M(T t1, B b) where T: struct { System.Console.Write(""struct ""); } + static void M(T t1, X s) where T : class { System.Console.Write(""class ""); } +} +public struct A {} +public class B {} +public class X {} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (5,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(T, B)' and 'Program.M(T, X)' + // M(new A(), null); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(T, B)", "Program.M(T, X)").WithLocation(5, 9), + // (6,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(T, B)' and 'Program.M(T, X)' + // M(new B(), null); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(T, B)", "Program.M(T, X)").WithLocation(6, 9) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + ); + CompileAndVerify(compilation, expectedOutput: "struct class "); + } + + //For a method group conversion, candidate methods whose return type doesn't match up with the delegate's return type are removed from the set. + [Fact] + public void TestReturnTypeMismatch01() + { + var source = +@"public class Program +{ + static void Main() + { + M(Program.Q); + } + + static void M(D1 d) { System.Console.WriteLine(1); } + static void M(D2 d) { System.Console.WriteLine(2); } + + static void Q(A a) { } + static void Q(B b) { } +} +delegate int D1(A a); +delegate void D2(B b); + +class A {} +class B {} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (5,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)' + // M(Q); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(5, 9) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + ); + CompileAndVerify(compilation, expectedOutput: "2"); + } + + //For a method group conversion, candidate methods whose return ref kind doesn't match up with the delegate's return ref kind are removed from the set. + [Fact] + public void TestReturnRefMismatch01() + { + var source = +@"public class Program +{ + static int tmp; + static void Main() + { + M(Q); + } + + static void M(D1 d) { System.Console.WriteLine(1); } + static void M(D2 d) { System.Console.WriteLine(2); } + + static ref int Q() { return ref tmp; } +} +delegate int D1(); +delegate ref int D2(); +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (6,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)' + // M(Q); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(6, 9) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + ); + CompileAndVerify(compilation, expectedOutput: "2"); + } + + //For a method group conversion, candidate methods whose return type doesn't match up with the delegate's return type are removed from the set. + [Fact] + public void TestReturnTypeMismatch02() + { + var source = +@"public class Program +{ + static void Main() + { + M(new Z().Q); + } + + static void M(D1 d) { System.Console.WriteLine(1); } + static void M(D2 d) { System.Console.WriteLine(2); } +} +delegate int D1(A a); +delegate void D2(B b); + +public class A {} +public class B {} +public class Z {} +public static class X +{ + public static void Q(this Z z, A a) {} + public static void Q(this Z z, B b) {} +} +namespace System.Runtime.CompilerServices +{ + public class ExtensionAttribute : System.Attribute {} +} +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (5,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)' + // M(new Z().Q); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(5, 9) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + ); + CompileAndVerify(compilation, expectedOutput: "2"); + } + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs index 8e073c7514a83..bcff9115cc8b1 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs @@ -2400,11 +2400,19 @@ void Test() } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (15,15): error CS8189: Ref mismatch between 'C.M()' and delegate 'D' // new D(M)(); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "M").WithArguments("C.M()", "D").WithLocation(15, 15) ); + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. + CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + // (15,9): error CS0123: No overload for 'M' matches delegate 'D' + // new D(M)(); + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D(M)").WithArguments("M", "D").WithLocation(15, 9) + ); } [Fact] @@ -2462,11 +2470,19 @@ void Test() } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (19,11): error CS8189: Ref mismatch between 'C.M()' and delegate 'D' // M(M); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "M").WithArguments("C.M()", "D").WithLocation(19, 11) ); + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. + CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + // (19,11): error CS1503: Argument 1: cannot convert from 'method group' to 'D' + // M(M); + Diagnostic(ErrorCode.ERR_BadArgType, "M").WithArguments("1", "method group", "D").WithLocation(19, 11) + ); } [Fact, WorkItem(1078958, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1078958")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ConditionalOperatorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ConditionalOperatorTests.cs index f9727f0fb2a61..38903be769463 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ConditionalOperatorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ConditionalOperatorTests.cs @@ -96,8 +96,12 @@ public void TestOneUntypedFailure() { TestConditional("true ? GetInt() : null", null, Diagnostic(ErrorCode.ERR_InvalidQM, "true ? GetInt() : null").WithArguments("int", "")); - TestConditional("false ? GetString : (System.Func)null", null, + TestConditional("false ? GetString : (System.Func)null", null, TestOptions.WithoutImprovedOverloadCandidates, Diagnostic(ErrorCode.ERR_BadRetType, "GetString").WithArguments("C.GetString()", "string")); + TestConditional("false ? GetString : (System.Func)null", null, + // (6,34): error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'method group' and 'Func' + // System.Console.WriteLine(false ? GetString : (System.Func)null); + Diagnostic(ErrorCode.ERR_InvalidQM, "false ? GetString : (System.Func)null").WithArguments("method group", "System.Func").WithLocation(6, 34)); TestConditional("true ? (System.Func)null : x => x", null, Diagnostic(ErrorCode.ERR_InvalidQM, "true ? (System.Func)null : x => x").WithArguments("System.Func", "lambda expression")); } @@ -1187,6 +1191,11 @@ static object M(bool b, C c, D d) } private static void TestConditional(string conditionalExpression, string expectedType, params DiagnosticDescription[] expectedDiagnostics) + { + TestConditional(conditionalExpression, expectedType, null, expectedDiagnostics); + } + + private static void TestConditional(string conditionalExpression, string expectedType, CSharpParseOptions parseOptions, params DiagnosticDescription[] expectedDiagnostics) { string sourceTemplate = @" class C @@ -1215,7 +1224,7 @@ public enum color {{ Red, Blue, Green }}; interface I {{ }}"; var source = string.Format(sourceTemplate, conditionalExpression); - var tree = Parse(source); + var tree = Parse(source, options: parseOptions); var comp = CreateStandardCompilation(tree); comp.VerifyDiagnostics(expectedDiagnostics); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs index 6e16d18ac0d72..59e7bcf36ce8c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs @@ -1335,7 +1335,7 @@ static void M(dynamic d, C c) } } "; - string expectedOperationTree = @" + VerifyOperationTreeAndDiagnosticsForTest(source, @" IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'c.Goo(d, d)') Children(3): IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: 'c.Goo') @@ -1343,14 +1343,22 @@ static void M(dynamic d, C c) IParameterReferenceOperation: c (OperationKind.ParameterReference, Type: C, IsInvalid) (Syntax: 'c') IParameterReferenceOperation: d (OperationKind.ParameterReference, Type: dynamic, IsInvalid) (Syntax: 'd') IParameterReferenceOperation: d (OperationKind.ParameterReference, Type: dynamic, IsInvalid) (Syntax: 'd') -"; - var expectedDiagnostics = new DiagnosticDescription[] { - // CS0452: The type 'short' must be a reference type in order to use it as parameter 'T' in the generic type or method 'C.Goo(int, int)' - // /**/c.Goo(d, d)/**/; +", new DiagnosticDescription[] { + // file.cs(15,19): error CS0452: The type 'short' must be a reference type in order to use it as parameter 'T' in the generic type or method 'C.Goo(int, int)' + // /**/c.Goo(d, d)/**/; // Doesn't constraints of generic overloads. Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "c.Goo(d, d)").WithArguments("C.Goo(int, int)", "T", "short").WithLocation(15, 19) - }; - - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates); + VerifyOperationTreeAndDiagnosticsForTest(source, @" +IInvalidOperation (OperationKind.Invalid, Type: System.Void, IsInvalid) (Syntax: 'c.Goo(d, d)') + Children(3): + IParameterReferenceOperation: c (OperationKind.ParameterReference, Type: C) (Syntax: 'c') + IParameterReferenceOperation: d (OperationKind.ParameterReference, Type: dynamic) (Syntax: 'd') + IParameterReferenceOperation: d (OperationKind.ParameterReference, Type: dynamic) (Syntax: 'd') +", new DiagnosticDescription[] { + // file.cs(15,21): error CS0452: The type 'short' must be a reference type in order to use it as parameter 'T' in the generic type or method 'C.Goo(int, int)' + // /**/c.Goo(d, d)/**/; // Doesn't constraints of generic overloads. + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "Goo").WithArguments("C.Goo(int, int)", "T", "short").WithLocation(15, 21) + }); } [CompilerTrait(CompilerFeature.IOperation)] @@ -1638,9 +1646,9 @@ static void Goo(int x, T y) where T : IEnumerable } "; CreateCompilationWithMscorlibAndSystemCore(source).VerifyDiagnostics( - // (8,9): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Program.Goo(int, T)'. - // There is no boxing conversion from 'int' to 'System.Collections.IEnumerable'. - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "Goo((dynamic)1, 1)").WithArguments("Program.Goo(int, T)", "System.Collections.IEnumerable", "T", "int")); + // (8,9): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Program.Goo(int, T)'. There is no boxing conversion from 'int' to 'System.Collections.IEnumerable'. + // Goo((dynamic)1, 1); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "Goo").WithArguments("Program.Goo(int, T)", "System.Collections.IEnumerable", "T", "int").WithLocation(8, 9)); } [Fact] @@ -1713,7 +1721,8 @@ void M() "; CreateCompilationWithMscorlibAndSystemCore(source).VerifyDiagnostics( // (13,9): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'C.F(T, X)' - Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "F(d, null)").WithArguments("C.F(T, X)", "T", "string")); + // F(d, null); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "F").WithArguments("C.F(T, X)", "T", "string").WithLocation(13, 9)); } [Fact] @@ -1732,7 +1741,8 @@ public static void Main() }"; CreateCompilationWithMscorlibAndSystemCore(source).VerifyDiagnostics( // (9,3): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'C.F(string, params T[])'. There is no boxing conversion from 'int' to 'C'. - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "F(d, 1, 2)").WithArguments("C.F(string, params T[])", "C", "T", "int")); + // F(d, 1, 2); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "F").WithArguments("C.F(string, params T[])", "C", "T", "int").WithLocation(9, 3)); } [Fact] @@ -3758,7 +3768,7 @@ public static void Main() compilation1.VerifyDiagnostics( // (11,18): error CS0120: An object reference is required for the non-static field, method, or property '_Worksheet.MRange(object, object)' // var z2 = Worksheet.MRange(x, y); - Diagnostic(ErrorCode.ERR_ObjectRequired, "Worksheet.MRange(x, y)").WithArguments("Microsoft.Office.Interop.Excel._Worksheet.MRange(object, object)").WithLocation(11, 18) + Diagnostic(ErrorCode.ERR_ObjectRequired, "Worksheet.MRange").WithArguments("Microsoft.Office.Interop.Excel._Worksheet.MRange(object, object)").WithLocation(11, 18) ); string consumer2 = @" diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs index 54cd5284b3caa..27bc238f646c2 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs @@ -276,11 +276,14 @@ class Enumerator } "; - CreateStandardCompilation(text).VerifyDiagnostics( + CreateStandardCompilation(text, parseOptions: TestOptions.Regular7).VerifyDiagnostics( // (6,27): warning CS0279: 'Enumerable' does not implement the 'collection' pattern. 'Enumerable.GetEnumerator()' is either static or not public. Diagnostic(ErrorCode.WRN_PatternStaticOrInaccessible, "new Enumerable()").WithArguments("Enumerable", "collection", "Enumerable.GetEnumerator()"), // (6,27): error CS1579: foreach statement cannot operate on variables of type 'Enumerable' because 'Enumerable' does not contain a public definition for 'GetEnumerator' Diagnostic(ErrorCode.ERR_ForEachMissingMember, "new Enumerable()").WithArguments("Enumerable", "GetEnumerator")); + CreateStandardCompilation(text).VerifyDiagnostics( + // (6,27): error CS1579: foreach statement cannot operate on variables of type 'Enumerable' because 'Enumerable' does not contain a public instance definition for 'GetEnumerator' + Diagnostic(ErrorCode.ERR_ForEachMissingMember, "new Enumerable()").WithArguments("Enumerable", "GetEnumerator")); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs index 0c313e4b6b434..ecae1bb7f0e5c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs @@ -375,21 +375,29 @@ void Test() CreateStandardCompilation(text).VerifyDiagnostics( // (13,9): error CS0120: An object reference is required for the non-static field, method, or property 'Interface.Method(int, long)' - Diagnostic(ErrorCode.ERR_ObjectRequired, "Interface.Method").WithArguments("Interface.Method(int, long)"), + // Interface.Method(1, 2); + Diagnostic(ErrorCode.ERR_ObjectRequired, "Interface.Method").WithArguments("Interface.Method(int, long)").WithLocation(13, 9), // (18,9): error CS0120: An object reference is required for the non-static field, method, or property 'Interface.Method()' - Diagnostic(ErrorCode.ERR_ObjectRequired, "Interface.Method").WithArguments("Interface.Method()"), + // Interface.Method(); + Diagnostic(ErrorCode.ERR_ObjectRequired, "Interface.Method").WithArguments("Interface.Method()").WithLocation(18, 9), // (27,9): error CS0120: An object reference is required for the non-static field, method, or property 'Interface.Property' - Diagnostic(ErrorCode.ERR_ObjectRequired, "Interface.Property").WithArguments("Interface.Property"), + // Interface.Property = 2; + Diagnostic(ErrorCode.ERR_ObjectRequired, "Interface.Property").WithArguments("Interface.Property").WithLocation(27, 9), // (28,9): error CS0120: An object reference is required for the non-static field, method, or property 'Interface.Event' - Diagnostic(ErrorCode.ERR_ObjectRequired, "Interface.Event").WithArguments("Interface.Event"), + // Interface.Event += null; + Diagnostic(ErrorCode.ERR_ObjectRequired, "Interface.Event").WithArguments("Interface.Event").WithLocation(28, 9), // (31,11): error CS1061: 'Class' does not contain a definition for 'Interface' and no extension method 'Interface' accepting a first argument of type 'Class' could be found (are you missing a using directive or an assembly reference?) - Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Interface").WithArguments("Class", "Interface"), + // c.Interface.Method(1, 2); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Interface").WithArguments("Class", "Interface").WithLocation(31, 11), // (32,11): error CS1061: 'Class' does not contain a definition for 'Interface' and no extension method 'Interface' accepting a first argument of type 'Class' could be found (are you missing a using directive or an assembly reference?) - Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Interface").WithArguments("Class", "Interface"), + // c.Interface.Method(); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Interface").WithArguments("Class", "Interface").WithLocation(32, 11), // (33,11): error CS1061: 'Class' does not contain a definition for 'Interface' and no extension method 'Interface' accepting a first argument of type 'Class' could be found (are you missing a using directive or an assembly reference?) - Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Interface").WithArguments("Class", "Interface"), + // c.Interface.Property = 2; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Interface").WithArguments("Class", "Interface").WithLocation(33, 11), // (34,11): error CS1061: 'Class' does not contain a definition for 'Interface' and no extension method 'Interface' accepting a first argument of type 'Class' could be found (are you missing a using directive or an assembly reference?) - Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Interface").WithArguments("Class", "Interface")); + // c.Interface.Event += null; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Interface").WithArguments("Class", "Interface").WithLocation(34, 11)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs index 1c4fd9685543b..61232085001c7 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs @@ -1572,10 +1572,8 @@ public static void Main() ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: MemberInitializerTest, IsInvalid) (Syntax: 'Goo() = new ... lizerTest()') Left: - IInvocationOperation ( MemberInitializerTest MemberInitializerTest.Goo()) (OperationKind.Invocation, Type: MemberInitializerTest, IsInvalid) (Syntax: 'Goo()') - Instance Receiver: - IInstanceReferenceOperation (OperationKind.InstanceReference, Type: MemberInitializerTest, IsInvalid, IsImplicit) (Syntax: 'Goo') - Arguments(0) + IInvalidOperation (OperationKind.Invalid, Type: MemberInitializerTest, IsInvalid) (Syntax: 'Goo()') + Children(0) Right: IObjectCreationOperation (Constructor: MemberInitializerTest..ctor()) (OperationKind.ObjectCreation, Type: MemberInitializerTest, IsInvalid) (Syntax: 'new MemberI ... lizerTest()') Arguments(0) @@ -2071,8 +2069,8 @@ public IEnumerator GetEnumerator() Initializer: IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: Test, IsInvalid) (Syntax: '{ 1 }') Initializers(1): - ICollectionElementInitializerOperation (AddMethod: void Test.Add(System.Int32 i)) (IsDynamic: False) (OperationKind.CollectionElementInitializer, Type: System.Void, IsInvalid, IsImplicit) (Syntax: '1') - Arguments(1): + IInvalidOperation (OperationKind.Invalid, Type: System.Void, IsInvalid, IsImplicit) (Syntax: '1') + Children(1): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') "; var expectedDiagnostics = new DiagnosticDescription[] { @@ -2281,10 +2279,8 @@ public static void Main() Children(1): ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: MemberInitializerTest, IsInvalid) (Syntax: 'Goo() = new ... lizerTest()') Left: - IInvocationOperation ( MemberInitializerTest MemberInitializerTest.Goo()) (OperationKind.Invocation, Type: MemberInitializerTest, IsInvalid) (Syntax: 'Goo()') - Instance Receiver: - IInstanceReferenceOperation (OperationKind.InstanceReference, Type: MemberInitializerTest, IsInvalid, IsImplicit) (Syntax: 'Goo') - Arguments(0) + IInvalidOperation (OperationKind.Invalid, Type: MemberInitializerTest, IsInvalid) (Syntax: 'Goo()') + Children(0) Right: IObjectCreationOperation (Constructor: MemberInitializerTest..ctor()) (OperationKind.ObjectCreation, Type: MemberInitializerTest, IsInvalid) (Syntax: 'new MemberI ... lizerTest()') Arguments(0) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs index 8214afdb2f13f..a891119f0630e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs @@ -1368,7 +1368,7 @@ static void Test4(object x) {} static void Test5(Y y, N ny) { } static void Test6(N nz) where Z : struct {} }"; - CreateStandardCompilation(source).VerifyDiagnostics( + CreateStandardCompilation(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (67,36): error CS0453: The type 'Y' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'C.N' // static void Test5(Y y, N ny) { } Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "ny").WithArguments("C.N", "T", "Y").WithLocation(67, 36), @@ -1390,6 +1390,25 @@ static void Test6(N nz) where Z : struct {} // (58,9): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'S' in the generic type or method 'C.L' // Test6>(null); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "Test6>").WithArguments("C.L", "S", "string").WithLocation(58, 9)); + CreateStandardCompilation(source).VerifyDiagnostics( + // (67,36): error CS0453: The type 'Y' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'C.N' + // static void Test5(Y y, N ny) { } + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "ny").WithArguments("C.N", "T", "Y").WithLocation(67, 36), + // (17,9): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'U' in the generic type or method 'C.Test1(U, C.N)' + // Test1(s, null); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "Test1").WithArguments("C.Test1(U, C.N)", "U", "string").WithLocation(17, 9), + // (21,9): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'V' in the generic type or method 'C.Test2(V, C.N)' + // Test2(s, null); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "Test2").WithArguments("C.Test2(V, C.N)", "V", "string").WithLocation(21, 9), + // (47,9): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'C.N' + // Test5(s, null); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "Test5").WithArguments("C.N", "T", "string").WithLocation(47, 9), + // (58,17): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'S' in the generic type or method 'C.L' + // Test6>(null); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "string").WithArguments("C.L", "S", "string").WithLocation(58, 17), + // (58,9): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'S' in the generic type or method 'C.L' + // Test6>(null); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "Test6>").WithArguments("C.L", "S", "string").WithLocation(58, 9)); } [Fact] @@ -7796,13 +7815,13 @@ static void Main(string[] args) } "; - var compilation = CreateStandardCompilation(source1, options: TestOptions.DebugExe); - - compilation.VerifyDiagnostics( + CreateStandardCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (25,38): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Bar.Create(Func)' and 'Program.Bar.Create(Func, params Func[])' // var x = Bar.Create(Goo.IsThing); Diagnostic(ErrorCode.ERR_AmbigCall, "Create").WithArguments("ConsoleApplication2.Program.Bar.Create(System.Func)", "ConsoleApplication2.Program.Bar.Create(System.Func, params System.Func[])").WithLocation(25, 38) ); + CreateStandardCompilation(source1, options: TestOptions.DebugExe).VerifyDiagnostics( + ); } [Fact, WorkItem(1080896, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1080896"), WorkItem(367, "Devdiv")] @@ -7876,13 +7895,13 @@ static void Main(string[] args) } "; - var compilation = CreateStandardCompilation(source1, options: TestOptions.DebugExe); - - compilation.VerifyDiagnostics( + CreateStandardCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (25,38): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Bar.Create(Func, params int[])' and 'Program.Bar.Create(Func)' // var x = Bar.Create(Goo.IsThing); Diagnostic(ErrorCode.ERR_AmbigCall, "Create").WithArguments("ConsoleApplication2.Program.Bar.Create(System.Func, params int[])", "ConsoleApplication2.Program.Bar.Create(System.Func)").WithLocation(25, 38) ); + CreateStandardCompilation(source1, options: TestOptions.DebugExe).VerifyDiagnostics( + ); } [Fact, WorkItem(1080896, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1080896"), WorkItem(367, "Devdiv")] @@ -7918,13 +7937,13 @@ static void Main(string[] args) } "; - var compilation = CreateStandardCompilation(source1, options: TestOptions.DebugExe); - - compilation.VerifyDiagnostics( + CreateStandardCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (25,38): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Bar.Create(Func)' and 'Program.Bar.Create(Func, params int[])' // var x = Bar.Create(Goo.IsThing); Diagnostic(ErrorCode.ERR_AmbigCall, "Create").WithArguments("ConsoleApplication2.Program.Bar.Create(System.Func)", "ConsoleApplication2.Program.Bar.Create(System.Func, params int[])").WithLocation(25, 38) ); + CreateStandardCompilation(source1, options: TestOptions.DebugExe).VerifyDiagnostics( + ); } [Fact, WorkItem(1080896, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1080896"), WorkItem(367, "Devdiv")] @@ -7960,13 +7979,13 @@ static void Main(string[] args) } "; - var compilation = CreateStandardCompilation(source1, options: TestOptions.DebugExe); - - compilation.VerifyDiagnostics( + CreateStandardCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (25,38): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Bar.Create(Func, params Func[])' and 'Program.Bar.Create(Func)' // var x = Bar.Create(Goo.IsThing); Diagnostic(ErrorCode.ERR_AmbigCall, "Create").WithArguments("ConsoleApplication2.Program.Bar.Create(System.Func, params System.Func[])", "ConsoleApplication2.Program.Bar.Create(System.Func)").WithLocation(25, 38) ); + CreateStandardCompilation(source1, options: TestOptions.DebugExe).VerifyDiagnostics( + ); } [Fact, WorkItem(1080896, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1080896"), WorkItem(367, "Devdiv")] @@ -8000,13 +8019,13 @@ static void Main(string[] args) } "; - var compilation = CreateStandardCompilation(source1, options: TestOptions.DebugExe); - - compilation.VerifyDiagnostics( + CreateStandardCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (23,38): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Bar.Create(Func, params int[])' and 'Program.Bar.Create(Func, params int[])' // var x = Bar.Create(Goo.IsThing); Diagnostic(ErrorCode.ERR_AmbigCall, "Create").WithArguments("ConsoleApplication2.Program.Bar.Create(System.Func, params int[])", "ConsoleApplication2.Program.Bar.Create(System.Func, params int[])").WithLocation(23, 38) ); + CreateStandardCompilation(source1, options: TestOptions.DebugExe).VerifyDiagnostics( + ); } [Fact, WorkItem(1081302, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1081302"), WorkItem(371, "Devdiv")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/QueryTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/QueryTests.cs index 1713515988ee1..eaf9ebe54761d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/QueryTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/QueryTests.cs @@ -2736,7 +2736,16 @@ static void Main() } } "; - string expectedOperationTree = @" + var expectedDiagnostics = new DiagnosticDescription[] { + // CS0718: 'GC': static types cannot be used as type arguments + // var q2 = string.Empty.Cast().Select(x => x); + Diagnostic(ErrorCode.ERR_GenericArgIsStaticClass, "string.Empty.Cast").WithArguments("System.GC").WithLocation(9, 18), + // CS0718: 'GC': static types cannot be used as type arguments + // var q1 = /**/from GC x in string.Empty select x/**/; + Diagnostic(ErrorCode.ERR_GenericArgIsStaticClass, "from GC x in string.Empty").WithArguments("System.GC").WithLocation(10, 28) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, @" ITranslatedQueryOperation (OperationKind.TranslatedQuery, Type: ?, IsInvalid) (Syntax: 'from GC x i ... ty select x') Expression: IInvalidOperation (OperationKind.Invalid, Type: ?, IsImplicit) (Syntax: 'select x') @@ -2759,17 +2768,37 @@ static void Main() IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'x') ReturnedValue: IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.GC) (Syntax: 'x') -"; - var expectedDiagnostics = new DiagnosticDescription[] { +", new DiagnosticDescription[] { // CS0718: 'GC': static types cannot be used as type arguments // var q2 = string.Empty.Cast().Select(x => x); Diagnostic(ErrorCode.ERR_GenericArgIsStaticClass, "string.Empty.Cast").WithArguments("System.GC").WithLocation(9, 18), // CS0718: 'GC': static types cannot be used as type arguments // var q1 = /**/from GC x in string.Empty select x/**/; Diagnostic(ErrorCode.ERR_GenericArgIsStaticClass, "from GC x in string.Empty").WithArguments("System.GC").WithLocation(10, 28) - }; - - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates); + VerifyOperationTreeAndDiagnosticsForTest(source, @" +ITranslatedQueryOperation (OperationKind.TranslatedQuery, Type: ?, IsInvalid) (Syntax: 'from GC x i ... ty select x') + Expression: + IInvalidOperation (OperationKind.Invalid, Type: ?, IsImplicit) (Syntax: 'select x') + Children(2): + IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid, IsImplicit) (Syntax: 'from GC x i ... tring.Empty') + Children(1): + IFieldReferenceOperation: System.String System.String.Empty (Static) (OperationKind.FieldReference, Type: System.String, IsInvalid) (Syntax: 'string.Empty') + Instance Receiver: + null + IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null, IsImplicit) (Syntax: 'x') + IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'x') + IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'x') + ReturnedValue: + IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: ?) (Syntax: 'x') +", new DiagnosticDescription[] { + // file.cs(9,18): error CS1929: 'string' does not contain a definition for 'Cast' and the best extension method overload 'Queryable.Cast(IQueryable)' requires a receiver of type 'IQueryable' + // var q2 = string.Empty.Cast().Select(x => x); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "string.Empty").WithArguments("string", "Cast", "System.Linq.Queryable.Cast(System.Linq.IQueryable)", "System.Linq.IQueryable").WithLocation(9, 18), + // file.cs(10,41): error CS1929: 'string' does not contain a definition for 'Cast' and the best extension method overload 'Queryable.Cast(IQueryable)' requires a receiver of type 'IQueryable' + // var q1 = /**/from GC x in string.Empty select x/**/; + Diagnostic(ErrorCode.ERR_BadInstanceArgType, "string.Empty").WithArguments("string", "Cast", "System.Linq.Queryable.Cast(System.Linq.IQueryable)", "System.Linq.IQueryable").WithLocation(10, 41) + }); } [CompilerTrait(CompilerFeature.IOperation)] @@ -3723,9 +3752,9 @@ public static Test Where(this Test x, System.Func filter) // (7,34): error CS1936: Could not find an implementation of the query pattern for source type 'Test'. 'Where' not found. // var x02 = from a in Test where a > 0 select a + 1; Diagnostic(ErrorCode.ERR_QueryNoProvider, "where a > 0").WithArguments("Test", "Where").WithLocation(7, 34), - // (7,46): error CS0176: Member 'Test.Select(Func)' cannot be accessed with an instance reference; qualify it with a type name instead + // (7,46): error CS1936: Could not find an implementation of the query pattern for source type 'Test'. 'Select' not found. // var x02 = from a in Test where a > 0 select a + 1; - Diagnostic(ErrorCode.ERR_ObjectProhibited, "select a + 1").WithArguments("Test.Select(System.Func)").WithLocation(7, 46) + Diagnostic(ErrorCode.ERR_QueryNoProvider, "select a + 1").WithArguments("Test", "Select").WithLocation(7, 46) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs index 010cc9596022a..e0e6c64fe2884 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs @@ -1372,9 +1372,9 @@ public void TestScriptWithConstVar() // (1,27): error CS0822: Implicitly-typed variables cannot be constant // string F() => null; const var x = F(); Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableCannotBeConst, "var").WithLocation(1, 27), - // (1,35): error CS0120: An object reference is required for the non-static field, method, or property 'F()' + // (1,35): error CS0236: A field initializer cannot reference the non-static field, method, or property 'F()' // string F() => null; const var x = F(); - Diagnostic(ErrorCode.ERR_ObjectRequired, "F").WithArguments("F()").WithLocation(1, 35) + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "F").WithArguments("F()").WithLocation(1, 35) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticAnalyzerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticAnalyzerTests.cs index 1dd99cbfb0708..b8d26fa96928a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticAnalyzerTests.cs @@ -448,12 +448,12 @@ static void M() } }"; CreateStandardCompilation(source).VerifyDiagnostics( - // (84,29): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? - // public static void PExt(this P p) {} - Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(84, 29), // (69,28): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // public static P Select(this P p, Func projection) Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(69, 28), + // (84,29): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? + // public static void PExt(this P p) {} + Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(84, 29), // (80,33): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // public static object Select(this Q q, object projection) Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(80, 33), @@ -505,7 +505,7 @@ static void M() // (190,24): error CS1620: Argument 1 must be passed with the 'ref' keyword // p.RefParameter(456); Diagnostic(ErrorCode.ERR_BadArgRef, "456").WithArguments("1", "ref").WithLocation(190, 24), - // (195,28): error CS1615: Argument 1 should not be passed with the 'out' keyword + // (195,28): error CS1615: Argument 1 may not be passed with the 'out' keyword // p.OneParameter(out local); Diagnostic(ErrorCode.ERR_BadArgExtraRef, "local").WithArguments("1", "out").WithLocation(195, 28), // (199,28): error CS1620: Argument 1 must be passed with the 'ref' keyword @@ -519,7 +519,8 @@ static void M() Diagnostic(ErrorCode.ERR_ObjectRequired, "P.NoParameter").WithArguments("P.NoParameter()").WithLocation(219, 9), // (223,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod()' // InstanceMethod(); // Verify that use of 'implicit this' is not legal in a static method. - Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod").WithArguments("C.InstanceMethod()").WithLocation(223, 9)); + Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod").WithArguments("C.InstanceMethod()").WithLocation(223, 9) + ); } [WorkItem(538651, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538651")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs index 28e1740755c8e..28c654f357d59 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs @@ -1340,17 +1340,19 @@ public void CS0027ERR_ThisInBadContext_Interactive() string text = @" int a; int b = a; -int c = this.a; -this.c = this.a; -int prop { get { return 1; } set { this.a = 1;} } +int c = this.a; // 1 +this.c = // 2 + this.a; // 3 +int prop { get { return 1; } set { this.a = 1;} } // 4 void goo() { - this.goo(); - this.a = this.b; - object c = this; + this.goo(); // 5 + this.a = // 6 + this.b; // 7 + object c = this; // 8 } -this.prop = 1; +this.prop = 1; // 9 class C { @@ -1360,30 +1362,40 @@ class C void goo() { - this.goo(); + this.goo(); // OK } }"; var comp = CreateCompilationWithMscorlib45( new[] { SyntaxFactory.ParseSyntaxTree(text, options: TestOptions.Script) }); comp.VerifyDiagnostics( // (4,9): error CS0027: Keyword 'this' is not available in the current context - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), + // int c = this.a; // 1 + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(4, 9), // (5,1): error CS0027: Keyword 'this' is not available in the current context - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), - // (5,10): error CS0027: Keyword 'this' is not available in the current context - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), - // (14,1): error CS0027: Keyword 'this' is not available in the current context - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), - // (6,36): error CS0027: Keyword 'this' is not available in the current context - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), - // (9,5): error CS0027: Keyword 'this' is not available in the current context - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), + // this.c = // 2 + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(5, 1), + // (6,5): error CS0027: Keyword 'this' is not available in the current context + // this.a; // 3 + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(6, 5), + // (16,1): error CS0027: Keyword 'this' is not available in the current context + // this.prop = 1; // 9 + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(16, 1), + // (7,36): error CS0027: Keyword 'this' is not available in the current context + // int prop { get { return 1; } set { this.a = 1;} } // 4 + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(7, 36), // (10,5): error CS0027: Keyword 'this' is not available in the current context - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), - // (10,14): error CS0027: Keyword 'this' is not available in the current context - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), - // (11,16): error CS0027: Keyword 'this' is not available in the current context - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this")); + // this.goo(); // 5 + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(10, 5), + // (11,5): error CS0027: Keyword 'this' is not available in the current context + // this.a = // 6 + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(11, 5), + // (12,9): error CS0027: Keyword 'this' is not available in the current context + // this.b; // 7 + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(12, 9), + // (13,16): error CS0027: Keyword 'this' is not available in the current context + // object c = this; // 8 + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(13, 16) + ); } [Fact] @@ -2661,17 +2673,23 @@ static void M() ") .VerifyDiagnostics( // (8,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.field' - Diagnostic(ErrorCode.ERR_ObjectRequired, "field").WithArguments("C.field"), + // field = Property; + Diagnostic(ErrorCode.ERR_ObjectRequired, "field").WithArguments("C.field").WithLocation(8, 9), // (8,17): error CS0120: An object reference is required for the non-static field, method, or property 'C.Property' - Diagnostic(ErrorCode.ERR_ObjectRequired, "Property").WithArguments("C.Property"), + // field = Property; + Diagnostic(ErrorCode.ERR_ObjectRequired, "Property").WithArguments("C.Property").WithLocation(8, 17), // (9,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.field' - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.field").WithArguments("C.field"), + // C.field = C.Property; + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.field").WithArguments("C.field").WithLocation(9, 9), // (9,19): error CS0120: An object reference is required for the non-static field, method, or property 'C.Property' - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.Property").WithArguments("C.Property"), + // C.field = C.Property; + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.Property").WithArguments("C.Property").WithLocation(9, 19), // (10,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.Method()' - Diagnostic(ErrorCode.ERR_ObjectRequired, "Method").WithArguments("C.Method()"), + // Method(); + Diagnostic(ErrorCode.ERR_ObjectRequired, "Method").WithArguments("C.Method()").WithLocation(10, 9), // (11,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.Method()' - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.Method").WithArguments("C.Method()")); + // C.Method(); + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.Method").WithArguments("C.Method()").WithLocation(11, 9)); } [Fact] @@ -2698,7 +2716,7 @@ static void Main(string[] args) [Fact] public void CS0120ERR_ObjectRequired03() { - CreateStandardCompilation( + var source = @"delegate int boo(); interface I { @@ -2717,8 +2735,8 @@ static void Main(string[] args) goo += new boo(I.bar); goo(); } -}") - .VerifyDiagnostics( +}"; + CreateStandardCompilation(source, parseOptions: TestOptions.Regular7).VerifyDiagnostics( // (16,24): error CS0120: An object reference is required for the non-static field, method, or property 'I.bar()' // goo += new boo(I.bar); Diagnostic(ErrorCode.ERR_ObjectRequired, "I.bar").WithArguments("I.bar()"), @@ -2726,6 +2744,17 @@ static void Main(string[] args) // abc p = new abc(); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "p").WithArguments("p") ); + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. + CreateStandardCompilation(source, parseOptions: TestOptions.Regular).VerifyDiagnostics( + // (16,16): error CS0123: No overload for 'bar' matches delegate 'boo' + // goo += new boo(I.bar); + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new boo(I.bar)").WithArguments("bar", "boo").WithLocation(16, 16), + // (14,13): warning CS0219: The variable 'p' is assigned but its value is never used + // abc p = new abc(); + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "p").WithArguments("p").WithLocation(14, 13) + ); } [WorkItem(543950, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543950")] @@ -2794,28 +2823,28 @@ class C : B .VerifyDiagnostics( // (19,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.instanceField' // instanceField, //CS0120 - Diagnostic(ErrorCode.ERR_ObjectRequired, "instanceField").WithArguments("C.instanceField"), + Diagnostic(ErrorCode.ERR_ObjectRequired, "instanceField").WithArguments("C.instanceField").WithLocation(19, 9), // (21,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceProperty' // InstanceProperty, //CS0120 - Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceProperty").WithArguments("C.InstanceProperty"), + Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceProperty").WithArguments("C.InstanceProperty").WithLocation(21, 9), // (23,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod()' // InstanceMethod(), //CS0120 - Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod()").WithArguments("C.InstanceMethod()"), + Diagnostic(ErrorCode.ERR_ObjectRequired, "InstanceMethod").WithArguments("C.InstanceMethod()").WithLocation(23, 9), // (25,9): error CS0027: Keyword 'this' is not available in the current context // this.instanceField, //CS0027 - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(25, 9), // (27,9): error CS0027: Keyword 'this' is not available in the current context // this.InstanceProperty, //CS0027 - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(27, 9), // (29,9): error CS0027: Keyword 'this' is not available in the current context // this.InstanceMethod(), //CS0027 - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(29, 9), // (8,9): warning CS0649: Field 'C.instanceField' is never assigned to, and will always have its default value 0 // int instanceField; - Diagnostic(ErrorCode.WRN_UnassignedInternalField, "instanceField").WithArguments("C.instanceField", "0"), + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "instanceField").WithArguments("C.instanceField", "0").WithLocation(8, 9), // (9,16): warning CS0649: Field 'C.staticField' is never assigned to, and will always have its default value 0 // static int staticField; - Diagnostic(ErrorCode.WRN_UnassignedInternalField, "staticField").WithArguments("C.staticField", "0")); + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "staticField").WithArguments("C.staticField", "0").WithLocation(9, 16)); } [Fact] @@ -2838,17 +2867,23 @@ static C() ") .VerifyDiagnostics( // (8,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.field' - Diagnostic(ErrorCode.ERR_ObjectRequired, "field").WithArguments("C.field"), + // field = Property; + Diagnostic(ErrorCode.ERR_ObjectRequired, "field").WithArguments("C.field").WithLocation(8, 9), // (8,17): error CS0120: An object reference is required for the non-static field, method, or property 'C.Property' - Diagnostic(ErrorCode.ERR_ObjectRequired, "Property").WithArguments("C.Property"), + // field = Property; + Diagnostic(ErrorCode.ERR_ObjectRequired, "Property").WithArguments("C.Property").WithLocation(8, 17), // (9,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.field' - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.field").WithArguments("C.field"), + // C.field = C.Property; + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.field").WithArguments("C.field").WithLocation(9, 9), // (9,19): error CS0120: An object reference is required for the non-static field, method, or property 'C.Property' - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.Property").WithArguments("C.Property"), + // C.field = C.Property; + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.Property").WithArguments("C.Property").WithLocation(9, 19), // (10,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.Method()' - Diagnostic(ErrorCode.ERR_ObjectRequired, "Method").WithArguments("C.Method()"), + // Method(); + Diagnostic(ErrorCode.ERR_ObjectRequired, "Method").WithArguments("C.Method()").WithLocation(10, 9), // (11,9): error CS0120: An object reference is required for the non-static field, method, or property 'C.Method()' - Diagnostic(ErrorCode.ERR_ObjectRequired, "C.Method").WithArguments("C.Method()")); + // C.Method(); + Diagnostic(ErrorCode.ERR_ObjectRequired, "C.Method").WithArguments("C.Method()").WithLocation(11, 9)); } [Fact] @@ -6439,7 +6474,7 @@ void M() CreateStandardCompilation(source).VerifyDiagnostics( // (9,13): error CS0176: Member 'A.B.Method()' cannot be accessed with an instance reference; qualify it with a type name instead // this.Method(); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.Method").WithArguments("A.B.Method()") + Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.Method").WithArguments("A.B.Method()").WithLocation(9, 13) ); } @@ -6488,19 +6523,20 @@ class B where T : A { static void M(T t) { - t.ReferenceEquals(t.F, null); + object q = t.F; + t.ReferenceEquals(q, null); } }"; CreateStandardCompilation(source).VerifyDiagnostics( - // (9,27): error CS0176: Member 'A.F' cannot be accessed with an instance reference; qualify it with a type name instead - // t.ReferenceEquals(t.F, null); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "t.F").WithArguments("A.F"), - // (9,9): error CS0176: Member 'object.ReferenceEquals(object, object)' cannot be accessed with an instance reference; qualify it with a type name instead - // t.ReferenceEquals(t.F, null); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "t.ReferenceEquals").WithArguments("object.ReferenceEquals(object, object)"), + // (9,20): error CS0176: Member 'A.F' cannot be accessed with an instance reference; qualify it with a type name instead + // object q = t.F; + Diagnostic(ErrorCode.ERR_ObjectProhibited, "t.F").WithArguments("A.F").WithLocation(9, 20), + // (10,9): error CS0176: Member 'object.ReferenceEquals(object, object)' cannot be accessed with an instance reference; qualify it with a type name instead + // t.ReferenceEquals(q, null); + Diagnostic(ErrorCode.ERR_ObjectProhibited, "t.ReferenceEquals").WithArguments("object.ReferenceEquals(object, object)").WithLocation(10, 9), // (3,28): warning CS0649: Field 'A.F' is never assigned to, and will always have its default value null // internal static object F; - Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F").WithArguments("A.F", "null")); + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F").WithArguments("A.F", "null").WithLocation(3, 28)); } [WorkItem(543361, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543361")] @@ -6520,9 +6556,9 @@ public void TestIdenticalEventName() } "; CreateStandardCompilation(source).VerifyDiagnostics( - // (9,9): error CS0176: Member Member 'System.Delegate.CreateDelegate(System.Type, System.Type, string)' cannot be accessed with an instance reference; qualify it with a type name instead - // this.Method(); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "D.CreateDelegate").WithArguments("System.Delegate.CreateDelegate(System.Type, System.Type, string)") + // (9,9): error CS0176: Member 'Delegate.CreateDelegate(Type, object, string)' cannot be accessed with an instance reference; qualify it with a type name instead + // D.CreateDelegate(null, null, null); // CS0176 + Diagnostic(ErrorCode.ERR_ObjectProhibited, "D.CreateDelegate").WithArguments("System.Delegate.CreateDelegate(System.Type, object, string)").WithLocation(9, 9) ); } @@ -8327,46 +8363,47 @@ public static void Main() comp.VerifyDiagnostics( // (12,13): error CS0236: A field initializer cannot reference the non-static field, method, or property 'MyClass.b' // int c = b; //CS0236 - Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "b").WithArguments("MyClass.b"), + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "b").WithArguments("MyClass.b").WithLocation(12, 13), // (13,13): error CS0027: Keyword 'this' is not available in the current context // int d = this.b; //CS0027 - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(13, 13), // (14,13): error CS0236: A field initializer cannot reference the non-static field, method, or property 'MyClass.InstanceMethod()' // int e = InstanceMethod(); //CS0236 - Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "InstanceMethod()").WithArguments("MyClass.InstanceMethod()"), + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "InstanceMethod").WithArguments("MyClass.InstanceMethod()").WithLocation(14, 13), // (15,13): error CS0027: Keyword 'this' is not available in the current context // int f = this.InstanceMethod(); //CS0027 - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(15, 13), // (18,13): error CS0236: A field initializer cannot reference the non-static field, method, or property 'MyClass.GenericInstanceMethod(int)' // int i = GenericInstanceMethod(1); //CS0236 - Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "GenericInstanceMethod(1)").WithArguments("MyClass.GenericInstanceMethod(int)"), + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "GenericInstanceMethod").WithArguments("MyClass.GenericInstanceMethod(int)").WithLocation(18, 13), // (19,13): error CS0027: Keyword 'this' is not available in the current context // int j = this.GenericInstanceMethod(1); //CS0027 - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(19, 13), // (22,13): error CS0236: A field initializer cannot reference the non-static field, method, or property 'MyClass.InstanceProperty' // int m = InstanceProperty; //CS0236 - Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "InstanceProperty").WithArguments("MyClass.InstanceProperty"), + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "InstanceProperty").WithArguments("MyClass.InstanceProperty").WithLocation(22, 13), // (23,13): error CS0027: Keyword 'this' is not available in the current context // int n = this.InstanceProperty; //CS0027 - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(23, 13), // (26,13): error CS0236: A field initializer cannot reference the non-static field, method, or property 'MyClass.instanceArray' // int q = instanceArray[0]; //CS0236 - Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "instanceArray").WithArguments("MyClass.instanceArray"), + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "instanceArray").WithArguments("MyClass.instanceArray").WithLocation(26, 13), // (27,13): error CS0027: Keyword 'this' is not available in the current context // int r = this.instanceArray[0]; //CS0027 - Diagnostic(ErrorCode.ERR_ThisInBadContext, "this"), + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(27, 13), // (4,11): warning CS0649: Field 'MyClass.instanceArray' is never assigned to, and will always have its default value null // int[] instanceArray; - Diagnostic(ErrorCode.WRN_UnassignedInternalField, "instanceArray").WithArguments("MyClass.instanceArray", "null"), + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "instanceArray").WithArguments("MyClass.instanceArray", "null").WithLocation(4, 11), // (5,18): warning CS0649: Field 'MyClass.staticArray' is never assigned to, and will always have its default value null // static int[] staticArray; - Diagnostic(ErrorCode.WRN_UnassignedInternalField, "staticArray").WithArguments("MyClass.staticArray", "null"), - // (32,9): warning CS0414: The field 'MyClass.w' is assigned but its value is never used - // int w = constField; - Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "w").WithArguments("MyClass.w"), + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "staticArray").WithArguments("MyClass.staticArray", "null").WithLocation(5, 18), // (33,9): warning CS0414: The field 'MyClass.x' is assigned but its value is never used // int x = MyClass.constField; - Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "x").WithArguments("MyClass.x")); + Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "x").WithArguments("MyClass.x").WithLocation(33, 9), + // (32,9): warning CS0414: The field 'MyClass.w' is assigned but its value is never used + // int w = constField; + Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "w").WithArguments("MyClass.w").WithLocation(32, 9) + ); } [Fact] @@ -9544,24 +9581,34 @@ static void M() CreateStandardCompilation(text, references: new[] { SystemCoreRef }).VerifyDiagnostics( // (9,36): error CS0310: 'U' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'D' + // internal static void E(D d) { } // Error: missing constraint on E to satisfy constraint on D Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "d").WithArguments("D", "T", "U").WithLocation(9, 36), - // (29,9): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'C.M()' - Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "C.M").WithArguments("C.M()", "U", "B").WithLocation(29, 9), + // (29,14): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'C.M()' + // C.M(); + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M").WithArguments("C.M()", "U", "B").WithLocation(29, 14), // (30,11): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // C.M(); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "B").WithArguments("C", "T", "B").WithLocation(30, 11), // (31,11): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // C.M(); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "B").WithArguments("C", "T", "B").WithLocation(31, 11), - // (31,9): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'C.M()' - Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "C.M").WithArguments("C.M()", "U", "B").WithLocation(31, 9), + // (31,14): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'C.M()' + // C.M(); + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M").WithArguments("C.M()", "U", "B").WithLocation(31, 14), // (32,11): error CS0310: 'G' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // C.M(); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "G").WithArguments("C", "T", "G").WithLocation(32, 11), - // (33,9): error CS0310: 'G' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'C.M()' - Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "C.M").WithArguments("C.M()", "U", "G").WithLocation(33, 9), + // (33,14): error CS0310: 'G' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'C.M()' + // C.M(); + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M").WithArguments("C.M()", "U", "G").WithLocation(33, 14), // (34,11): error CS0310: 'I' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // C.M(); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "I").WithArguments("C", "T", "I").WithLocation(34, 11), - // (36,9): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'E.F(D)' + // (36,11): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'E.F(D)' + // E.F(S.F); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "F").WithArguments("E.F(D)", "T", "B").WithLocation(36, 11), // (38,19): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // E.F(S.F>); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "B").WithArguments("C", "T", "B").WithLocation(38, 19), // This invocation of E.F(S.F>) is an extremely interesting one. @@ -9595,13 +9642,15 @@ static void M() // We might want to put some gear in place to suppress this cascading error. It is not // entirely clear what that machinery might look like. - // (38,9): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // (38,11): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' // E.F(S.F>); - Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "F").WithArguments("C", "T", "B"), + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "F").WithArguments("C", "T", "B").WithLocation(38, 11), - // (41,9): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'E.M(object)' - Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "o.M").WithArguments("E.M(object)", "T", "B").WithLocation(41, 9), + // (41,11): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'E.M(object)' + // o.M(); + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M").WithArguments("E.M(object)", "T", "B").WithLocation(41, 11), // (42,22): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'F' + // o = new F(); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "B").WithArguments("F", "U", "B").WithLocation(42, 22)); } @@ -9642,13 +9691,18 @@ static class S }"; CreateStandardCompilation(text, references: new[] { SystemCoreRef }).VerifyDiagnostics( // (15,9): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'V' in the generic type or method 'C.M(V)' + // M(b); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M").WithArguments("C.M(V)", "V", "B").WithLocation(15, 9), - // (16,9): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'S.E(T)' - Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "b.E").WithArguments("S.E(T)", "T", "B").WithLocation(16, 9), + // (16,11): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'S.E(T)' + // b.E(); + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "E").WithArguments("S.E(T)", "T", "B").WithLocation(16, 11), // (18,9): error CS0310: 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'V' in the generic type or method 'C.M(V)' + // M(t); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M").WithArguments("C.M(V)", "V", "T").WithLocation(18, 9), - // (19,9): error CS0310: 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'S.E(T)' - Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "t.E").WithArguments("S.E(T)", "T", "T").WithLocation(19, 9)); + // (19,11): error CS0310: 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'S.E(T)' + // t.E(); + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "E").WithArguments("S.E(T)", "T", "T").WithLocation(19, 11) +); } /// @@ -9696,27 +9750,38 @@ static void M() } }"; CreateStandardCompilation(text, references: new[] { SystemCoreRef }).VerifyDiagnostics( - // (4,7): error CS0310: 'N.B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'N.C' + // (4,7): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // using CB = N.C; Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "CB").WithArguments("N.C", "T", "N.B").WithLocation(4, 7), - // (8,11): error CS0310: 'N.B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'N.C' + // (8,11): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // using CBD = C.D; Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "CBD").WithArguments("N.C", "T", "N.B").WithLocation(8, 11), - // (24,13): error CS0310: 'N.B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'N.C.M()' - Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "C.M").WithArguments("N.C.M()", "U", "N.B").WithLocation(24, 13), - // (25,15): error CS0310: 'N.B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'N.C' + // (24,20): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'C.M()' + // C.M(); + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M").WithArguments("N.C.M()", "U", "N.B").WithLocation(24, 20), + // (25,15): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // C.M(); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "NB").WithArguments("N.C", "T", "N.B").WithLocation(25, 15), - // (26,15): error CS0310: 'N.C.D' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'N.C' + // (26,15): error CS0310: 'C.D' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // C.D>.M(); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "C.D").WithArguments("N.C", "T", "N.C.D").WithLocation(26, 15), - // (27,13): error CS0310: 'N.B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'N.C.D.M()' - Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "C.D.M").WithArguments("N.C.D.M()", "U", "N.B").WithLocation(27, 13), - // (28,15): error CS0310: 'N.B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'N.C' + // (27,22): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'C.D.M()' + // C.D.M(); + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M").WithArguments("N.C.D.M()", "U", "N.B").WithLocation(27, 22), + // (28,15): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // C.D.M(); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "N.B").WithArguments("N.C", "T", "N.B").WithLocation(28, 15), - // (29,13): error CS0310: 'N.B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'N.C.M()' - Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "CA.M").WithArguments("N.C.M()", "U", "N.B").WithLocation(29, 13), - // (31,13): error CS0310: 'N.B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'N.C.D.M()' - Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "CAD.M").WithArguments("N.C.D.M()", "U", "N.B").WithLocation(31, 13), - // (33,15): error CS0310: 'N.C.D' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'N.C' + // (29,16): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'C.M()' + // CA.M(); + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M").WithArguments("N.C.M()", "U", "N.B").WithLocation(29, 16), + // (31,17): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'U' in the generic type or method 'C.D.M()' + // CAD.M(); + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M").WithArguments("N.C.D.M()", "U", "N.B").WithLocation(31, 17), + // (33,15): error CS0310: 'C.D' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // C.M(); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "CAD").WithArguments("N.C", "T", "N.C.D").WithLocation(33, 15), - // (34,15): error CS0310: 'N.C.D' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'N.C' + // (34,15): error CS0310: 'C.D' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C' + // C.M(); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "CBD").WithArguments("N.C", "T", "N.C.D").WithLocation(34, 15)); } @@ -9848,10 +9913,12 @@ static void M() } }"; CreateStandardCompilation(source).VerifyDiagnostics( - // (16,24): error CS0311: The type 'object' cannot be used as type parameter 'U' in the generic type or method 'N.C'. There is no implicit reference conversion from 'object' to 'int'. + // (16,24): error CS0311: The type 'object' cannot be used as type parameter 'U' in the generic type or method 'C'. There is no implicit reference conversion from 'object' to 'int'. + // o = C.F(); Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "object").WithArguments("N.C", "int", "U", "object").WithLocation(16, 24), - // (17,17): error CS0311: The type 'string' cannot be used as type parameter 'V' in the generic type or method 'N.C.G()'. There is no implicit reference conversion from 'string' to 'int'. - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "N.C.G").WithArguments("N.C.G()", "int", "V", "string").WithLocation(17, 17)); + // (17,31): error CS0311: The type 'string' cannot be used as type parameter 'V' in the generic type or method 'C.G()'. There is no implicit reference conversion from 'string' to 'int'. + // o = N.C.G(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "G").WithArguments("N.C.G()", "int", "V", "string").WithLocation(17, 31)); } [Fact] @@ -9870,9 +9937,11 @@ static void M() }"; CreateStandardCompilation(source).VerifyDiagnostics( // (7,26): error CS0312: The type 'int?' cannot be used as type parameter 'T' in the generic type or method 'A'. The nullable type 'int?' does not satisfy the constraint of 'int'. + // object o = new A(); Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum, "int?").WithArguments("A", "int", "T", "int?").WithLocation(7, 26), - // (8,9): error CS0312: The type 'int?' cannot be used as type parameter 'U' in the generic type or method 'B.M()'. The nullable type 'int?' does not satisfy the constraint of 'int'. - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum, "B.M").WithArguments("B.M()", "int", "U", "int?").WithLocation(8, 9)); + // (8,16): error CS0312: The type 'int?' cannot be used as type parameter 'U' in the generic type or method 'B.M()'. The nullable type 'int?' does not satisfy the constraint of 'int'. + // B.M(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum, "M").WithArguments("B.M()", "int", "U", "int?").WithLocation(8, 16)); } [Fact] @@ -10106,9 +10175,19 @@ public static void Main() } } "; - CreateStandardCompilation(text).VerifyDiagnostics( + CreateStandardCompilation(text, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (11,28): error CS0407: 'void C.G()' has the wrong return type - Diagnostic(ErrorCode.ERR_BadRetType, "G").WithArguments("C.G()", "void")); + // d = new MyDelegate(G); // CS0407 - G doesn't return int + Diagnostic(ErrorCode.ERR_BadRetType, "G").WithArguments("C.G()", "void").WithLocation(11, 28) + ); + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. + CreateStandardCompilation(text).VerifyDiagnostics( + // (11,13): error CS0123: No overload for 'G' matches delegate 'MyDelegate' + // d = new MyDelegate(G); // CS0407 - G doesn't return int + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new MyDelegate(G)").WithArguments("G", "MyDelegate").WithLocation(11, 13) + ); } [WorkItem(925899, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/925899")] @@ -10129,13 +10208,24 @@ public static void Main() } } "; + CreateStandardCompilation(text, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( + // (10,43): error CS0407: 'object System.Func.Invoke(object)' has the wrong return type + // var os = new Func(oo); + Diagnostic(ErrorCode.ERR_BadRetType, "oo").WithArguments("System.Func.Invoke(object)", "object").WithLocation(10, 43), + // (11,43): error CS0407: 'object System.Func.Invoke(object)' has the wrong return type + // var ss = new Func(oo); + Diagnostic(ErrorCode.ERR_BadRetType, "oo").WithArguments("System.Func.Invoke(object)", "object").WithLocation(11, 43) + ); + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. CreateStandardCompilation(text).VerifyDiagnostics( - // (10,43): error CS0407: 'object System.Func.Invoke(object)' has the wrong return type - // var os = new Func(oo); - Diagnostic(ErrorCode.ERR_BadRetType, "oo").WithArguments("System.Func.Invoke(object)", "object").WithLocation(10, 43), - // (11,43): error CS0407: 'object System.Func.Invoke(object)' has the wrong return type - // var ss = new Func(oo); - Diagnostic(ErrorCode.ERR_BadRetType, "oo").WithArguments("System.Func.Invoke(object)", "object").WithLocation(11, 43) + // (10,18): error CS0123: No overload for 'Func' matches delegate 'Func' + // var os = new Func(oo); + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Func(oo)").WithArguments("Func", "System.Func").WithLocation(10, 18), + // (11,18): error CS0123: No overload for 'Func' matches delegate 'Func' + // var ss = new Func(oo); + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Func(oo)").WithArguments("Func", "System.Func").WithLocation(11, 18) ); } @@ -17821,10 +17911,13 @@ public static void M(__arglist) { d, delegate() { } }, { d, 1, p }, { d, __arglist }, - { d, GetEnumerator } + { d, GetEnumerator }, + { d, SomeStaticMethod }, }; } + public static void SomeStaticMethod() {} + public void Add(dynamic d, int x, int* ptr) { } @@ -17854,13 +17947,23 @@ IEnumerator IEnumerable.GetEnumerator() var comp = CreateCompilationWithMscorlibAndSystemCore(source, new[] { CSharpRef }, options: TestOptions.UnsafeReleaseDll); comp.VerifyDiagnostics( // (16,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. - Diagnostic(ErrorCode.ERR_BadDynamicMethodArgLambda, "delegate() { }"), + // { d, delegate() { } }, + Diagnostic(ErrorCode.ERR_BadDynamicMethodArgLambda, "delegate() { }").WithLocation(16, 18), // (17,21): error CS1978: Cannot use an expression of type 'int*' as an argument to a dynamically dispatched operation. - Diagnostic(ErrorCode.ERR_BadDynamicMethodArg, "p").WithArguments("int*"), - // (18,18): error CS1978: Cannot use an expression of type 'System.RuntimeArgumentHandle' as an argument to a dynamically dispatched operation. - Diagnostic(ErrorCode.ERR_BadDynamicMethodArg, "__arglist").WithArguments("System.RuntimeArgumentHandle"), - // (19,18): error CS1976: Cannot use a method group as an argument to a dynamically dispatched operation. Did you intend to invoke the method? - Diagnostic(ErrorCode.ERR_BadDynamicMethodArgMemgrp, "GetEnumerator")); + // { d, 1, p }, + Diagnostic(ErrorCode.ERR_BadDynamicMethodArg, "p").WithArguments("int*").WithLocation(17, 21), + // (18,18): error CS1978: Cannot use an expression of type 'RuntimeArgumentHandle' as an argument to a dynamically dispatched operation. + // { d, __arglist }, + Diagnostic(ErrorCode.ERR_BadDynamicMethodArg, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(18, 18), + // (19,13): error CS1950: The best overloaded Add method 'C.Add(dynamic, RuntimeArgumentHandle)' for the collection initializer has some invalid arguments + // { d, GetEnumerator }, + Diagnostic(ErrorCode.ERR_BadArgTypesForCollectionAdd, "{ d, GetEnumerator }").WithArguments("C.Add(dynamic, System.RuntimeArgumentHandle)").WithLocation(19, 13), + // (19,18): error CS1503: Argument 2: cannot convert from 'method group' to 'RuntimeArgumentHandle' + // { d, GetEnumerator }, + Diagnostic(ErrorCode.ERR_BadArgType, "GetEnumerator").WithArguments("2", "method group", "System.RuntimeArgumentHandle").WithLocation(19, 18), + // (20,18): error CS1976: Cannot use a method group as an argument to a dynamically dispatched operation. Did you intend to invoke the method? + // { d, SomeStaticMethod }, + Diagnostic(ErrorCode.ERR_BadDynamicMethodArgMemgrp, "SomeStaticMethod").WithLocation(20, 18)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 2ef4b96822138..a9e02c5fc9ae0 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -4370,19 +4370,19 @@ public static void ExtensionMethod(this S s) CreateCompilationWithMscorlibAndSystemCore(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (26,9): error CS0176: Member 'S.StaticField' cannot be accessed with an instance reference; qualify it with a type name instead // p->StaticField = 1; //CS0176 - Diagnostic(ErrorCode.ERR_ObjectProhibited, "p->StaticField").WithArguments("S.StaticField"), + Diagnostic(ErrorCode.ERR_ObjectProhibited, "p->StaticField").WithArguments("S.StaticField").WithLocation(26, 9), // (29,9): error CS0176: Member 'S.StaticProperty' cannot be accessed with an instance reference; qualify it with a type name instead // p->StaticProperty = 2; //CS0176 - Diagnostic(ErrorCode.ERR_ObjectProhibited, "p->StaticProperty").WithArguments("S.StaticProperty"), + Diagnostic(ErrorCode.ERR_ObjectProhibited, "p->StaticProperty").WithArguments("S.StaticProperty").WithLocation(29, 9), // (32,9): error CS0176: Member 'S.StaticMethod()' cannot be accessed with an instance reference; qualify it with a type name instead // p->StaticMethod(); //CS0176 - Diagnostic(ErrorCode.ERR_ObjectProhibited, "p->StaticMethod").WithArguments("S.StaticMethod()"), + Diagnostic(ErrorCode.ERR_ObjectProhibited, "p->StaticMethod").WithArguments("S.StaticMethod()").WithLocation(32, 9), // (38,13): error CS0176: Member 'S.StaticMethod()' cannot be accessed with an instance reference; qualify it with a type name instead // a = p->StaticMethod; //CS0176 - Diagnostic(ErrorCode.ERR_ObjectProhibited, "p->StaticMethod").WithArguments("S.StaticMethod()"), + Diagnostic(ErrorCode.ERR_ObjectProhibited, "p->StaticMethod").WithArguments("S.StaticMethod()").WithLocation(38, 13), // (39,13): error CS1113: Extension method 'Extensions.ExtensionMethod(S)' defined on value type 'S' cannot be used to create delegates // a = p->ExtensionMethod; //CS1113 - Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "p->ExtensionMethod").WithArguments("Extensions.ExtensionMethod(S)", "S") + Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "p->ExtensionMethod").WithArguments("Extensions.ExtensionMethod(S)", "S").WithLocation(39, 13) ); } diff --git a/src/Compilers/CSharp/Test/Symbol/BadSymbolReference.cs b/src/Compilers/CSharp/Test/Symbol/BadSymbolReference.cs index 138bedac9be3c..5af0ae08298ff 100644 --- a/src/Compilers/CSharp/Test/Symbol/BadSymbolReference.cs +++ b/src/Compilers/CSharp/Test/Symbol/BadSymbolReference.cs @@ -313,6 +313,9 @@ interface I1 // (151,9): error CS0012: The type 'CL2_C1' is defined in an assembly that is not referenced. You must add a reference to assembly 'CL2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // CL3_C2.Test1(); Diagnostic(ErrorCode.ERR_NoTypeDef, "CL3_C2.Test1").WithArguments("CL2_C1", "CL2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(151, 9), + // (156,9): error CS0012: The type 'CL2_C1' is defined in an assembly that is not referenced. You must add a reference to assembly 'CL2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // CL3_C2.Test1(1); + Diagnostic(ErrorCode.ERR_NoTypeDef, "CL3_C2.Test1").WithArguments("CL2_C1", "CL2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(156, 9), // (156,9): error CS0120: An object reference is required for the non-static field, method, or property 'CL3_C2.Test1(int)' // CL3_C2.Test1(1); Diagnostic(ErrorCode.ERR_ObjectRequired, "CL3_C2.Test1").WithArguments("CL3_C2.Test1(int)").WithLocation(156, 9), @@ -500,6 +503,9 @@ public interface CL3_I1 : CL2_I1 // (151,9): error CS0246: The type or namespace name 'CL2_C1' could not be found (are you missing a using directive or an assembly reference?) // CL3_C2.Test1(); Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "CL3_C2.Test1").WithArguments("CL2_C1").WithLocation(151, 9), + // (156,9): error CS0246: The type or namespace name 'CL2_C1' could not be found (are you missing a using directive or an assembly reference?) + // CL3_C2.Test1(1); + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "CL3_C2.Test1").WithArguments("CL2_C1").WithLocation(156, 9), // (156,9): error CS0120: An object reference is required for the non-static field, method, or property 'CL3_C2.Test1(int)' // CL3_C2.Test1(1); Diagnostic(ErrorCode.ERR_ObjectRequired, "CL3_C2.Test1").WithArguments("CL3_C2.Test1(int)").WithLocation(156, 9), diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/GetSemanticInfoTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/GetSemanticInfoTests.cs index 0f59742d4bb32..563cc9edf902c 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/GetSemanticInfoTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/GetSemanticInfoTests.cs @@ -5714,7 +5714,7 @@ class C { } Assert.Equal(ConversionKind.MethodGroup, conversionB.Kind); var conversionC = model.ClassifyConversion(methodGroupSyntax, typeFuncC); - Assert.Equal(ConversionKind.MethodGroup, conversionC.Kind); + Assert.Equal(ConversionKind.NoConversion, conversionC.Kind); } [WorkItem(872064, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/872064")] diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetDeclaredSymbolAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetDeclaredSymbolAPITests.cs index c6f4119ae032e..2c35d2d319bb2 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetDeclaredSymbolAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetDeclaredSymbolAPITests.cs @@ -1871,8 +1871,10 @@ internal static void F(this T t) where T : A { } }"; var compilation = CreateCompilationWithMscorlibAndSystemCore(source); compilation.VerifyDiagnostics( - // (8,9): error CS0311: The type 'B' cannot be used as type parameter 'T' in the generic type or method 'E.F(T)'. There is no implicit reference conversion from 'B' to 'A'. - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "b.F").WithArguments("E.F(T)", "A", "T", "B").WithLocation(8, 9)); + // (8,11): error CS0311: The type 'B' cannot be used as type parameter 'T' in the generic type or method 'E.F(T)'. There is no implicit reference conversion from 'B' to 'A'. + // b.F(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "F").WithArguments("E.F(T)", "A", "T", "B").WithLocation(8, 11) +); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -1910,8 +1912,9 @@ internal static void F(this T t) where T : A { } }"; compilation = CreateCompilationWithMscorlibAndSystemCore(source); compilation.VerifyDiagnostics( - // (8,9): error CS0311: The type 'B' cannot be used as type parameter 'T' in the generic type or method 'E.F(T)'. There is no implicit reference conversion from 'B' to 'A'. - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "b.F").WithArguments("E.F(T)", "A", "T", "B").WithLocation(8, 9)); + // (8,11): error CS0311: The type 'B' cannot be used as type parameter 'T' in the generic type or method 'E.F(T)'. There is no implicit reference conversion from 'B' to 'A'. + // b.F(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "F").WithArguments("E.F(T)", "A", "T", "B").WithLocation(8, 11)); tree = compilation.SyntaxTrees.Single(); model = compilation.GetSemanticModel(tree); diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs index 7bc8376b8c6d3..b7261cbf152c9 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs @@ -7960,28 +7960,47 @@ static void Main(string[] args) } } "; - var semanticInfo = GetSemanticInfoForTest(sourceCode); + { + var semanticInfo = GetSemanticInfoForTest(sourceCode, + parseOptions: TestOptions.WithoutImprovedOverloadCandidates); - Assert.Null(semanticInfo.Type); - Assert.Equal("System.Action", semanticInfo.ConvertedType.ToTestDisplayString()); - Assert.Equal(ConversionKind.MethodGroup, semanticInfo.ImplicitConversion.Kind); + Assert.Null(semanticInfo.Type); + Assert.Equal("System.Action", semanticInfo.ConvertedType.ToTestDisplayString()); + Assert.Equal(ConversionKind.MethodGroup, semanticInfo.ImplicitConversion.Kind); - Assert.Equal("System.Int32 Program.f()", semanticInfo.Symbol.ToTestDisplayString()); - Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason); - Assert.Empty(semanticInfo.CandidateSymbols); + Assert.Equal("System.Int32 Program.f()", semanticInfo.Symbol.ToTestDisplayString()); + Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason); + Assert.Empty(semanticInfo.CandidateSymbols); - Assert.Equal(1, semanticInfo.MethodGroup.Length); - Assert.Equal("System.Int32 Program.f()", semanticInfo.MethodGroup[0].ToTestDisplayString()); + Assert.Equal(1, semanticInfo.MethodGroup.Length); + Assert.Equal("System.Int32 Program.f()", semanticInfo.MethodGroup[0].ToTestDisplayString()); - Assert.False(semanticInfo.IsCompileTimeConstant); + Assert.False(semanticInfo.IsCompileTimeConstant); + } + { + var semanticInfo = GetSemanticInfoForTest(sourceCode); + + + Assert.Null(semanticInfo.Type); + Assert.Equal("System.Action", semanticInfo.ConvertedType.ToTestDisplayString()); + Assert.Equal(ConversionKind.MethodGroup, semanticInfo.ImplicitConversion.Kind); + + Assert.Null(semanticInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, semanticInfo.CandidateReason); + Assert.Equal("System.Int32 Program.f()", semanticInfo.CandidateSymbols[0].ToTestDisplayString()); + Assert.Equal(1, semanticInfo.CandidateSymbols.Length); + + Assert.Equal(1, semanticInfo.MethodGroup.Length); + Assert.Equal("System.Int32 Program.f()", semanticInfo.MethodGroup[0].ToTestDisplayString()); + + Assert.False(semanticInfo.IsCompileTimeConstant); + } } [Fact] public void DelegateSignatureMismatch4() { - // This test and the DelgateSignatureMismatch3 should have identical results, as they are semantically identical - string sourceCode = @" using System; using System.Collections.Generic; @@ -7996,20 +8015,42 @@ static void Main(string[] args) } } "; - var semanticInfo = GetSemanticInfoForTest(sourceCode); + { + var semanticInfo = GetSemanticInfoForTest(sourceCode, + parseOptions: TestOptions.WithoutImprovedOverloadCandidates); - Assert.Null(semanticInfo.Type); - Assert.Equal("System.Action", semanticInfo.ConvertedType.ToTestDisplayString()); - Assert.Equal(ConversionKind.MethodGroup, semanticInfo.ImplicitConversion.Kind); - Assert.Equal("System.Int32 Program.f()", semanticInfo.Symbol.ToTestDisplayString()); - Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason); - Assert.Empty(semanticInfo.CandidateSymbols); + Assert.Null(semanticInfo.Type); + Assert.Equal("System.Action", semanticInfo.ConvertedType.ToTestDisplayString()); + Assert.Equal(ConversionKind.MethodGroup, semanticInfo.ImplicitConversion.Kind); - Assert.Equal(1, semanticInfo.MethodGroup.Length); - Assert.Equal("System.Int32 Program.f()", semanticInfo.MethodGroup[0].ToTestDisplayString()); + Assert.Equal("System.Int32 Program.f()", semanticInfo.Symbol.ToTestDisplayString()); + Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason); + Assert.Empty(semanticInfo.CandidateSymbols); - Assert.False(semanticInfo.IsCompileTimeConstant); + Assert.Equal(1, semanticInfo.MethodGroup.Length); + Assert.Equal("System.Int32 Program.f()", semanticInfo.MethodGroup[0].ToTestDisplayString()); + + Assert.False(semanticInfo.IsCompileTimeConstant); + } + { + var semanticInfo = GetSemanticInfoForTest(sourceCode); + + + Assert.Null(semanticInfo.Type); + Assert.Equal("System.Action", semanticInfo.ConvertedType.ToTestDisplayString()); + Assert.Equal(ConversionKind.NoConversion, semanticInfo.ImplicitConversion.Kind); + + Assert.Null(semanticInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, semanticInfo.CandidateReason); + Assert.Equal("System.Int32 Program.f()", semanticInfo.CandidateSymbols[0].ToTestDisplayString()); + Assert.Equal(1, semanticInfo.CandidateSymbols.Length); + + Assert.Equal(1, semanticInfo.MethodGroup.Length); + Assert.Equal("System.Int32 Program.f()", semanticInfo.MethodGroup[0].ToTestDisplayString()); + + Assert.False(semanticInfo.IsCompileTimeConstant); + } } [WorkItem(541802, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541802")] @@ -13006,9 +13047,12 @@ public static void Main() Assert.Equal(TypeKind.Class, semanticInfo.ConvertedType.TypeKind); Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind); - Assert.Equal("MemberInitializerTest MemberInitializerTest.Goo()", semanticInfo.Symbol.ToTestDisplayString()); - Assert.Equal(SymbolKind.Method, semanticInfo.Symbol.Kind); - Assert.Equal(0, semanticInfo.CandidateSymbols.Length); + Assert.Null(semanticInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, semanticInfo.CandidateReason); + Assert.Equal(1, semanticInfo.CandidateSymbols.Length); + var symbol = semanticInfo.CandidateSymbols[0]; + Assert.Equal("MemberInitializerTest MemberInitializerTest.Goo()", symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Method, symbol.Kind); Assert.Equal(0, semanticInfo.MethodGroup.Length); @@ -13016,7 +13060,7 @@ public static void Main() } [Fact] - public void ObjectInitializer_BadNamedAssignmentLeft_InvocationExpressionSyntax() + public void ObjectInitializer_BadNamedAssignmentLeft_InvocationExpressionSyntax_01() { string sourceCode = @" public class MemberInitializerTest @@ -13037,9 +13081,46 @@ public static void Main() Assert.Equal(TypeKind.Class, semanticInfo.ConvertedType.TypeKind); Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind); - Assert.Equal("MemberInitializerTest MemberInitializerTest.Goo()", semanticInfo.Symbol.ToTestDisplayString()); - Assert.Equal(SymbolKind.Method, semanticInfo.Symbol.Kind); - Assert.Equal(0, semanticInfo.CandidateSymbols.Length); + Assert.Null(semanticInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, semanticInfo.CandidateReason); + Assert.Equal(1, semanticInfo.CandidateSymbols.Length); + var symbol = semanticInfo.CandidateSymbols[0]; + Assert.Equal("MemberInitializerTest MemberInitializerTest.Goo()", symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Method, symbol.Kind); + + Assert.Equal(0, semanticInfo.MethodGroup.Length); + + Assert.False(semanticInfo.IsCompileTimeConstant); + } + + [Fact] + public void ObjectInitializer_BadNamedAssignmentLeft_InvocationExpressionSyntax_02() + { + string sourceCode = @" +public class MemberInitializerTest +{ + public int x; + public static MemberInitializerTest Goo() { return new MemberInitializerTest(); } + public static void Main() + { + var i = new MemberInitializerTest() { x = 0, /**/Goo()/**/ = new MemberInitializerTest() }; + } +} +"; + var semanticInfo = GetSemanticInfoForTest(sourceCode); + + Assert.Equal("MemberInitializerTest", semanticInfo.Type.ToTestDisplayString()); + Assert.Equal(TypeKind.Class, semanticInfo.Type.TypeKind); + Assert.Equal("MemberInitializerTest", semanticInfo.ConvertedType.ToTestDisplayString()); + Assert.Equal(TypeKind.Class, semanticInfo.ConvertedType.TypeKind); + Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind); + + Assert.Null(semanticInfo.Symbol); + Assert.Equal(CandidateReason.NotAVariable, semanticInfo.CandidateReason); + Assert.Equal(1, semanticInfo.CandidateSymbols.Length); + var symbol = semanticInfo.CandidateSymbols[0]; + Assert.Equal("MemberInitializerTest MemberInitializerTest.Goo()", symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Method, symbol.Kind); Assert.Equal(0, semanticInfo.MethodGroup.Length); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs index 28e5eb89c54cd..754e98d4e35ca 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs @@ -1888,10 +1888,12 @@ static void M(Out f) { } // The return type of F isn't considered until the delegate compatibility check, // which happens AFTER determining that the method group conversion exists. As // a result, both methods are considered applicable and the "wrong" one is chosen. - CreateCompilationWithMscorlibAndSystemCore(source).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSystemCore(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (8,11): error CS0407: 'dynamic C.F()' has the wrong return type // M(F); Diagnostic(ErrorCode.ERR_BadRetType, "F").WithArguments("C.F()", "dynamic")); + // However, we later added a feature that takes the return type into account. + CreateCompilationWithMscorlibAndSystemCore(source).VerifyDiagnostics(); } [WorkItem(737971, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/737971")] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs index f78d3f1cac8f7..16b2213adf4e1 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs @@ -1000,8 +1000,8 @@ static class S3 { internal static object F3(this N.C x, object y) { return null; } }"; - var compilation = CreateStandardCompilation(source, references: new[] { SystemCoreRef }); - compilation.VerifyDiagnostics( + CreateStandardCompilation(source, references: new[] { SystemCoreRef }, + parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (10,16): error CS0407: 'void S2.F1(object, object)' has the wrong return type Diagnostic(ErrorCode.ERR_BadRetType, "c.F1").WithArguments("S2.F1(object, object)", "void").WithLocation(10, 16), // (13,16): error CS0407: 'object S2.F2(N.C, object)' has the wrong return type @@ -1009,6 +1009,19 @@ static class S3 // (14,16): error CS1503: Argument 1: cannot convert from 'method group' to 'System.Func' // M1(c.F3); // ambiguous Diagnostic(ErrorCode.ERR_BadArgType, "c.F3").WithArguments("1", "method group", "System.Func")); + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case + // because we don't report *why* a delegate conversion failed. + // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. + CreateStandardCompilation(source, references: new[] { SystemCoreRef }).VerifyDiagnostics( + // (10,16): error CS1503: Argument 1: cannot convert from 'method group' to 'Func' + // M1(c.F1); // wrong return type + Diagnostic(ErrorCode.ERR_BadArgType, "c.F1").WithArguments("1", "method group", "System.Func").WithLocation(10, 16), + // (13,16): error CS1503: Argument 1: cannot convert from 'method group' to 'Action' + // M2(c.F2); // wrong return type + Diagnostic(ErrorCode.ERR_BadArgType, "c.F2").WithArguments("1", "method group", "System.Action").WithLocation(13, 16), + // (14,16): error CS1503: Argument 1: cannot convert from 'method group' to 'Func' + // M1(c.F3); // ambiguous + Diagnostic(ErrorCode.ERR_BadArgType, "c.F3").WithArguments("1", "method group", "System.Func").WithLocation(14, 16)); } [Fact] @@ -1874,7 +1887,7 @@ public void InvalidTypeArguments() void M() { this.E(1); - this.E(null); + this.E(); this.E(null); this.E(1); } @@ -1890,9 +1903,9 @@ public static void E(this C c, T t) }"; var compilation = CreateStandardCompilation(source, references: new[] { SystemCoreRef }); compilation.VerifyDiagnostics( - // (6,9): error CS0718: 'S': static types cannot be used as type arguments - // this.E(null); - Diagnostic(ErrorCode.ERR_GenericArgIsStaticClass, "this.E").WithArguments("S").WithLocation(6, 9), + // (6,14): error CS0718: 'S': static types cannot be used as type arguments + // this.E(); + Diagnostic(ErrorCode.ERR_GenericArgIsStaticClass, "E").WithArguments("S").WithLocation(6, 14), // (7,16): error CS0246: The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?) // this.E(null); Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("A").WithLocation(7, 16), @@ -3771,9 +3784,9 @@ public class BaseClass "; var compilation = CreateStandardCompilation(source, references: new[] { SystemCoreRef }); compilation.VerifyDiagnostics( - // (7,9): error CS0311: The type 'BaseClass' cannot be used as type parameter 'BC' in the generic type or method 'Extensions.SetMember(BC, TMember)'. There is no implicit reference conversion from 'BaseClass' to 'BaseClass'. + // (7,18): error CS0311: The type 'BaseClass' cannot be used as type parameter 'BC' in the generic type or method 'Extensions.SetMember(BC, TMember)'. There is no implicit reference conversion from 'BaseClass' to 'BaseClass'. // Instance.SetMember(32); - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "Instance.SetMember").WithArguments("Extensions.SetMember(BC, TMember)", "BaseClass", "BC", "BaseClass").WithLocation(7, 9) + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "SetMember").WithArguments("Extensions.SetMember(BC, TMember)", "BaseClass", "BC", "BaseClass").WithLocation(7, 18) ); var tree = compilation.SyntaxTrees.Single(); @@ -3866,9 +3879,9 @@ public class BaseClass : I1 "; var compilation = CreateStandardCompilation(source, references: new[] { SystemCoreRef }); compilation.VerifyDiagnostics( - // (7,9): error CS0311: The type 'BaseClass' cannot be used as type parameter 'BC' in the generic type or method 'Extensions.SetMember(BC, TMember)'. There is no implicit reference conversion from 'BaseClass' to 'I1'. + // (7,18): error CS0311: The type 'BaseClass' cannot be used as type parameter 'BC' in the generic type or method 'Extensions.SetMember(BC, TMember)'. There is no implicit reference conversion from 'BaseClass' to 'I1'. // Instance.SetMember(32); - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "Instance.SetMember").WithArguments("Extensions.SetMember(BC, TMember)", "I1", "BC", "BaseClass").WithLocation(7, 9) + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "SetMember").WithArguments("Extensions.SetMember(BC, TMember)", "I1", "BC", "BaseClass").WithLocation(7, 18) ); var tree = compilation.SyntaxTrees.Single(); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs index 935b9fbc7a804..14b92f61a75d4 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs @@ -1078,11 +1078,12 @@ static void E(this object o) { } static void F(this object o) { } static void F(this T t) where T : struct { } }"; - CreateStandardCompilation(text, references: new[] { SystemCoreRef }).VerifyDiagnostics( + CreateStandardCompilation(text, references: new[] { SystemCoreRef }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (7,9): error CS0310: 'I' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C.E(T)' Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "i.E").WithArguments("C.E(T)", "T", "I").WithLocation(7, 9), // (9,9): error CS0453: The type 'I' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'C.F(T)' Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "i.F").WithArguments("C.F(T)", "T", "I").WithLocation(9, 9)); + CreateStandardCompilation(text, references: new[] { SystemCoreRef }).VerifyDiagnostics(); } [ClrOnlyFact] @@ -2701,9 +2702,9 @@ static void M() // (3,29): error CS0454: Circular constraint dependency involving 'T' and 'T' // static void M(A a) { } Diagnostic(ErrorCode.ERR_CircularConstraint, "a").WithArguments("T", "T").WithLocation(3, 29), - // (6,9): error CS0454: Circular constraint dependency involving 'T' and 'U' + // (6,11): error CS0454: Circular constraint dependency involving 'T' and 'U' // B.M(); - Diagnostic(ErrorCode.ERR_CircularConstraint, "B.M").WithArguments("T", "U").WithLocation(6, 9)); + Diagnostic(ErrorCode.ERR_CircularConstraint, "M").WithArguments("T", "U").WithLocation(6, 11)); } /// @@ -2733,18 +2734,18 @@ static void M() // Note: for method overload resolution, methods with use-site errors // are ignored so there is no constraint error for B.M(). CreateCompilationWithCustomILSource(csharpSource, ilSource).VerifyDiagnostics( - // (3,29): error CS0012: The type 'C' is defined in an assembly that is not referenced. You must add a reference to assembly 'other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. - // static void M(A a) { } - Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("C", "other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(3, 29), // (3,29): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A'. There is no implicit reference conversion from 'object' to 'C'. // static void M(A a) { } Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "a").WithArguments("A", "C", "T", "object").WithLocation(3, 29), - // (6,9): error CS0311: The type 'string' cannot be used as type parameter 'U' in the generic type or method 'B.M()'. There is no implicit reference conversion from 'string' to 'C'. + // (3,29): error CS0012: The type 'C' is defined in an assembly that is not referenced. You must add a reference to assembly 'other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // static void M(A a) { } + Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("C", "other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(3, 29), + // (6,11): error CS0311: The type 'string' cannot be used as type parameter 'U' in the generic type or method 'B.M()'. There is no implicit reference conversion from 'string' to 'C'. // B.M(); - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "B.M").WithArguments("B.M()", "C", "U", "string").WithLocation(6, 9), - // (6,9): error CS0012: The type 'C' is defined in an assembly that is not referenced. You must add a reference to assembly 'other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("B.M()", "C", "U", "string").WithLocation(6, 11), + // (6,11): error CS0012: The type 'C' is defined in an assembly that is not referenced. You must add a reference to assembly 'other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // B.M(); - Diagnostic(ErrorCode.ERR_NoTypeDef, "B.M").WithArguments("C", "other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 9)); + Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("C", "other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 11)); } [Fact] @@ -2894,36 +2895,36 @@ static void M() } }"; CreateCompilationWithCustomILSource(csharpSource, ilSource).VerifyDiagnostics( - // (3,30): error CS0012: The type 'B1' is defined in an assembly that is not referenced. You must add a reference to assembly 'other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. - // static void M(A1 a) { } - Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("B1", "other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(3, 30), - // (4,30): error CS0012: The type 'B2' is defined in an assembly that is not referenced. You must add a reference to assembly 'other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. - // static void M(A2 a) { } - Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("B2", "other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 30), - // (3,30): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A1'. There is no implicit reference conversion from 'object' to 'B1'. - // static void M(A1 a) { } - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "a").WithArguments("A1", "B1", "T", "object").WithLocation(3, 30), // (4,30): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A2'. There is no implicit reference conversion from 'object' to 'B2'. // static void M(A2 a) { } Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "a").WithArguments("A2", "B2", "T", "object").WithLocation(4, 30), // (4,30): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A2'. There is no implicit reference conversion from 'object' to 'I'. // static void M(A2 a) { } Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "a").WithArguments("A2", "I", "T", "object").WithLocation(4, 30), + // (4,30): error CS0012: The type 'B2' is defined in an assembly that is not referenced. You must add a reference to assembly 'other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // static void M(A2 a) { } + Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("B2", "other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 30), // (4,30): error CS0012: The type 'I' is defined in an assembly that is not referenced. You must add a reference to assembly 'other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // static void M(A2 a) { } Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("I", "other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 30), + // (3,30): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A1'. There is no implicit reference conversion from 'object' to 'B1'. + // static void M(A1 a) { } + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "a").WithArguments("A1", "B1", "T", "object").WithLocation(3, 30), // (3,30): error CS0454: Circular constraint dependency involving 'T' and 'T' // static void M(A1 a) { } Diagnostic(ErrorCode.ERR_CircularConstraint, "a").WithArguments("T", "T").WithLocation(3, 30), - // (7,9): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A3.M()'. There is no implicit reference conversion from 'object' to 'B3'. + // (3,30): error CS0012: The type 'B1' is defined in an assembly that is not referenced. You must add a reference to assembly 'other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // static void M(A1 a) { } + Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("B1", "other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(3, 30), + // (7,12): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A3.M()'. There is no implicit reference conversion from 'object' to 'B3'. // A3.M(); - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "A3.M").WithArguments("A3.M()", "B3", "T", "object").WithLocation(7, 9), - // (7,9): error CS0454: Circular constraint dependency involving 'T' and 'T' + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("A3.M()", "B3", "T", "object").WithLocation(7, 12), + // (7,12): error CS0454: Circular constraint dependency involving 'T' and 'T' // A3.M(); - Diagnostic(ErrorCode.ERR_CircularConstraint, "A3.M").WithArguments("T", "T").WithLocation(7, 9), - // (7,9): error CS0012: The type 'B3' is defined in an assembly that is not referenced. You must add a reference to assembly 'other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + Diagnostic(ErrorCode.ERR_CircularConstraint, "M").WithArguments("T", "T").WithLocation(7, 12), + // (7,12): error CS0012: The type 'B3' is defined in an assembly that is not referenced. You must add a reference to assembly 'other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // A3.M(); - Diagnostic(ErrorCode.ERR_NoTypeDef, "A3.M").WithArguments("B3", "other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 9)); + Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("B3", "other, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 12)); } // Same as UseSiteErrorMissingConstraintTypeAndCircularConstraint but @@ -2963,30 +2964,30 @@ static void M() }"; var compilation3 = CreateStandardCompilation(source3, references: new MetadataReference[] { new CSharpCompilationReference(compilation2) }); compilation3.VerifyDiagnostics( - // (3,30): error CS0012: The type 'B1' is defined in an assembly that is not referenced. You must add a reference to assembly 'd521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. - // static void M(A1 a) { } - Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("B1", "d521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(3, 30), - // (4,30): error CS0012: The type 'B2' is defined in an assembly that is not referenced. You must add a reference to assembly 'd521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. - // static void M(A2 a) { } - Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("B2", "d521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 30), - // (3,30): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A1'. There is no implicit reference conversion from 'object' to 'B1'. - // static void M(A1 a) { } - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "a").WithArguments("A1", "B1", "T", "object").WithLocation(3, 30), // (4,30): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A2'. There is no implicit reference conversion from 'object' to 'B2'. // static void M(A2 a) { } Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "a").WithArguments("A2", "B2", "T", "object").WithLocation(4, 30), // (4,30): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A2'. There is no implicit reference conversion from 'object' to 'I'. // static void M(A2 a) { } Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "a").WithArguments("A2", "I", "T", "object").WithLocation(4, 30), + // (4,30): error CS0012: The type 'B2' is defined in an assembly that is not referenced. You must add a reference to assembly 'd521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // static void M(A2 a) { } + Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("B2", "d521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 30), // (4,30): error CS0012: The type 'I' is defined in an assembly that is not referenced. You must add a reference to assembly 'd521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // static void M(A2 a) { } Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("I", "d521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 30), - // (7,9): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A3.M()'. There is no implicit reference conversion from 'object' to 'B3'. + // (3,30): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A1'. There is no implicit reference conversion from 'object' to 'B1'. + // static void M(A1 a) { } + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "a").WithArguments("A1", "B1", "T", "object").WithLocation(3, 30), + // (3,30): error CS0012: The type 'B1' is defined in an assembly that is not referenced. You must add a reference to assembly 'd521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // static void M(A1 a) { } + Diagnostic(ErrorCode.ERR_NoTypeDef, "a").WithArguments("B1", "d521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(3, 30), + // (7,12): error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'A3.M()'. There is no implicit reference conversion from 'object' to 'B3'. // A3.M(); - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "A3.M").WithArguments("A3.M()", "B3", "T", "object").WithLocation(7, 9), - // (7,9): error CS0012: The type 'B3' is defined in an assembly that is not referenced. You must add a reference to assembly 'd521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("A3.M()", "B3", "T", "object").WithLocation(7, 12), + // (7,12): error CS0012: The type 'B3' is defined in an assembly that is not referenced. You must add a reference to assembly 'd521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // A3.M(); - Diagnostic(ErrorCode.ERR_NoTypeDef, "A3.M").WithArguments("B3", "d521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 9)); + Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("B3", "d521fe98-c881-45cf-8870-249e00ae400d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 12)); } [WorkItem(542753, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542753")] @@ -3320,24 +3321,24 @@ static void Main() // (7,17): error CS0648: '' is a type not supported by the language // void I.M() { } Diagnostic(ErrorCode.ERR_BogusType, "T").WithArguments("").WithLocation(7, 17), - // (13,9): error CS0311: The type 'A' cannot be used as type parameter 'T' in the generic type or method 'A.M()'. There is no implicit reference conversion from 'A' to '?'. + // (13,17): error CS0311: The type 'A' cannot be used as type parameter 'T' in the generic type or method 'A.M()'. There is no implicit reference conversion from 'A' to '?'. // new A().M(); - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "new A().M").WithArguments("A.M()", "?", "T", "A").WithLocation(13, 9), - // (13,9): error CS0648: '' is a type not supported by the language + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("A.M()", "?", "T", "A").WithLocation(13, 17), + // (13,17): error CS0648: '' is a type not supported by the language // new A().M(); - Diagnostic(ErrorCode.ERR_BogusType, "new A().M").WithArguments("").WithLocation(13, 9), + Diagnostic(ErrorCode.ERR_BogusType, "M").WithArguments("").WithLocation(13, 17), // (15,13): error CS0311: The type 'A' cannot be used as type parameter 'T' in the generic type or method 'I'. There is no implicit reference conversion from 'A' to '?'. // ((I)new C()).M(); Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "A").WithArguments("I", "?", "T", "A").WithLocation(15, 13), // (15,13): error CS0648: '' is a type not supported by the language // ((I)new C()).M(); Diagnostic(ErrorCode.ERR_BogusType, "A").WithArguments("").WithLocation(15, 13), - // (15,9): error CS0311: The type 'A' cannot be used as type parameter 'U' in the generic type or method 'I.M()'. There is no implicit reference conversion from 'A' to '?'. + // (15,25): error CS0311: The type 'A' cannot be used as type parameter 'U' in the generic type or method 'I.M()'. There is no implicit reference conversion from 'A' to '?'. // ((I)new C()).M(); - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "((I)new C()).M").WithArguments("I.M()", "?", "U", "A").WithLocation(15, 9), - // (15,9): error CS0648: '' is a type not supported by the language + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("I.M()", "?", "U", "A").WithLocation(15, 25), + // (15,25): error CS0648: '' is a type not supported by the language // ((I)new C()).M(); - Diagnostic(ErrorCode.ERR_BogusType, "((I)new C()).M").WithArguments("").WithLocation(15, 9)); + Diagnostic(ErrorCode.ERR_BogusType, "M").WithArguments("").WithLocation(15, 25)); } /// @@ -5039,12 +5040,16 @@ static void M() where T2 : I, I }"; CreateStandardCompilation(source).VerifyDiagnostics( // (11,26): error CS0311: The type 'object' cannot be used as type parameter 'U' in the generic type or method 'A'. There is no implicit reference conversion from 'object' to 'I'. + // new A, object>(); Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "object").WithArguments("A", "I", "U", "object").WithLocation(11, 26), - // (12,9): error CS0311: The type 'string' cannot be used as type parameter 'U' in the generic type or method 'B>.M()'. There is no implicit reference conversion from 'string' to 'I'. - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "B>.M").WithArguments("B>.M()", "I", "U", "string").WithLocation(12, 9), - // (12,9): error CS0311: The type 'string' cannot be used as type parameter 'U' in the generic type or method 'B>.M()'. There is no implicit reference conversion from 'string' to 'I'. - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "B>.M").WithArguments("B>.M()", "I", "U", "string").WithLocation(12, 9), + // (12,22): error CS0311: The type 'string' cannot be used as type parameter 'U' in the generic type or method 'B>.M()'. There is no implicit reference conversion from 'string' to 'I'. + // B>.M(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("B>.M()", "I", "U", "string").WithLocation(12, 22), + // (12,22): error CS0311: The type 'string' cannot be used as type parameter 'U' in the generic type or method 'B>.M()'. There is no implicit reference conversion from 'string' to 'I'. + // B>.M(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("B>.M()", "I", "U", "string").WithLocation(12, 22), // (13,9): error CS0311: The type 'object' cannot be used as type parameter 'T2' in the generic type or method 'C.M()'. There is no implicit reference conversion from 'object' to 'I'. + // M(); Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("C.M()", "I", "T2", "object").WithLocation(13, 9)); } @@ -5763,10 +5768,12 @@ internal override void M2() } }"; CreateStandardCompilation(source).VerifyDiagnostics( - // (23,9): error CS0314: The type 'U' cannot be used as type parameter 'U' in the generic type or method 'A.M0()'. There is no boxing conversion or type parameter conversion from 'U' to 'int'. - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "base.M0").WithArguments("A.M0()", "int", "U", "U").WithLocation(23, 9), - // (24,9): error CS0314: The type 'U' cannot be used as type parameter 'U' in the generic type or method 'A.M1()'. There is no boxing conversion or type parameter conversion from 'U' to 'int'. - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "base.M1").WithArguments("A.M1()", "int", "U", "U").WithLocation(24, 9)); + // (23,14): error CS0314: The type 'U' cannot be used as type parameter 'U' in the generic type or method 'A.M0()'. There is no boxing conversion or type parameter conversion from 'U' to 'int'. + // base.M0(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "M0").WithArguments("A.M0()", "int", "U", "U").WithLocation(23, 14), + // (24,14): error CS0314: The type 'U' cannot be used as type parameter 'U' in the generic type or method 'A.M1()'. There is no boxing conversion or type parameter conversion from 'U' to 'int'. + // base.M1(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "M1").WithArguments("A.M1()", "int", "U", "U").WithLocation(24, 14)); } [WorkItem(545588, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545588")] @@ -5792,8 +5799,9 @@ internal override void M1() } }"; CreateStandardCompilation(source).VerifyDiagnostics( - // (12,9): error CS0311: The type 'U' cannot be used as type parameter 'V' in the generic type or method 'A.M1()'. There is no implicit reference conversion from 'U' to 'V'. - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "base.M1").WithArguments("A.M1()", "V", "V", "U").WithLocation(12, 9)); + // (12,14): error CS0311: The type 'U' cannot be used as type parameter 'V' in the generic type or method 'A.M1()'. There is no implicit reference conversion from 'U' to 'V'. + // base.M1(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M1").WithArguments("A.M1()", "V", "V", "U").WithLocation(12, 14)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolDistinguisherTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolDistinguisherTests.cs index 445fdf88ac26c..9c48a4d10ee0e 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolDistinguisherTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolDistinguisherTests.cs @@ -609,9 +609,9 @@ public static void Main() // file.cs(6,15): warning CS0436: The type 'C' in 'file.cs' conflicts with the imported type 'C' in 'Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'file.cs'. // Lib.M(); Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "C").WithArguments("file.cs", "C", "Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "C").WithLocation(6, 15), - // file.cs(6,9): error CS0311: The type 'C [file.cs(2)]' cannot be used as type parameter 'T' in the generic type or method 'Lib.M()'. There is no implicit reference conversion from 'C [file.cs(2)]' to 'C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]'. + // file.cs(6,13): error CS0311: The type 'C [file.cs(2)]' cannot be used as type parameter 'T' in the generic type or method 'Lib.M()'. There is no implicit reference conversion from 'C [file.cs(2)]' to 'C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]'. // Lib.M(); - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "Lib.M").WithArguments("Lib.M()", "C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]", "T", "C [file.cs(2)]").WithLocation(6, 9)); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("Lib.M()", "C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]", "T", "C [file.cs(2)]").WithLocation(6, 13)); } // Not relevant: will always have one nullable and one non-nullable. @@ -643,9 +643,9 @@ public static void M() var libRef = CreateStandardCompilation(libSource, assemblyName: "Metadata").EmitToImageReference(); CreateStandardCompilation(Parse(source, "file.cs"), new[] { libRef }, assemblyName: "Source").VerifyDiagnostics( - // file.cs(6,9): error CS0314: The type 'C [file.cs(2)]' cannot be used as type parameter 'T' in the generic type or method 'Lib.M()'. There is no boxing conversion or type parameter conversion from 'C [file.cs(2)]' to 'C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]'. + // file.cs(6,13): error CS0314: The type 'C [file.cs(2)]' cannot be used as type parameter 'T' in the generic type or method 'Lib.M()'. There is no boxing conversion or type parameter conversion from 'C [file.cs(2)]' to 'C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]'. // Lib.M(); - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "Lib.M").WithArguments("Lib.M()", "C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]", "T", "C [file.cs(2)]").WithLocation(6, 9)); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "M").WithArguments("Lib.M()", "C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]", "T", "C [file.cs(2)]").WithLocation(6, 13)); } [Fact] @@ -677,9 +677,9 @@ public static void Main() // file.cs(8,15): warning CS0436: The type 'C' in 'file.cs' conflicts with the imported type 'C' in 'Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'file.cs'. // Lib.M(); Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "C").WithArguments("file.cs", "C", "Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "C").WithLocation(8, 15), - // file.cs(8,9): error CS0315: The type 'C [file.cs(2)]' cannot be used as type parameter 'T' in the generic type or method 'Lib.M()'. There is no boxing conversion from 'C [file.cs(2)]' to 'C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]'. + // file.cs(8,13): error CS0315: The type 'C [file.cs(2)]' cannot be used as type parameter 'T' in the generic type or method 'Lib.M()'. There is no boxing conversion from 'C [file.cs(2)]' to 'C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]'. // Lib.M(); - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "Lib.M").WithArguments("Lib.M()", "C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]", "T", "C [file.cs(2)]").WithLocation(8, 9)); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M").WithArguments("Lib.M()", "C [Metadata, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]", "T", "C [file.cs(2)]").WithLocation(8, 13)); } [WorkItem(6262, "https://github.com/dotnet/roslyn/issues/6262")] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index 30dab31e0413a..1c60d91133e9e 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -4125,36 +4125,36 @@ internal static void E(this object o) { } } "; CreateCompilationWithMscorlib46(source).VerifyDiagnostics( -// (7,15): error CS0306: The type 'int*' may not be used as a type argument -// new C(); -Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*"), -// (8,15): error CS0306: The type 'System.ArgIterator' may not be used as a type argument -// new C(); -Diagnostic(ErrorCode.ERR_BadTypeArgument, "ArgIterator").WithArguments("System.ArgIterator"), -// (9,15): error CS0306: The type 'System.RuntimeArgumentHandle' may not be used as a type argument -// new C(); -Diagnostic(ErrorCode.ERR_BadTypeArgument, "RuntimeArgumentHandle").WithArguments("System.RuntimeArgumentHandle"), -// (10,15): error CS0306: The type 'System.TypedReference' may not be used as a type argument -// new C(); -Diagnostic(ErrorCode.ERR_BadTypeArgument, "TypedReference").WithArguments("System.TypedReference"), -// (11,9): error CS0306: The type 'int*' may not be used as a type argument -// F(); -Diagnostic(ErrorCode.ERR_BadTypeArgument, "F").WithArguments("int*"), -// (12,9): error CS0306: The type 'System.ArgIterator' may not be used as a type argument -// o.E(); -Diagnostic(ErrorCode.ERR_BadTypeArgument, "o.E").WithArguments("System.ArgIterator"), -// (14,13): error CS0306: The type 'System.RuntimeArgumentHandle' may not be used as a type argument -// a = F; -Diagnostic(ErrorCode.ERR_BadTypeArgument, "F").WithArguments("System.RuntimeArgumentHandle"), -// (15,13): error CS0306: The type 'System.TypedReference' may not be used as a type argument -// a = o.E; -Diagnostic(ErrorCode.ERR_BadTypeArgument, "o.E").WithArguments("System.TypedReference"), -// (16,34): error CS0306: The type 'System.TypedReference' may not be used as a type argument -// Console.WriteLine(typeof(TypedReference?)); -Diagnostic(ErrorCode.ERR_BadTypeArgument, "TypedReference?").WithArguments("System.TypedReference"), -// (17,43): error CS0306: The type 'System.TypedReference' may not be used as a type argument -// Console.WriteLine(typeof(Nullable)); -Diagnostic(ErrorCode.ERR_BadTypeArgument, "TypedReference").WithArguments("System.TypedReference")); + // (7,15): error CS0306: The type 'int*' may not be used as a type argument + // new C(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(7, 15), + // (8,15): error CS0306: The type 'ArgIterator' may not be used as a type argument + // new C(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "ArgIterator").WithArguments("System.ArgIterator").WithLocation(8, 15), + // (9,15): error CS0306: The type 'RuntimeArgumentHandle' may not be used as a type argument + // new C(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "RuntimeArgumentHandle").WithArguments("System.RuntimeArgumentHandle").WithLocation(9, 15), + // (10,15): error CS0306: The type 'TypedReference' may not be used as a type argument + // new C(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "TypedReference").WithArguments("System.TypedReference").WithLocation(10, 15), + // (11,9): error CS0306: The type 'int*' may not be used as a type argument + // F(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "F").WithArguments("int*").WithLocation(11, 9), + // (12,11): error CS0306: The type 'ArgIterator' may not be used as a type argument + // o.E(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "E").WithArguments("System.ArgIterator").WithLocation(12, 11), + // (14,13): error CS0306: The type 'RuntimeArgumentHandle' may not be used as a type argument + // a = F; + Diagnostic(ErrorCode.ERR_BadTypeArgument, "F").WithArguments("System.RuntimeArgumentHandle").WithLocation(14, 13), + // (15,13): error CS0306: The type 'TypedReference' may not be used as a type argument + // a = o.E; + Diagnostic(ErrorCode.ERR_BadTypeArgument, "o.E").WithArguments("System.TypedReference").WithLocation(15, 13), + // (16,34): error CS0306: The type 'TypedReference' may not be used as a type argument + // Console.WriteLine(typeof(TypedReference?)); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "TypedReference?").WithArguments("System.TypedReference").WithLocation(16, 34), + // (17,43): error CS0306: The type 'TypedReference' may not be used as a type argument + // Console.WriteLine(typeof(Nullable)); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "TypedReference").WithArguments("System.TypedReference").WithLocation(17, 43)); } /// @@ -4181,13 +4181,16 @@ static void M() } }"; CreateCompilationWithMscorlib46(source).VerifyDiagnostics( + // (3,7): error CS0306: The type 'ArgIterator' may not be used as a type argument + // using COfArgIterator = C; // unused + Diagnostic(ErrorCode.ERR_BadTypeArgument, "COfArgIterator").WithArguments("System.ArgIterator").WithLocation(3, 7), // (2,7): error CS0306: The type 'int*' may not be used as a type argument + // using COfIntPtr = C; Diagnostic(ErrorCode.ERR_BadTypeArgument, "COfIntPtr").WithArguments("int*").WithLocation(2, 7), - // (3,7): error CS0306: The type 'System.ArgIterator' may not be used as a type argument - Diagnostic(ErrorCode.ERR_BadTypeArgument, "COfArgIterator").WithArguments("System.ArgIterator").WithLocation(3, 7), - // (10,9): error CS0306: The type 'int*' may not be used as a type argument - Diagnostic(ErrorCode.ERR_BadTypeArgument, "COfObject.F").WithArguments("int*").WithLocation(10, 9), - // (3,1): info CS8019: Unnecessary using directive. + // (10,19): error CS0306: The type 'int*' may not be used as a type argument + // COfObject.F(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "F").WithArguments("int*").WithLocation(10, 19), + // (3,1): hidden CS8019: Unnecessary using directive. // using COfArgIterator = C; // unused Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using COfArgIterator = C;").WithLocation(3, 1)); } diff --git a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs index f958e2cbd0674..467ed0172464a 100644 --- a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs +++ b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs @@ -17,6 +17,7 @@ public static class TestOptions public static readonly CSharpParseOptions Regular7_1 = Regular.WithLanguageVersion(LanguageVersion.CSharp7_1); public static readonly CSharpParseOptions Regular7_2 = Regular.WithLanguageVersion(LanguageVersion.CSharp7_2); public static readonly CSharpParseOptions RegularWithDocumentationComments = Regular.WithDocumentationMode(DocumentationMode.Diagnose); + public static readonly CSharpParseOptions WithoutImprovedOverloadCandidates = Regular.WithLanguageVersion(MessageID.IDS_FeatureImprovedOverloadCandidates.RequiredVersion() - 1); private static readonly SmallDictionary s_experimentalFeatures = new SmallDictionary { }; public static readonly CSharpParseOptions ExperimentalParseOptions = From ba2e7126b4a62150fd5e410dc5fef9b8af3e7835 Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Mon, 12 Feb 2018 13:45:24 -0800 Subject: [PATCH 2/5] Implement improved diagnostics for some cases of method group conversion failure Fixes #24675 --- .../Portable/Binder/Binder_Conversions.cs | 12 +- .../Portable/Binder/Binder_Expressions.cs | 24 ++-- .../OverloadResolutionResult.cs | 21 ++-- .../Emit/CodeGen/CodeGenExprLambdaTests.cs | 12 +- .../Emit/CodeGen/CodeGenRefReturnTests.cs | 29 ++--- .../Diagnostics/MethodGroupConversion.cs | 68 +++++++++++ ...rationTests_IDelegateCreationExpression.cs | 39 +++--- .../Test/Semantic/Semantics/BindingTests.cs | 14 +-- .../Semantic/Semantics/SemanticErrorTests.cs | 47 +++----- .../Symbol/Symbols/ExtensionMethodTests.cs | 27 +++-- .../Symbol/Symbols/Source/DelegateTests.cs | 113 +++++++++--------- 11 files changed, 234 insertions(+), 172 deletions(-) create mode 100644 src/Compilers/CSharp/Test/Semantic/Diagnostics/MethodGroupConversion.cs diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 19ccf391d8a84..3237a101afdd8 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -807,8 +807,8 @@ private bool MethodGroupConversionHasErrors( MethodSymbol selectedMethod = conversion.Method; - if (MemberGroupFinalValidation(receiverOpt, selectedMethod, syntax, diagnostics, isExtensionMethod) || - !MethodGroupIsCompatibleWithDelegate(receiverOpt, isExtensionMethod, selectedMethod, delegateType, syntax.Location, diagnostics)) + if (!MethodGroupIsCompatibleWithDelegate(receiverOpt, isExtensionMethod, selectedMethod, delegateType, syntax.Location, diagnostics) || + MemberGroupFinalValidation(receiverOpt, selectedMethod, syntax, diagnostics, isExtensionMethod)) { return true; } @@ -863,8 +863,12 @@ private bool MethodGroupConversionDoesNotExistOrHasErrors( diagnostics.Add(delegateMismatchLocation, useSiteDiagnostics); if (!conversion.Exists) { - // No overload for '{0}' matches delegate '{1}' - diagnostics.Add(ErrorCode.ERR_MethDelegateMismatch, delegateMismatchLocation, boundMethodGroup.Name, delegateType); + if (!Conversions.ReportDelegateMethodGroupDiagnostics(this, boundMethodGroup, delegateType, diagnostics)) + { + // No overload for '{0}' matches delegate '{1}' + diagnostics.Add(ErrorCode.ERR_MethDelegateMismatch, delegateMismatchLocation, boundMethodGroup.Name, delegateType); + } + return true; } else diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index a9357d3249e17..8c0f9cc2ad8c0 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -1953,8 +1953,12 @@ private void GenerateExplicitConversionErrors( { case BoundKind.MethodGroup: { - // TODO: report more specific diagnostics here for failed method group conversions - diagnostics.Add(ErrorCode.ERR_NoExplicitConv, syntax.Location, MessageID.IDS_SK_METHOD.Localize(), targetType); + if (targetType.TypeKind != TypeKind.Delegate || + !MethodGroupConversionDoesNotExistOrHasErrors((BoundMethodGroup)operand, (NamedTypeSymbol)targetType, syntax.Location, diagnostics, out _)) + { + diagnostics.Add(ErrorCode.ERR_NoExplicitConv, syntax.Location, MessageID.IDS_SK_METHOD.Localize(), targetType); + } + return; } case BoundKind.TupleLiteral: @@ -3598,16 +3602,22 @@ private BoundExpression BindDelegateCreationExpression(ObjectCreationExpressionS } methodGroup.PopulateWithSingleMethod(argument, sourceDelegate.DelegateInvokeMethod); - HashSet useSiteDiagnostics = null; Conversion conv = Conversions.MethodGroupConversion(argument.Syntax, methodGroup, type, ref useSiteDiagnostics); diagnostics.Add(node, useSiteDiagnostics); if (!conv.Exists) { - // No overload for '{0}' matches delegate '{1}' - diagnostics.Add(ErrorCode.ERR_MethDelegateMismatch, node.Location, - sourceDelegate.Name, // duplicate questionable Dev10 diagnostic - type); + var boundMethodGroup = new BoundMethodGroup( + argument.Syntax, default, WellKnownMemberNames.DelegateInvokeName, ImmutableArray.Create(sourceDelegate.DelegateInvokeMethod), + sourceDelegate.DelegateInvokeMethod, null, BoundMethodGroupFlags.None, argument, LookupResultKind.Viable); + if (!Conversions.ReportDelegateMethodGroupDiagnostics(this, boundMethodGroup, type, diagnostics)) + { + // If we could not produce a more specialized diagnostic, we report + // No overload for '{0}' matches delegate '{1}' + diagnostics.Add(ErrorCode.ERR_MethDelegateMismatch, node.Location, + sourceDelegate.DelegateInvokeMethod, + type); + } } else { diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs index 19d9a49fe5175..96c4d8e5ceb34 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs @@ -293,7 +293,7 @@ internal void ReportDiagnostics( // Otherwise, f there is any such method that has a bad conversion or out/ref mismatch // then the first such method found is the best bad method. - if (HadBadArguments(diagnostics, binder.Compilation, name, arguments, symbols, location, binder.Flags, isMethodGroupConversion)) + if (HadBadArguments(diagnostics, binder, name, arguments, symbols, location, binder.Flags, isMethodGroupConversion)) { return; } @@ -972,7 +972,7 @@ private static bool HadLambdaConversionError(DiagnosticBag diagnostics, Analyzed private bool HadBadArguments( DiagnosticBag diagnostics, - Compilation compilation, + Binder binder, string name, AnalyzedArguments arguments, ImmutableArray symbols, @@ -1023,15 +1023,15 @@ private bool HadBadArguments( foreach (var arg in badArg.Result.BadArgumentsOpt) { - ReportBadArgumentError(diagnostics, compilation, name, arguments, symbols, location, badArg, method, arg); + ReportBadArgumentError(diagnostics, binder, name, arguments, symbols, location, badArg, method, arg); } return true; } - private static void ReportBadArgumentError( + private void ReportBadArgumentError( DiagnosticBag diagnostics, - Compilation compilation, + Binder binder, string name, AnalyzedArguments arguments, ImmutableArray symbols, @@ -1093,11 +1093,18 @@ private static void ReportBadArgumentError( argument.Kind != BoundKind.OutVariablePendingInference && argument.Kind != BoundKind.DiscardExpression) { + TypeSymbol parameterType = UnwrapIfParamsArray(parameter, isLastParameter) is TypeSymbol t ? t : parameter.Type; + // If the problem is that a lambda isn't convertible to the given type, also report why. // The argument and parameter type might match, but may not have same in/out modifiers if (argument.Kind == BoundKind.UnboundLambda && refArg == refParameter) { - ((UnboundLambda)argument).GenerateAnonymousFunctionConversionError(diagnostics, parameter.Type); + ((UnboundLambda)argument).GenerateAnonymousFunctionConversionError(diagnostics, parameterType); + } + else if (argument.Kind == BoundKind.MethodGroup && parameterType.TypeKind == TypeKind.Delegate && + Conversions.ReportDelegateMethodGroupDiagnostics(binder, (BoundMethodGroup)argument, parameterType, diagnostics)) + { + // a diagnostic has been reported by ReportDelegateMethodGroupDiagnostics } else { @@ -1174,7 +1181,7 @@ private static void ReportBadArgumentError( isParams: false, refKind: refArg); - SymbolDistinguisher distinguisher = new SymbolDistinguisher(compilation, displayArg, UnwrapIfParamsArray(parameter, isLastParameter)); + SymbolDistinguisher distinguisher = new SymbolDistinguisher(binder.Compilation, displayArg, UnwrapIfParamsArray(parameter, isLastParameter)); // CS1503: Argument {0}: cannot convert from '{1}' to '{2}' diagnostics.Add( diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs index 250f664a211a5..9b93f09a20580 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs @@ -4234,19 +4234,19 @@ public static void Run() CreateCompilationWithMscorlibAndSystemCore(source).VerifyDiagnostics( // (9,105): error CS1525: Invalid expression term 'int' // genD = (D) GenericMethod<((System.Linq.Expressions.Expression>)(() => int)).Compile()()> - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int"), + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(9, 105), // (9,123): error CS1525: Invalid expression term '}' // genD = (D) GenericMethod<((System.Linq.Expressions.Expression>)(() => int)).Compile()()> - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("}"), + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("}").WithLocation(9, 123), // (8,9): error CS0246: The type or namespace name 'Goo' could not be found (are you missing a using directive or an assembly reference?) // Goo f = new Goo { - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Goo").WithArguments("Goo"), + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Goo").WithArguments("Goo").WithLocation(8, 9), // (8,21): error CS0246: The type or namespace name 'Goo' could not be found (are you missing a using directive or an assembly reference?) // Goo f = new Goo { - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Goo").WithArguments("Goo"), - // (9,20): error CS0030: Cannot convert type 'method' to 'MemberInitializerTest.D' + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Goo").WithArguments("Goo").WithLocation(8, 21), + // (9,29): error CS0411: The type arguments for method 'MemberInitializerTest.GenericMethod()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // genD = (D) GenericMethod<((System.Linq.Expressions.Expression>)(() => int)).Compile()()> - Diagnostic(ErrorCode.ERR_NoExplicitConv, "(D) GenericMethod").WithArguments("method", "MemberInitializerTest.D")); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "GenericMethod").WithArguments("MemberInitializerTest.GenericMethod()").WithLocation(9, 29)); } [WorkItem(545191, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545191")] diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs index c2d03b4960c36..51df283a33f3b 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs @@ -2792,16 +2792,13 @@ static void Main() // B.F(new D(o.F), 3); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A.F()", "D").WithLocation(26, 24) ); - // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. CreateStandardCompilation(source).VerifyDiagnostics( - // (24,13): error CS1503: Argument 1: cannot convert from 'method group' to 'D' + // (24,13): error CS8189: Ref mismatch between 'A.F()' and delegate 'D' // B.F(o.F, 2); - Diagnostic(ErrorCode.ERR_BadArgType, "o.F").WithArguments("1", "method group", "D").WithLocation(24, 13), - // (26,13): error CS0123: No overload for 'F' matches delegate 'D' + Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A.F()", "D").WithLocation(24, 13), + // (26,24): error CS8189: Ref mismatch between 'A.F()' and delegate 'D' // B.F(new D(o.F), 3); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D(o.F)").WithArguments("F", "D").WithLocation(26, 13) + Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A.F()", "D").WithLocation(26, 24) ); } @@ -2847,16 +2844,13 @@ static void Main() // B.F(new D(o.F), 3); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A.F()", "D").WithLocation(25, 24) ); - // NOTE: we now have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. CreateStandardCompilation(source).VerifyDiagnostics( - // (23,13): error CS1503: Argument 1: cannot convert from 'method group' to 'D' + // (23,13): error CS8189: Ref mismatch between 'A.F()' and delegate 'D' // B.F(o.F, 2); - Diagnostic(ErrorCode.ERR_BadArgType, "o.F").WithArguments("1", "method group", "D").WithLocation(23, 13), - // (25,13): error CS0123: No overload for 'F' matches delegate 'D' + Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A.F()", "D").WithLocation(23, 13), + // (25,24): error CS8189: Ref mismatch between 'A.F()' and delegate 'D' // B.F(new D(o.F), 3); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D(o.F)").WithArguments("F", "D").WithLocation(25, 13) + Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A.F()", "D").WithLocation(25, 24) ); } @@ -3331,16 +3325,13 @@ static void Main() // f = new RefFunc1(M1); Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string").WithLocation(13, 34) ); - // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics( // (10,30): error CS0407: 'string Program.M1()' has the wrong return type // RefFunc1 f = M1; Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string").WithLocation(10, 30), - // (13,13): error CS0123: No overload for 'M1' matches delegate 'Program.RefFunc1' + // (13,34): error CS0407: 'string Program.M1()' has the wrong return type // f = new RefFunc1(M1); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new RefFunc1(M1)").WithArguments("M1", "Program.RefFunc1").WithLocation(13, 13) + Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string").WithLocation(13, 34) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/MethodGroupConversion.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/MethodGroupConversion.cs new file mode 100644 index 0000000000000..e38ebcead3e19 --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/MethodGroupConversion.cs @@ -0,0 +1,68 @@ +// 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.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public class MethodGroupConversion : CSharpTestBase + { + [Fact] + public void TestAmbiguous() + { + var source = @" +partial class Program +{ + static void Main() + { + D d; + d = M; + d = new D(M); + M2(M); + + d = M3; + d = new D(M3); + M2(M3); + } + static void M(I1 i1) {} + static void M(I2 i2) {} + static void M2(D d) {} + + static void M3(int x) {} +} +interface I1 {} +interface I2 {} +class C : I1, I2 {} + +delegate void D(C c); +"; + var compilation = CreateStandardCompilation(source); + compilation.VerifyDiagnostics( + // (7,13): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(I1)' and 'Program.M(I2)' + // d = M; + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(I1)", "Program.M(I2)").WithLocation(7, 13), + // (8,19): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(I1)' and 'Program.M(I2)' + // d = new D(M); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(I1)", "Program.M(I2)").WithLocation(8, 19), + // (9,12): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(I1)' and 'Program.M(I2)' + // M2(M); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(I1)", "Program.M(I2)").WithLocation(9, 12), + // (11,13): error CS0123: No overload for 'M3' matches delegate 'D' + // d = M3; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M3").WithArguments("M3", "D").WithLocation(11, 13), + // (12,13): error CS0123: No overload for 'M3' matches delegate 'D' + // d = new D(M3); + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D(M3)").WithArguments("M3", "D").WithLocation(12, 13), + // (13,12): error CS1503: Argument 1: cannot convert from 'method group' to 'D' + // M2(M3); + Diagnostic(ErrorCode.ERR_BadArgType, "M3").WithArguments("1", "method group", "D").WithLocation(13, 12) + ); + } + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IDelegateCreationExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IDelegateCreationExpression.cs index b3362cea23423..6eeb380b0fb6a 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IDelegateCreationExpression.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IDelegateCreationExpression.cs @@ -777,13 +777,10 @@ void Main() Instance Receiver: ILocalReferenceOperation: p (OperationKind.LocalReference, Type: Program, IsInvalid) (Syntax: 'p') ", new DiagnosticDescription[] { - // CS0407: 'int Program.M1()' has the wrong return type + // file.cs(8,30): error CS0407: 'int Program.M1()' has the wrong return type // Action a = /**/(Action)p.M1/**/; Diagnostic(ErrorCode.ERR_BadRetType, "(Action)p.M1").WithArguments("Program.M1()", "int").WithLocation(8, 30) }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates); - // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. VerifyOperationTreeAndDiagnosticsForTest(source, @" IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Action, IsInvalid) (Syntax: '(Action)p.M1') Target: @@ -791,9 +788,9 @@ void Main() Children(1): ILocalReferenceOperation: p (OperationKind.LocalReference, Type: Program, IsInvalid) (Syntax: 'p') ", new DiagnosticDescription[] { - // file.cs(8,30): error CS0030: Cannot convert type 'method' to 'Action' + // file.cs(8,38): error CS0407: 'int Program.M1()' has the wrong return type // Action a = /**/(Action)p.M1/**/; - Diagnostic(ErrorCode.ERR_NoExplicitConv, "(Action)p.M1").WithArguments("method", "System.Action").WithLocation(8, 30) + Diagnostic(ErrorCode.ERR_BadRetType, "p.M1").WithArguments("Program.M1()", "int").WithLocation(8, 38) }); } @@ -821,9 +818,9 @@ void M1(object o) { } "; var expectedDiagnostics = new DiagnosticDescription[] { - // CS0030: Cannot convert type 'method' to 'Action' + // file.cs(7,30): error CS0123: No overload for 'M1' matches delegate 'Action' // Action a = /**/(Action)M1/**/; - Diagnostic(ErrorCode.ERR_NoExplicitConv, "(Action)M1").WithArguments("method", "System.Action").WithLocation(7, 30) + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "(Action)M1").WithArguments("M1", "System.Action").WithLocation(7, 30) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); @@ -853,9 +850,9 @@ void M1(object o) { } ILocalReferenceOperation: p (OperationKind.LocalReference, Type: Program, IsInvalid) (Syntax: 'p') "; var expectedDiagnostics = new DiagnosticDescription[] { - // CS0030: Cannot convert type 'method' to 'Action' + // file.cs(8,30): error CS0123: No overload for 'M1' matches delegate 'Action' // Action a = /**/(Action)p.M1/**/; - Diagnostic(ErrorCode.ERR_NoExplicitConv, "(Action)p.M1").WithArguments("method", "System.Action").WithLocation(8, 30) + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "(Action)p.M1").WithArguments("M1", "System.Action").WithLocation(8, 30) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); @@ -1074,13 +1071,10 @@ static void M1() Children(1): IInstanceReferenceOperation (OperationKind.InstanceReference, Type: Program, IsInvalid) (Syntax: 'this') "; - // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. var expectedDiagnostics = new DiagnosticDescription[] { - // file.cs(7,30): error CS0123: No overload for 'M1' matches delegate 'Action' + // file.cs(7,41): error CS0176: Member 'Program.M1()' cannot be accessed with an instance reference; qualify it with a type name instead // Action a = /**/new Action(this.M1)/**/; - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Action(this.M1)").WithArguments("M1", "System.Action").WithLocation(7, 30) + Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.M1").WithArguments("Program.M1()").WithLocation(7, 41) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); @@ -1171,9 +1165,6 @@ void Main() // Action a = /**/new Action(M1)/**/; Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "int").WithLocation(7, 41) }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates); - // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. VerifyOperationTreeAndDiagnosticsForTest(source, @" IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Action, IsInvalid) (Syntax: 'new Action(M1)') Target: @@ -1181,9 +1172,9 @@ void Main() Children(1): IInstanceReferenceOperation (OperationKind.InstanceReference, Type: Program, IsInvalid, IsImplicit) (Syntax: 'M1') ", new DiagnosticDescription[] { - // file.cs(7,30): error CS0123: No overload for 'M1' matches delegate 'Action' + // file.cs(7,41): error CS0407: 'int Program.M1()' has the wrong return type // Action a = /**/new Action(M1)/**/; - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Action(M1)").WithArguments("M1", "System.Action").WithLocation(7, 30) + Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "int").WithLocation(7, 41) }); } @@ -1541,9 +1532,9 @@ void M1(int i) { } IInstanceReferenceOperation (OperationKind.InstanceReference, Type: Program, IsInvalid, IsImplicit) (Syntax: 'M1') "; var expectedDiagnostics = new DiagnosticDescription[] { - // CS0030: Cannot convert type 'method' to 'Action' + // file.cs(7,41): error CS0123: No overload for 'M1' matches delegate 'Action' // Action a = /**/new Action((Action)M1)/**/; - Diagnostic(ErrorCode.ERR_NoExplicitConv, "(Action)M1").WithArguments("method", "System.Action").WithLocation(7, 41) + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "(Action)M1").WithArguments("M1", "System.Action").WithLocation(7, 41) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); @@ -1643,9 +1634,9 @@ void M1() { } IInstanceReferenceOperation (OperationKind.InstanceReference, Type: Program, IsInvalid, IsImplicit) (Syntax: 'M1') "; var expectedDiagnostics = new DiagnosticDescription[] { - // CS0123: No overload for 'Action' matches delegate 'Action' + // file.cs(7,35): error CS0123: No overload for 'Action.Invoke()' matches delegate 'Action' // Action a = /**/new Action((Action)M1)/**/; - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Action((Action)M1)").WithArguments("Action", "System.Action").WithLocation(7, 35) + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Action((Action)M1)").WithArguments("System.Action.Invoke()", "System.Action").WithLocation(7, 35) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs index bcff9115cc8b1..bceb8e7ebe9f2 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs @@ -2405,13 +2405,10 @@ void Test() // new D(M)(); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "M").WithArguments("C.M()", "D").WithLocation(15, 15) ); - // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (15,9): error CS0123: No overload for 'M' matches delegate 'D' + // (15,15): error CS8189: Ref mismatch between 'C.M()' and delegate 'D' // new D(M)(); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D(M)").WithArguments("M", "D").WithLocation(15, 9) + Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "M").WithArguments("C.M()", "D").WithLocation(15, 15) ); } @@ -2475,13 +2472,10 @@ void Test() // M(M); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "M").WithArguments("C.M()", "D").WithLocation(19, 11) ); - // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (19,11): error CS1503: Argument 1: cannot convert from 'method group' to 'D' + // (19,11): error CS8189: Ref mismatch between 'C.M()' and delegate 'D' // M(M); - Diagnostic(ErrorCode.ERR_BadArgType, "M").WithArguments("1", "method group", "D").WithLocation(19, 11) + Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "M").WithArguments("C.M()", "D").WithLocation(19, 11) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs index 28c654f357d59..5b3c115e9529e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs @@ -2744,13 +2744,10 @@ static void Main(string[] args) // abc p = new abc(); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "p").WithArguments("p") ); - // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. CreateStandardCompilation(source, parseOptions: TestOptions.Regular).VerifyDiagnostics( - // (16,16): error CS0123: No overload for 'bar' matches delegate 'boo' + // (16,24): error CS0120: An object reference is required for the non-static field, method, or property 'I.bar()' // goo += new boo(I.bar); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new boo(I.bar)").WithArguments("bar", "boo").WithLocation(16, 16), + Diagnostic(ErrorCode.ERR_ObjectRequired, "I.bar").WithArguments("I.bar()").WithLocation(16, 24), // (14,13): warning CS0219: The variable 'p' is assigned but its value is never used // abc p = new abc(); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "p").WithArguments("p").WithLocation(14, 13) @@ -10180,13 +10177,10 @@ public static void Main() // d = new MyDelegate(G); // CS0407 - G doesn't return int Diagnostic(ErrorCode.ERR_BadRetType, "G").WithArguments("C.G()", "void").WithLocation(11, 28) ); - // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. CreateStandardCompilation(text).VerifyDiagnostics( - // (11,13): error CS0123: No overload for 'G' matches delegate 'MyDelegate' + // (11,28): error CS0407: 'void C.G()' has the wrong return type // d = new MyDelegate(G); // CS0407 - G doesn't return int - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new MyDelegate(G)").WithArguments("G", "MyDelegate").WithLocation(11, 13) + Diagnostic(ErrorCode.ERR_BadRetType, "G").WithArguments("C.G()", "void").WithLocation(11, 28) ); } @@ -10216,16 +10210,13 @@ public static void Main() // var ss = new Func(oo); Diagnostic(ErrorCode.ERR_BadRetType, "oo").WithArguments("System.Func.Invoke(object)", "object").WithLocation(11, 43) ); - // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. CreateStandardCompilation(text).VerifyDiagnostics( - // (10,18): error CS0123: No overload for 'Func' matches delegate 'Func' + // (10,43): error CS0407: 'object Func.Invoke(object)' has the wrong return type // var os = new Func(oo); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Func(oo)").WithArguments("Func", "System.Func").WithLocation(10, 18), - // (11,18): error CS0123: No overload for 'Func' matches delegate 'Func' + Diagnostic(ErrorCode.ERR_BadRetType, "oo").WithArguments("System.Func.Invoke(object)", "object").WithLocation(10, 43), + // (11,43): error CS0407: 'object Func.Invoke(object)' has the wrong return type // var ss = new Func(oo); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Func(oo)").WithArguments("Func", "System.Func").WithLocation(11, 18) + Diagnostic(ErrorCode.ERR_BadRetType, "oo").WithArguments("System.Func.Invoke(object)", "object").WithLocation(11, 43) ); } @@ -22137,25 +22128,25 @@ static void F(Program p) comp.VerifyDiagnostics( // (28,25): error CS0149: Method name expected // d1 = new D1(2 + 2); - Diagnostic(ErrorCode.ERR_MethodNameExpected, "2 + 2"), - // (29,18): error CS0123: No overload for 'D3' matches delegate 'CSSample.Program.D1' + Diagnostic(ErrorCode.ERR_MethodNameExpected, "2 + 2").WithLocation(28, 25), + // (29,18): error CS0123: No overload for 'Program.D3.Invoke(int)' matches delegate 'Program.D1' // d1 = new D1(d3); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D1(d3)").WithArguments("D3", "CSSample.Program.D1"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D1(d3)").WithArguments("CSSample.Program.D3.Invoke(int)", "CSSample.Program.D1").WithLocation(29, 18), // (30,25): error CS0149: Method name expected // d1 = new D1(2, 3); - Diagnostic(ErrorCode.ERR_MethodNameExpected, "2, 3"), + Diagnostic(ErrorCode.ERR_MethodNameExpected, "2, 3").WithLocation(30, 25), // (31,28): error CS0149: Method name expected // d1 = new D1(x: 3); - Diagnostic(ErrorCode.ERR_MethodNameExpected, "3"), - // (32,18): error CS0123: No overload for 'M2' matches delegate 'CSSample.Program.D1' + Diagnostic(ErrorCode.ERR_MethodNameExpected, "3").WithLocation(31, 28), + // (32,18): error CS0123: No overload for 'M2' matches delegate 'Program.D1' // d1 = new D1(M2); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D1(M2)").WithArguments("M2", "CSSample.Program.D1"), - // (16,19): warning CS0169: The field 'CSSample.Program.d2' is never used + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D1(M2)").WithArguments("M2", "CSSample.Program.D1").WithLocation(32, 18), + // (16,19): warning CS0169: The field 'Program.d2' is never used // static D2 d2; - Diagnostic(ErrorCode.WRN_UnreferencedField, "d2").WithArguments("CSSample.Program.d2"), - // (17,19): warning CS0649: Field 'CSSample.Program.d3' is never assigned to, and will always have its default value null + Diagnostic(ErrorCode.WRN_UnreferencedField, "d2").WithArguments("CSSample.Program.d2").WithLocation(16, 19), + // (17,19): warning CS0649: Field 'Program.d3' is never assigned to, and will always have its default value null // static D3 d3; - Diagnostic(ErrorCode.WRN_UnassignedInternalField, "d3").WithArguments("CSSample.Program.d3", "null")); + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "d3").WithArguments("CSSample.Program.d3", "null").WithLocation(17, 19)); } [Fact, WorkItem(7359, "https://github.com/dotnet/roslyn/issues/7359")] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs index 16b2213adf4e1..8aef3b543e70d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs @@ -1003,15 +1003,26 @@ static class S3 CreateStandardCompilation(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (10,16): error CS0407: 'void S2.F1(object, object)' has the wrong return type + // M1(c.F1); // wrong return type Diagnostic(ErrorCode.ERR_BadRetType, "c.F1").WithArguments("S2.F1(object, object)", "void").WithLocation(10, 16), - // (13,16): error CS0407: 'object S2.F2(N.C, object)' has the wrong return type + // (13,16): error CS0407: 'object S2.F2(C, object)' has the wrong return type + // M2(c.F2); // wrong return type Diagnostic(ErrorCode.ERR_BadRetType, "c.F2").WithArguments("S2.F2(N.C, object)", "object").WithLocation(13, 16), - // (14,16): error CS1503: Argument 1: cannot convert from 'method group' to 'System.Func' + // (14,16): error CS0121: The call is ambiguous between the following methods or properties: 'S2.F3(C, object)' and 'S3.F3(C, object)' // M1(c.F3); // ambiguous - Diagnostic(ErrorCode.ERR_BadArgType, "c.F3").WithArguments("1", "method group", "System.Func")); - // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this failure case - // because we don't report *why* a delegate conversion failed. - // See https://github.com/dotnet/roslyn/issues/24675 for a proposal to restore the quality of this diagnostic. + Diagnostic(ErrorCode.ERR_AmbigCall, "c.F3").WithArguments("S2.F3(N.C, object)", "S3.F3(N.C, object)").WithLocation(14, 16)); + // NOTE: we have a degradation in the quality of diagnostics for a delegate conversion in this particular failure case. + // See https://github.com/dotnet/roslyn/issues/24787 + // It is caused by a combination of two shortcomings in the computation of diagnostics. First, in `BindExtensionMethod` + // when we fail to find an applicable extension method, we only report a diagnostic for the first extension method group + // that failed, even if some other extension method group contains a much better candidate. In the case of this test the first + // extension method group contains a method with the wrong number of parameters, while the second one has an extension method + // that fails only because of its return type mismatch. Second, in + // `OverloadResolutionResult.ReportDiagnostics`, we do not report a diagnostic for the failure + // `MemberResolutionKind.NoCorrespondingParameter`, leaving it to the caller to notice that we failed to produce a + // diagnostic (the caller has to grub through the diagnostic bag to see that there is no error there) and then the caller + // has to produce a generic error message, which we see below. It does not appear that all callers have that test, though, + // suggesting there may be a latent bug of missing diagnostics. CreateStandardCompilation(source, references: new[] { SystemCoreRef }).VerifyDiagnostics( // (10,16): error CS1503: Argument 1: cannot convert from 'method group' to 'Func' // M1(c.F1); // wrong return type @@ -1019,9 +1030,9 @@ static class S3 // (13,16): error CS1503: Argument 1: cannot convert from 'method group' to 'Action' // M2(c.F2); // wrong return type Diagnostic(ErrorCode.ERR_BadArgType, "c.F2").WithArguments("1", "method group", "System.Action").WithLocation(13, 16), - // (14,16): error CS1503: Argument 1: cannot convert from 'method group' to 'Func' + // (14,16): error CS0121: The call is ambiguous between the following methods or properties: 'S2.F3(C, object)' and 'S3.F3(C, object)' // M1(c.F3); // ambiguous - Diagnostic(ErrorCode.ERR_BadArgType, "c.F3").WithArguments("1", "method group", "System.Func").WithLocation(14, 16)); + Diagnostic(ErrorCode.ERR_AmbigCall, "c.F3").WithArguments("S2.F3(N.C, object)", "S3.F3(N.C, object)").WithLocation(14, 16)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs index 230474843d5a4..4036cbe43819d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs @@ -589,95 +589,90 @@ public static void RunG(T t) { } } "; CreateStandardCompilation(text).VerifyDiagnostics( - // These match Dev10. - // (44,14): error CS0123: No overload for 'FTT' matches delegate 'DelegateTest.Da' // da = new Da(FTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Da(FTT)").WithArguments("FTT", "DelegateTest.Da"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Da(FTT)").WithArguments("FTT", "DelegateTest.Da").WithLocation(44, 14), + // (45,21): error CS0411: The type arguments for method 'DelegateTest.FCT(C)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // da = new Da(FCT); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "FCT").WithArguments("DelegateTest.FCT(C)").WithLocation(45, 21), + // (46,21): error CS0411: The type arguments for method 'DelegateTest.PT(params T[])' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // da = new Da(PT); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "PT").WithArguments("DelegateTest.PT(params T[])").WithLocation(46, 21), // (48,15): error CS0123: No overload for 'FT' matches delegate 'DelegateTest.Daa' // daa = new Daa(FT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Daa(FT)").WithArguments("FT", "DelegateTest.Daa"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Daa(FT)").WithArguments("FT", "DelegateTest.Daa").WithLocation(48, 15), // (49,15): error CS0123: No overload for 'FTi' matches delegate 'DelegateTest.Daa' // daa = new Daa(FTi); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Daa(FTi)").WithArguments("FTi", "DelegateTest.Daa"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Daa(FTi)").WithArguments("FTi", "DelegateTest.Daa").WithLocation(49, 15), // (50,15): error CS0123: No overload for 'PTT' matches delegate 'DelegateTest.Daa' // daa = new Daa(PTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Daa(PTT)").WithArguments("PTT", "DelegateTest.Daa"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Daa(PTT)").WithArguments("PTT", "DelegateTest.Daa").WithLocation(50, 15), + // (51,23): error CS0411: The type arguments for method 'DelegateTest.PST(S, params T[])' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // daa = new Daa(PST); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "PST").WithArguments("DelegateTest.PST(S, params T[])").WithLocation(51, 23), // (53,15): error CS0123: No overload for 'FT' matches delegate 'DelegateTest.Dai' // dai = new Dai(FT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dai(FT)").WithArguments("FT", "DelegateTest.Dai"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dai(FT)").WithArguments("FT", "DelegateTest.Dai").WithLocation(53, 15), + // (54,23): error CS0411: The type arguments for method 'DelegateTest.FTT(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // dai = new Dai(FTT); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "FTT").WithArguments("DelegateTest.FTT(T, T)").WithLocation(54, 23), // (55,15): error CS0123: No overload for 'PTT' matches delegate 'DelegateTest.Dai' // dai = new Dai(PTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dai(PTT)").WithArguments("PTT", "DelegateTest.Dai"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dai(PTT)").WithArguments("PTT", "DelegateTest.Dai").WithLocation(55, 15), + // (56,23): error CS0411: The type arguments for method 'DelegateTest.PST(S, params T[])' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // dai = new Dai(PST); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "PST").WithArguments("DelegateTest.PST(S, params T[])").WithLocation(56, 23), // (58,15): error CS0123: No overload for 'FT' matches delegate 'DelegateTest.Dab' // dab = new Dab(FT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dab(FT)").WithArguments("FT", "DelegateTest.Dab"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dab(FT)").WithArguments("FT", "DelegateTest.Dab").WithLocation(58, 15), + // (59,23): error CS0411: The type arguments for method 'DelegateTest.FTT(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // dab = new Dab(FTT); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "FTT").WithArguments("DelegateTest.FTT(T, T)").WithLocation(59, 23), // (60,15): error CS0123: No overload for 'FTi' matches delegate 'DelegateTest.Dab' // dab = new Dab(FTi); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dab(FTi)").WithArguments("FTi", "DelegateTest.Dab"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dab(FTi)").WithArguments("FTi", "DelegateTest.Dab").WithLocation(60, 15), // (61,15): error CS0123: No overload for 'PTT' matches delegate 'DelegateTest.Dab' // dab = new Dab(PTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dab(PTT)").WithArguments("PTT", "DelegateTest.Dab"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dab(PTT)").WithArguments("PTT", "DelegateTest.Dab").WithLocation(61, 15), + // (62,23): error CS0411: The type arguments for method 'DelegateTest.PST(S, params T[])' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // dab = new Dab(PST); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "PST").WithArguments("DelegateTest.PST(S, params T[])").WithLocation(62, 23), // (64,15): error CS0123: No overload for 'FTT' matches delegate 'DelegateTest.Dpa' // dpa = new Dpa(FTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dpa(FTT)").WithArguments("FTT", "DelegateTest.Dpa"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dpa(FTT)").WithArguments("FTT", "DelegateTest.Dpa").WithLocation(64, 15), + // (65,23): error CS0411: The type arguments for method 'DelegateTest.FCT(C)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // dpa = new Dpa(FCT); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "FCT").WithArguments("DelegateTest.FCT(C)").WithLocation(65, 23), // (67,16): error CS0123: No overload for 'FT' matches delegate 'DelegateTest.Dapa' // dapa = new Dapa(FT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dapa(FT)").WithArguments("FT", "DelegateTest.Dapa"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dapa(FT)").WithArguments("FT", "DelegateTest.Dapa").WithLocation(67, 16), + // (68,25): error CS0411: The type arguments for method 'DelegateTest.FTT(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // dapa = new Dapa(FTT); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "FTT").WithArguments("DelegateTest.FTT(T, T)").WithLocation(68, 25), // (70,16): error CS0123: No overload for 'FT' matches delegate 'DelegateTest.Dapb' // dapb = new Dapb(FT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dapb(FT)").WithArguments("FT", "DelegateTest.Dapb"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dapb(FT)").WithArguments("FT", "DelegateTest.Dapb").WithLocation(70, 16), + // (71,25): error CS0411: The type arguments for method 'DelegateTest.FTT(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // dapb = new Dapb(FTT); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "FTT").WithArguments("DelegateTest.FTT(T, T)").WithLocation(71, 25), + // (72,25): error CS0411: The type arguments for method 'DelegateTest.PTT(T, params T[])' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // dapb = new Dapb(PTT); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "PTT").WithArguments("DelegateTest.PTT(T, params T[])").WithLocation(72, 25), // (74,17): error CS0123: No overload for 'FT' matches delegate 'DelegateTest.Dpapa' // dpapa = new Dpapa(FT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dpapa(FT)").WithArguments("FT", "DelegateTest.Dpapa"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dpapa(FT)").WithArguments("FT", "DelegateTest.Dpapa").WithLocation(74, 17), + // (75,27): error CS0411: The type arguments for method 'DelegateTest.PTT(T, params T[])' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // dpapa = new Dpapa(PTT); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "PTT").WithArguments("DelegateTest.PTT(T, params T[])").WithLocation(75, 27), // (77,15): error CS0123: No overload for 'FTT' matches delegate 'DelegateTest.Dca' // dca = new Dca(FTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dca(FTT)").WithArguments("FTT", "DelegateTest.Dca"), + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dca(FTT)").WithArguments("FTT", "DelegateTest.Dca").WithLocation(77, 15), + // (78,23): error CS0411: The type arguments for method 'DelegateTest.PT(params T[])' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // dca = new Dca(PT); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "PT").WithArguments("DelegateTest.PT(params T[])").WithLocation(78, 23), // (80,9): error CS0411: The type arguments for method 'DelegateTest.RunG(T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // RunG(null); - Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "RunG").WithArguments("DelegateTest.RunG(T)"), - - // Dev10 reports CS0411 (ERR_CantInferMethTypeArgs) for these. - - // (45,14): error CS0123: No overload for 'FCT' matches delegate 'DelegateTest.Da' - // da = new Da(FCT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Da(FCT)").WithArguments("FCT", "DelegateTest.Da"), - // (46,14): error CS0123: No overload for 'PT' matches delegate 'DelegateTest.Da' - // da = new Da(PT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Da(PT)").WithArguments("PT", "DelegateTest.Da"), - // (51,15): error CS0123: No overload for 'PST' matches delegate 'DelegateTest.Daa' - // daa = new Daa(PST); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Daa(PST)").WithArguments("PST", "DelegateTest.Daa"), - // (54,15): error CS0123: No overload for 'FTT' matches delegate 'DelegateTest.Dai' - // dai = new Dai(FTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dai(FTT)").WithArguments("FTT", "DelegateTest.Dai"), - // (56,15): error CS0123: No overload for 'PST' matches delegate 'DelegateTest.Dai' - // dai = new Dai(PST); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dai(PST)").WithArguments("PST", "DelegateTest.Dai"), - // (59,15): error CS0123: No overload for 'FTT' matches delegate 'DelegateTest.Dab' - // dab = new Dab(FTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dab(FTT)").WithArguments("FTT", "DelegateTest.Dab"), - // (62,15): error CS0123: No overload for 'PST' matches delegate 'DelegateTest.Dab' - // dab = new Dab(PST); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dab(PST)").WithArguments("PST", "DelegateTest.Dab"), - // (65,15): error CS0123: No overload for 'FCT' matches delegate 'DelegateTest.Dpa' - // dpa = new Dpa(FCT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dpa(FCT)").WithArguments("FCT", "DelegateTest.Dpa"), - // (68,16): error CS0123: No overload for 'FTT' matches delegate 'DelegateTest.Dapa' - // dapa = new Dapa(FTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dapa(FTT)").WithArguments("FTT", "DelegateTest.Dapa"), - // (71,16): error CS0123: No overload for 'FTT' matches delegate 'DelegateTest.Dapb' - // dapb = new Dapb(FTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dapb(FTT)").WithArguments("FTT", "DelegateTest.Dapb"), - // (72,16): error CS0123: No overload for 'PTT' matches delegate 'DelegateTest.Dapb' - // dapb = new Dapb(PTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dapb(PTT)").WithArguments("PTT", "DelegateTest.Dapb"), - // (75,17): error CS0123: No overload for 'PTT' matches delegate 'DelegateTest.Dpapa' - // dpapa = new Dpapa(PTT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dpapa(PTT)").WithArguments("PTT", "DelegateTest.Dpapa"), - // (78,15): error CS0123: No overload for 'PT' matches delegate 'DelegateTest.Dca' - // dca = new Dca(PT); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new Dca(PT)").WithArguments("PT", "DelegateTest.Dca")); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "RunG").WithArguments("DelegateTest.RunG(T)").WithLocation(80, 9)); } [Fact] From 184f14d94159e08f163b3b3c4236263e3f146e84 Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Mon, 12 Feb 2018 14:34:53 -0800 Subject: [PATCH 3/5] Small changes per code review. --- .../Portable/Binder/Binder_Expressions.cs | 19 +++++++++++++------ .../MemberAnalysisResult.cs | 13 ++++--------- .../OverloadResolution/OverloadResolution.cs | 14 ++++++++------ .../OverloadResolutionResult.cs | 2 +- .../Semantics/OverloadResolutionTests.cs | 1 + 5 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 8c0f9cc2ad8c0..4e62a54b2914f 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -4871,9 +4871,9 @@ private bool TryPerformConstructorOverloadResolution( else { result.ReportDiagnostics( - binder: this, location: errorLocation, nodeOpt: null, diagnostics: diagnostics, - name: errorName, receiver: null, invokedExpression: null, arguments: analyzedArguments, - memberGroup: candidateConstructors, typeContainingConstructor: typeContainingConstructors, delegateTypeBeingInvoked: null); + binder: this, location: errorLocation, nodeOpt: null, diagnostics, + name: errorName, receiver: null, invokedExpression: null, analyzedArguments, + memberGroup: candidateConstructors, typeContainingConstructors, delegateTypeBeingInvoked: null); } } @@ -5836,9 +5836,8 @@ private MethodGroupResolution BindExtensionMethod( BoundExpression left, ImmutableArray typeArguments, bool isMethodGroupConversion, - RefKind returnRefKind = default, - TypeSymbol returnType = null -) + RefKind returnRefKind, + TypeSymbol returnType) { var firstResult = new MethodGroupResolution(); AnalyzedArguments actualArguments = null; @@ -6888,6 +6887,14 @@ private ErrorPropertySymbol CreateErrorPropertySymbol(ImmutableArray + /// The node associated with the method group + /// The arguments of the invocation (or the delegate type, if a method group conversion) + /// True if it is a method group conversion + /// + /// + /// If a method group conversion, the desired ref kind of the delegate + /// If a method group conversion, the desired return type of the delegate. + /// May be null during inference if the return type of the delegate needs to be computed. internal MethodGroupResolution ResolveMethodGroup( BoundMethodGroup node, AnalyzedArguments analyzedArguments, diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs index c1992fed26e64..d1088d325d6e5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs @@ -17,7 +17,7 @@ internal struct MemberAnalysisResult public readonly ImmutableArray ConversionsOpt; public readonly ImmutableArray BadArgumentsOpt; public readonly ImmutableArray ArgsToParamsOpt; - public readonly ArrayBuilder ConstraintFailureDiagnosticsOpt; + public readonly ImmutableArray ConstraintFailureDiagnosticsOpt; public readonly int BadParameter; public readonly MemberResolutionKind Kind; @@ -28,11 +28,6 @@ internal struct MemberAnalysisResult /// public readonly bool HasAnyRefOmittedArgument; - private MemberAnalysisResult(MemberResolutionKind kind) - : this(kind, constraintFailureDiagnosticsOpt: default) - { - } - private MemberAnalysisResult( MemberResolutionKind kind, ImmutableArray badArgumentsOpt = default, @@ -40,7 +35,7 @@ private MemberAnalysisResult( ImmutableArray conversionsOpt = default, int missingParameter = -1, bool hasAnyRefOmittedArgument = false, - ArrayBuilder constraintFailureDiagnosticsOpt = null) + ImmutableArray constraintFailureDiagnosticsOpt = default) { this.Kind = kind; this.BadArgumentsOpt = badArgumentsOpt; @@ -48,7 +43,7 @@ private MemberAnalysisResult( this.ConversionsOpt = conversionsOpt; this.BadParameter = missingParameter; this.HasAnyRefOmittedArgument = hasAnyRefOmittedArgument; - this.ConstraintFailureDiagnosticsOpt = constraintFailureDiagnosticsOpt; + this.ConstraintFailureDiagnosticsOpt = constraintFailureDiagnosticsOpt.NullToEmpty(); } public override bool Equals(object obj) @@ -284,7 +279,7 @@ public static MemberAnalysisResult Worst() return new MemberAnalysisResult(MemberResolutionKind.Worst); } - internal static MemberAnalysisResult ConstraintFailure(ArrayBuilder constraintFailureDiagnostics) + internal static MemberAnalysisResult ConstraintFailure(ImmutableArray constraintFailureDiagnostics) { return new MemberAnalysisResult(MemberResolutionKind.ConstraintFailure, constraintFailureDiagnosticsOpt: constraintFailureDiagnostics); } diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs index c0d498145b709..063646076be75 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs @@ -365,7 +365,8 @@ private void RemoveConstraintViolations(ArrayBuilder constraintFailureDiagnosticsOpt)) { results[f] = new MemberResolutionResult( - result.Member, result.LeastOverriddenMember, MemberAnalysisResult.ConstraintFailure(constraintFailureDiagnosticsOpt)); + result.Member, result.LeastOverriddenMember, + MemberAnalysisResult.ConstraintFailure(constraintFailureDiagnosticsOpt.ToImmutableAndFree())); } } } @@ -379,8 +380,8 @@ private bool FailsConstraintChecks(MethodSymbol method, out ArrayBuilder.GetInstance(); - ArrayBuilder useSiteDiagnosticsBuilder = null; - var constraintsSatisfied = ConstraintsHelper.CheckMethodConstraints( + ArrayBuilder useSiteDiagnosticsBuilder = null; + bool constraintsSatisfied = ConstraintsHelper.CheckMethodConstraints( method, this.Conversions, this.Compilation, @@ -433,9 +434,10 @@ private void RemoveDelegateConversionsWithWrongReturnType( } var method = (MethodSymbol)(Symbol)result.Member; - bool returnsMatch = returnType == null || - method.ReturnType.Equals(returnType, TypeCompareKind.AllIgnoreOptions) || - returnRefKind == RefKind.None && Conversions.HasIdentityOrImplicitReferenceConversion(method.ReturnType, returnType, ref useSiteDiagnostics); + bool returnsMatch = + (object)returnType == null || + method.ReturnType.Equals(returnType, TypeCompareKind.AllIgnoreOptions) || + returnRefKind == RefKind.None && Conversions.HasIdentityOrImplicitReferenceConversion(method.ReturnType, returnType, ref useSiteDiagnostics); if (!returnsMatch) { results[f] = new MemberResolutionResult( diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs index 96c4d8e5ceb34..44fc87a031549 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs @@ -290,7 +290,7 @@ internal void ReportDiagnostics( return; } - // Otherwise, f there is any such method that has a bad conversion or out/ref mismatch + // Otherwise, if there is any such method that has a bad argument conversion or out/ref mismatch // then the first such method found is the best bad method. if (HadBadArguments(diagnostics, binder, name, arguments, symbols, location, binder.Flags, isMethodGroupConversion)) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs index a891119f0630e..38a89607e69af 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs @@ -1390,6 +1390,7 @@ static void Test6(N nz) where Z : struct {} // (58,9): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'S' in the generic type or method 'C.L' // Test6>(null); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "Test6>").WithArguments("C.L", "S", "string").WithLocation(58, 9)); + CreateStandardCompilation(source).VerifyDiagnostics( // (67,36): error CS0453: The type 'Y' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'C.N' // static void Test5(Y y, N ny) { } From 597fd0c094741f7ee819f410c2686f2257bf1012 Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Mon, 12 Feb 2018 16:05:23 -0800 Subject: [PATCH 4/5] Rename ConstraintFailureDiagnosticsOpt to ConstraintFailureDiagnostics --- .../Semantics/OverloadResolution/MemberAnalysisResult.cs | 4 ++-- .../Semantics/OverloadResolution/OverloadResolutionResult.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs index d1088d325d6e5..ae3a9d22c7159 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberAnalysisResult.cs @@ -17,7 +17,7 @@ internal struct MemberAnalysisResult public readonly ImmutableArray ConversionsOpt; public readonly ImmutableArray BadArgumentsOpt; public readonly ImmutableArray ArgsToParamsOpt; - public readonly ImmutableArray ConstraintFailureDiagnosticsOpt; + public readonly ImmutableArray ConstraintFailureDiagnostics; public readonly int BadParameter; public readonly MemberResolutionKind Kind; @@ -43,7 +43,7 @@ private MemberAnalysisResult( this.ConversionsOpt = conversionsOpt; this.BadParameter = missingParameter; this.HasAnyRefOmittedArgument = hasAnyRefOmittedArgument; - this.ConstraintFailureDiagnosticsOpt = constraintFailureDiagnosticsOpt.NullToEmpty(); + this.ConstraintFailureDiagnostics = constraintFailureDiagnosticsOpt.NullToEmpty(); } public override bool Equals(object obj) diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs index 44fc87a031549..d9c4206728077 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs @@ -638,7 +638,7 @@ private bool HadConstraintFailure(Location location, DiagnosticBag diagnostics) return false; } - foreach (var pair in constraintFailure.Result.ConstraintFailureDiagnosticsOpt) + foreach (var pair in constraintFailure.Result.ConstraintFailureDiagnostics) { diagnostics.Add(new CSDiagnostic(pair.DiagnosticInfo, location)); } From fa261b6dddca49250b08d018d3a1e064e79ee934 Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Fri, 16 Feb 2018 13:10:08 -0800 Subject: [PATCH 5/5] Add tests suggested by @VSadov. --- .../Semantic/Semantics/BetterCandidates.cs | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs index 3c5d7ac585b57..5b6b29821c6ad 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs @@ -429,5 +429,93 @@ public class ExtensionAttribute : System.Attribute {} ); CompileAndVerify(compilation, expectedOutput: "2"); } + + // Test suggested by @VSadov + // 1) one candidate is generic, but candidate fails constraints, while another overload requires a conversion. Used to be an error, second should be picked now. + [Fact] + public void TestConstraintFailed03() + { + var source = +@"public class Program +{ + static void Main() + { + M(new A(), 0); + } + + static void M(T t1, int i) where T: B { System.Console.WriteLine(1); } + static void M(C c, short s) { System.Console.WriteLine(2); } +} +public class A {} +public class B {} +public class C { public static implicit operator C(A a) => null; } +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (5,9): error CS0311: The type 'A' cannot be used as type parameter 'T' in the generic type or method 'Program.M(T, int)'. There is no implicit reference conversion from 'A' to 'B'. + // M(new A(), 0); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("Program.M(T, int)", "B", "T", "A").WithLocation(5, 9) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + ); + CompileAndVerify(compilation, expectedOutput: "2"); + } + + // Test suggested by @VSadov + // 2) one candidate is generic without constraints, but we pass a ref-struct to it, which cannot be a generic type arg, another candidate requires a conversion and now works. + [Fact] + public void TestConstraintFailed04() + { + var source = +@"public class Program +{ + static void Main() + { + M(new A(), 0); + } + + static void M(T t1, int i) { System.Console.WriteLine(1); } + static void M(C c, short s) { System.Console.WriteLine(2); } +} +public ref struct A {} +public class C { public static implicit operator C(A a) => null; } +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + // (5,9): error CS0306: The type 'A' may not be used as a type argument + // M(new A(), 0); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "M").WithArguments("A").WithLocation(5, 9) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + ); + CompileAndVerify(compilation, expectedOutput: "2"); + } + + // Test suggested by @VSadov + // 3) one candidate is generic without constraints, but we pass a pointer to it, which cannot be a generic type arg, another candidate requires a conversion and now works. + [Fact] + public void TestConstraintFailed05() + { + var source = +@"public class Program +{ + static unsafe void Main() + { + int *p = null; + M(p, 0); + } + + static void M(T t1, int i) { System.Console.WriteLine(1); } + static void M(C c, short s) { System.Console.WriteLine(2); } +} +public class C { public static unsafe implicit operator C(int* p) => null; } +"; + CreateCompilationWithoutBetterCandidates(source, options: TestOptions.ReleaseExe.WithAllowUnsafe(true)).VerifyDiagnostics( + // (6,9): error CS0306: The type 'int*' may not be used as a type argument + // M(p, 0); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "M").WithArguments("int*").WithLocation(6, 9) + ); + var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe.WithAllowUnsafe(true)).VerifyDiagnostics( + ); + CompileAndVerify(compilation, expectedOutput: "2", verify: Verification.Skipped); + } } }