-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Implement scoping and shadowing rules for extension parameter and type parameters #77704
Implement scoping and shadowing rules for extension parameter and type parameters #77704
Conversation
…e parameters See dotnet/csharplang#9229 (commit 9)
<value>Type parameter '{0}' has the same name as an extension container type parameter</value> | ||
</data> | ||
<data name="ERR_LocalSameNameAsExtensionParameter" xml:space="preserve"> | ||
<value>'{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter</value> |
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.
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.
I used the following message as a template "'{0}': a parameter, local variable, or local function cannot have the same name as a method type parameter"
{ | ||
get | ||
{ | ||
int local() => p; |
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.
Do we have a test for the happy case, where the extension parameter is used in a non-static local function or lambda, inside an instance extension member? #Closed
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.
Implementation_InstanceMethod_03_WithLocalFunction
, for example?
else if (parameter.ContainingSymbol is NamedTypeSymbol { IsExtension: true } && | ||
(InParameterDefaultValue || InAttributeArgument || | ||
this.ContainingMember() is not { Kind: not SymbolKind.NamedType, IsStatic: false } || // We are not in an instance member | ||
(object)this.ContainingMember().ContainingSymbol != parameter.ContainingSymbol) && |
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.
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.
That is for references in nested types. IsInDeclaringTypeInstanceMember
does the same. Declaring a nested type in extension is an error, but I prefer to be consistent
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.
Consider adding a test for this
diagnostics.Add(ErrorCode.ERR_LocalSameNameAsTypeParam, GetLocation(p), name); | ||
if (tp.ContainingSymbol is NamedTypeSymbol { IsExtension: true }) | ||
{ | ||
if (p.ContainingSymbol != (object)tp.ContainingSymbol) |
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.
nit: consider leaving a comment (the error for naming the extension parameter after an extension type parameter is reported elsewhere) #Resolved
} | ||
|
||
if (!pNames.Add(name)) | ||
{ | ||
// The parameter name '{0}' is a duplicate | ||
diagnostics.Add(ErrorCode.ERR_DuplicateParamName, GetLocation(p), name); | ||
if (parameters[0] is { ContainingSymbol: NamedTypeSymbol { IsExtension: true }, Name: var receiverName } && receiverName == name) |
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.
|
||
using System.Diagnostics; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Runtime.CompilerServices; |
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.
nit: unused using? #Resolved
{ | ||
Debug.Assert(result.IsClear); | ||
|
||
if ((options & (LookupOptions.NamespaceAliasesOnly | LookupOptions.NamespacesOrTypesOnly)) != 0) |
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.
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.
I didn't follow, what's the reasoning for checking some options early, but letting others be handled by
Why do the work if we know that parameters do not satisfy the request. Especially, when we are binding types names in source, we want to avoid having to create symbols for members, etc. This helps with avoiding cycles. In terms of implementation, I used WithPrimaryConstructorParametersBinder
as a template.
"; | ||
var comp = CreateCompilation(src); | ||
|
||
comp.VerifyDiagnostics( |
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.
// (5,14): error CS0102: The type 'Extensions.extension<T>(object)' already contains a definition for 'T' | ||
// void T() { } | ||
Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "T").WithArguments("Extensions.extension<T>(object)", "T").WithLocation(5, 14)); | ||
comp.VerifyEmitDiagnostics(); |
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.
Consider adding a similar test for an accessor: extension<get_P>(...) int P => 0;
#Resolved
_type = type; | ||
} | ||
|
||
internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) |
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.
We probably need some direct LookupSymbols tests to cover this method #Resolved
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.
LGTM Thanks (iteration 4) with some minor questions/suggestions
@jjonescz, @dotnet/roslyn-compiler For the second review. |
<value>'{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter</value> | ||
</data> | ||
<data name="ERR_ValueParameterSameNameAsExtensionParameter" xml:space="preserve"> | ||
<value>'value': an automatically-generated parameter name conflicts with an extension parameter name</value> |
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.
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.
The terminology was "copied" from ERR_DuplicateGeneratedName
See dotnet/csharplang#9229 (commit 9)
Relates to test plan #76130