diff --git a/src/Compilers/CSharp/Portable/Binder/LookupResult.cs b/src/Compilers/CSharp/Portable/Binder/LookupResult.cs index 6c09a44d86d9..18152c3e6013 100644 --- a/src/Compilers/CSharp/Portable/Binder/LookupResult.cs +++ b/src/Compilers/CSharp/Portable/Binder/LookupResult.cs @@ -286,11 +286,32 @@ internal void MergeEqual(SingleLookupResult result) { this.SetFrom(result); } + else if (Kind == LookupResultKind.WrongArity && result.Kind == LookupResultKind.WrongArity) + { + // When both results are WrongArity, prefer the generic type over the non-generic one + // if the user supplied type arguments + if (PreferGenericOverNonGeneric(this.SingleSymbolOrDefault, result.Symbol)) + { + this.SetFrom(result); + } + else if (!PreferGenericOverNonGeneric(result.Symbol, this.SingleSymbolOrDefault)) + { + // Neither is preferred, add both symbols + if ((object)result.Symbol != null) + { + _symbolList.Add(result.Symbol); + } + } + // else: existing result is preferred (generic over non-generic), keep it + } else if ((object)result.Symbol != null) { // Same goodness. Include all symbols _symbolList.Add(result.Symbol); } + + static bool PreferGenericOverNonGeneric(Symbol currentSymbol, Symbol newSymbol) + => currentSymbol is NamedTypeSymbol { Arity: 0 } && newSymbol is NamedTypeSymbol { Arity: > 0 }; } // global pool diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs index 03e82bb806db..4085b8cb6283 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs @@ -1833,9 +1833,9 @@ class C // (20,27): error CS0305: Using the generic type 'N.A' requires '1' type arguments // Diagnostic(ErrorCode.ERR_BadArity, "A").WithArguments("N.A", "type", "1"), - // (21,34): error CS0308: The non-generic type 'N.B' cannot be used with type arguments + // (21,34): error CS0305: Using the generic type 'N.B' requires '2' type arguments // - Diagnostic(ErrorCode.ERR_HasNoTypeVars, "B").WithArguments("N.B", "type") + Diagnostic(ErrorCode.ERR_BadArity, "B").WithArguments("N.B", "type", "2") ); } @@ -4080,5 +4080,126 @@ static void M(bool a, object b) VerifyOperationTree(comp, model.GetOperation(ifStmt), operationString); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24406")] + public void TestGenericAndNonGenericType() + { + var text = """ + class MyExpression { } + class MyExpression { } + + class Test + { + void M() + { + MyExpression x; + } + } + """; + + CreateCompilation(text).VerifyDiagnostics( + // (8,9): error CS0305: Using the generic type 'MyExpression' requires 1 type arguments + // MyExpression x; + Diagnostic(ErrorCode.ERR_BadArity, "MyExpression").WithArguments("MyExpression", "type", "1").WithLocation(8, 9), + // (8,35): warning CS0168: The variable 'x' is declared but never used + // MyExpression x; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(8, 35)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24406")] + public void TestGenericAndNonGenericType_SingleTypeArgument() + { + var text = """ + class MyExpression { } + class MyExpression { } + + class Test + { + void M() + { + MyExpression x = null; + } + } + """; + + CreateCompilation(text).VerifyDiagnostics( + // (8,27): warning CS0219: The variable 'x' is assigned but its value is never used + // MyExpression x = null; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(8, 27)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24406")] + public void TestNonGenericTypeOnly() + { + var text = """ + class MyExpression { } + + class Test + { + void M() + { + MyExpression x; + } + } + """; + + CreateCompilation(text).VerifyDiagnostics( + // (7,9): error CS0308: The non-generic type 'MyExpression' cannot be used with type arguments + // MyExpression x; + Diagnostic(ErrorCode.ERR_HasNoTypeVars, "MyExpression").WithArguments("MyExpression", "type").WithLocation(7, 9), + // (7,27): warning CS0168: The variable 'x' is declared but never used + // MyExpression x; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(7, 27)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24406")] + public void TestGenericTypeOnly() + { + var text = """ + class MyExpression { } + + class Test + { + void M() + { + MyExpression x; + } + } + """; + + CreateCompilation(text).VerifyDiagnostics( + // (7,9): error CS0305: Using the generic type 'MyExpression' requires 1 type arguments + // MyExpression x; + Diagnostic(ErrorCode.ERR_BadArity, "MyExpression").WithArguments("MyExpression", "type", "1").WithLocation(7, 9), + // (7,35): warning CS0168: The variable 'x' is declared but never used + // MyExpression x; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(7, 35)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24406")] + public void TestMultipleGenericTypes() + { + var text = """ + class MyExpression { } + class MyExpression { } + class MyExpression { } + + class Test + { + void M() + { + MyExpression x; + } + } + """; + + CreateCompilation(text).VerifyDiagnostics( + // (9,9): error CS0305: Using the generic type 'MyExpression' requires 1 type arguments + // MyExpression x; + Diagnostic(ErrorCode.ERR_BadArity, "MyExpression").WithArguments("MyExpression", "type", "1").WithLocation(9, 9), + // (9,41): warning CS0168: The variable 'x' is declared but never used + // MyExpression x; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(9, 41)); + } } } diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.NamedTypeSymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.NamedTypeSymbols.vb index 97c02854545a..be0747edce69 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.NamedTypeSymbols.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.NamedTypeSymbols.vb @@ -446,7 +446,7 @@ class A private C c2; private C c3; private C> c4; - private [|C|] c5; + private C c5; } class C {