-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Improve arity error message to prefer generic type when both generic and non-generic exist #80707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 4 commits
ea3af0c
1cc3b72
f3ff1c2
eb87740
f8f611b
e08335c
6a16886
01d1c78
8b1aa80
565efa9
849d606
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
using Microsoft.CodeAnalysis.CSharp.Test.Utilities; | ||
using Roslyn.Test.Utilities; | ||
using Xunit; | ||
|
||
namespace Microsoft.CodeAnalysis.CSharp.UnitTests | ||
{ | ||
public class ImprovedArityErrorTests : CSharpTestBase | ||
{ | ||
[Fact] | ||
|
||
public void TestGenericAndNonGenericType() | ||
{ | ||
var text = @" | ||
|
||
class MyExpression { } | ||
class MyExpression<T> { } | ||
class Test | ||
{ | ||
void M() | ||
{ | ||
MyExpression<int, string> x; | ||
} | ||
} | ||
"; | ||
// Currently reports: The non-generic type 'MyExpression' cannot be used with type arguments | ||
// Should report: Using the generic type 'MyExpression<T>' requires 1 type arguments (not 2) | ||
CreateCompilation(text).VerifyDiagnostics( | ||
// (9,9): error CS0305: Using the generic type 'MyExpression<T>' requires 1 type arguments | ||
Diagnostic(ErrorCode.ERR_BadArity, "MyExpression<int, string>").WithArguments("MyExpression<T>", "type", "1").WithLocation(9, 9), | ||
// (9,35): warning CS0168: The variable 'x' is declared but never used | ||
Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(9, 35)); | ||
} | ||
|
||
[Fact] | ||
public void TestGenericAndNonGenericType_SingleTypeArgument() | ||
{ | ||
var text = @" | ||
class MyExpression { } | ||
class MyExpression<T> { } | ||
class Test | ||
{ | ||
void M() | ||
{ | ||
MyExpression<int> x = null; | ||
} | ||
} | ||
"; | ||
// With the correct arity, should use the generic type successfully | ||
CreateCompilation(text).VerifyDiagnostics( | ||
// (9,35): warning CS0219: The variable 'x' is assigned but its value is never used | ||
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(9, 27)); | ||
} | ||
|
||
[Fact] | ||
public void TestNonGenericTypeOnly() | ||
{ | ||
var text = @" | ||
class MyExpression { } | ||
class Test | ||
{ | ||
void M() | ||
{ | ||
MyExpression<int> x; | ||
} | ||
} | ||
"; | ||
// When there's only a non-generic type, should still report ERR_HasNoTypeVars | ||
CreateCompilation(text).VerifyDiagnostics( | ||
// (8,9): error CS0308: The non-generic type 'MyExpression' cannot be used with type arguments | ||
Diagnostic(ErrorCode.ERR_HasNoTypeVars, "MyExpression<int>").WithArguments("MyExpression", "type").WithLocation(8, 9), | ||
// (8,27): warning CS0168: The variable 'x' is declared but never used | ||
Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(8, 27)); | ||
} | ||
|
||
[Fact] | ||
public void TestGenericTypeOnly() | ||
{ | ||
var text = @" | ||
class MyExpression<T> { } | ||
class Test | ||
{ | ||
void M() | ||
{ | ||
MyExpression<int, string> x; | ||
} | ||
} | ||
"; | ||
// When there's only a generic type with wrong arity, should report ERR_BadArity | ||
CreateCompilation(text).VerifyDiagnostics( | ||
// (8,9): error CS0305: Using the generic type 'MyExpression<T>' requires 1 type arguments | ||
Diagnostic(ErrorCode.ERR_BadArity, "MyExpression<int, string>").WithArguments("MyExpression<T>", "type", "1").WithLocation(8, 9), | ||
// (8,35): warning CS0168: The variable 'x' is declared but never used | ||
Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(8, 35)); | ||
} | ||
|
||
[Fact] | ||
public void TestMultipleGenericTypes() | ||
{ | ||
var text = @" | ||
class MyExpression { } | ||
class MyExpression<T> { } | ||
class MyExpression<T1, T2> { } | ||
class Test | ||
{ | ||
void M() | ||
{ | ||
MyExpression<int, string, bool> x; | ||
} | ||
} | ||
"; | ||
// With multiple generic types and non-generic, should prefer the closest match | ||
// In this case, we look for arity 3, find generic with arity 2, that's better than non-generic | ||
CreateCompilation(text).VerifyDiagnostics( | ||
// (10,9): error CS0305: Using the generic type 'MyExpression<T>' requires 1 type arguments | ||
Diagnostic(ErrorCode.ERR_BadArity, "MyExpression<int, string, bool>").WithArguments("MyExpression<T>", "type", "1").WithLocation(10, 9), | ||
// (10,41): warning CS0168: The variable 'x' is declared but never used | ||
Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(10, 41)); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot make this a static local function inside MergeEqual
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit 7b5a8c6.