-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Properly populate ExportedType metadata table in presence of extension block. #80311
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
Conversation
…n block. Related to dotnet#79894. Also temporarily blocks the logic that causes a crash tracked by dotnet#80294. This is needed to unblock testing.
333fred
left a comment
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 review pass (commit 1)
| private void SetExtensionGroupingTypeNestedTypes(ArrayBuilder<PENamedTypeSymbol> groupingNestedTypes) | ||
| { | ||
| var exchangeResult = Interlocked.CompareExchange(ref _lazyNestedTypes, GroupByName(groupingNestedTypes), null); | ||
| Debug.Assert(exchangeResult == null); |
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.
Why is this safe to assume? Is it not possible that multiple threads may get here at the same time? Certainly, given that EnsureNestedTypesAreLoaded does not assume that it is only called once, I do not expect it is safe to assume here either. #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.
Why is this safe to assume?
It is safe to assume by design and the assert verifies that the design is not violated, This method is called on a symbol that is not part of a regular container/member hierarchy, no one can get its instance by accident, only through ExtensionGroupingType API (added below) on an extension symbol. No one can get an extension symbol from which this symbol is accessible before this function is called, because it is called before the extensions are added to their contained type.
| } | ||
|
|
||
| var groupingType = ((PENamedTypeSymbol)type).ExtensionGroupingType; | ||
| if (seenGroupingTypes.Add(groupingType)) |
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 why we need seeGroupingTypes logic. When could we get duplicates? Do we have a test demonstrating this?
Same question for Sort operation below (line 634) #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.
When could we get duplicates?
A grouping type might contain several marker types, each representing an extension block. Here we are enumerating extension blocks. Therefore, can see the same grouping type multiple times.
Do we have a test demonstrating this?
Many tests demonstrating duplication, but not specifically for this code path. I'll add a scenario.
Same question for Sort operation below
Sorting guarantees deterministic emit
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.
Sorting guarantees deterministic emit
Aren't the APIs above already deterministic?
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.
Aren't the APIs above already deterministic?
As far as I know a lookup by name doesn't guarantee a particular order. I.e. it is not part of the contract.
| var namespaceOrType = member as NamespaceOrTypeSymbol; | ||
| if ((object)namespaceOrType != null && | ||
| member is not NamedTypeSymbol { IsExtension: true }) // https://github.com/dotnet/roslyn/issues/78963 - This is a temporary handling, we should get grouping and marker types processed instead. | ||
| if ((object)namespaceOrType != null) |
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.
When could this be null? #ByDesign
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.
When could this be null?
I am not adding this condition.
| } | ||
| } | ||
|
|
||
| type.SetExtensionGroupingTypeNestedTypes(groupingNestedTypes); |
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.
Is there a way to observe this, maybe by checking the nested types of a grouping type via the internal ExtensionGroupingType API? Removing this line doesn't affect extension tests #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.
Is there a way to observe this
In order to observe the effect, you would need to revert:
- this line
- changes in the PEModuleSymbol
If this line is removed on its own, when PEModuleBuilder tries to enumerate nested types of a grouping type we would end up in EnsureNestedTypesAreLoaded with null _lazyNestedTypes. It will load the marker types that we just loaded again, so we will end up with duplicate symbols for the same types in metadata. Also, it will register those nested types in various side tables and we don't want that to happen because these instances are not part of a regular container/nested type hierarchy.
jcouv
left a comment
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 with review pass (commit 1)
| } | ||
|
|
||
| groupingTypes.Free(); | ||
| } |
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 adding an assertion in GetForwardedTypes logic that the types being forwarded can't be extensions #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.
consider adding an assertion in GetForwardedTypes logic that the types being forwarded can't be extensions
This is not related to the purpose of this PR and extensions can be forwarded. Forwarding will be dealt with in a separate PR
jcouv
left a comment
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 (commit 3)
src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEModuleSymbol.cs
Outdated
Show resolved
Hide resolved
…ol.cs Fix typo Co-authored-by: Jan Jones <jan.jones.cz@gmail.com>
* upstream/main: (206 commits) Remove bogus xlf tag (#80357) Fix missing type argument checks Add tests Use dotnet run file for generating compiler code (#80248) Only restore based on assets file changes if the actual content changed (#80341) make expressionbody analyzer use semanticspananalysis (#80339) [EnC] Use ignoreAssemblyKey: false to resolve symbol keys (#80342) Properly populate ExportedType metadata table in presence of extension block. (#80311) Propagate `params` to lambdas and local functions (#79880) Change 17.15 to VS 2026 preview. (#80325) Improve virtualproject support for older .NET SDKs (#80324) Update dependencies from https://github.com/dotnet/dotnet build 283666 (#80344) Update dependencies from https://github.com/dotnet/arcade build 20250917.6 (#80343) Simplifying Fix tests Fix tests Fix introduce variable placement in top level statements move to immutable types in signature help move to immutable types in signature help Fix check ...
* upstream/main: (31 commits) Remove bogus xlf tag (dotnet#80357) Fix missing type argument checks Add tests Use dotnet run file for generating compiler code (dotnet#80248) Only restore based on assets file changes if the actual content changed (dotnet#80341) make expressionbody analyzer use semanticspananalysis (dotnet#80339) [EnC] Use ignoreAssemblyKey: false to resolve symbol keys (dotnet#80342) Properly populate ExportedType metadata table in presence of extension block. (dotnet#80311) Propagate `params` to lambdas and local functions (dotnet#79880) Change 17.15 to VS 2026 preview. (dotnet#80325) Improve virtualproject support for older .NET SDKs (dotnet#80324) Update dependencies from https://github.com/dotnet/dotnet build 283666 (dotnet#80344) Update dependencies from https://github.com/dotnet/arcade build 20250917.6 (dotnet#80343) Simplifying Fix tests Fix tests Fix introduce variable placement in top level statements move to immutable types in signature help move to immutable types in signature help Fix check ...
Related to #79894.
Also temporarily blocks the logic that causes a crash tracked by #80294. This is needed to unblock testing.