Avoid calculating inferred delegate type unnecessarily in conversions and type inference#58115
Avoid calculating inferred delegate type unnecessarily in conversions and type inference#58115cston merged 5 commits intodotnet:mainfrom
Conversation
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.Symbols | ||
| { | ||
| internal sealed class InferredDelegateTypeData |
| Data = new ConcurrentDictionary<object, NullableWalker.Data>(); | ||
| } | ||
| } | ||
| internal object? CompilationData; |
| /// Nullable analysis data for methods, parameter default values, and attributes. | ||
| /// The key is a symbol for methods or parameters, and syntax for attributes. | ||
| /// The data is collected during testing only. | ||
| /// Optional data collected during testing only. |
| var thisDelegateType = GetInternalDelegateType(); | ||
| var otherDelegateType = otherType.GetInternalDelegateType(); | ||
|
|
||
| Debug.Assert(thisDelegateType is { }); |
It doesn't look like this function is going to be happy about null arguments. In reply to: 987389957 Refers to: src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs:2706 in 1acfcdc. [](commit_id = 1acfcdc, deletion_comment = False) |
| { | ||
| if (HasImplicitFunctionTypeConversion(sourceFunctionType, destination, ref useSiteInfo)) | ||
| if (HasImplicitFunctionTypeConversion(sourceFunctionType, destination, ref useSiteInfo) && | ||
| sourceFunctionType.GetInternalDelegateType() is { }) |
| } | ||
|
|
||
| /// <summary> | ||
| /// A <see cref="TypeSymbol"/> implementation that represents the inferred signature of a |
|
Done with review pass (commit 2) |
|
|
||
| [Fact] | ||
| [WorkItem(58106, "https://github.com/dotnet/roslyn/issues/58106")] | ||
| public void InferDelegateType_01() |
There was a problem hiding this comment.
Are these enough of a stress test that it will demonstrate the perf problem? Or can we create a pathological test that won't compile in any reasonable amount of time without this change? #Resolved
There was a problem hiding this comment.
No, these are not stress tests. I decided to test these cases more directly by tracking the InferredDelegateCount instead. We could test perf although that might require a test that is slow even after the fix.
There was a problem hiding this comment.
I like tracking the count here as that is directly tracking the problem we are trying to fix here (avoiding unnecessary work).
My biggest fear is making sure that future developers understand why we are tracking the count though. The only documentation here is the issue and the issue doesn't specifically call out that this is a customer scenario. It only mentions that it's causing us to do unnecessary work. I think we should make the issue more specific here, say it caused customer reported problems and link to the VS feedback (or link to the feedback here).
Want to make it clear as possible to future developers why this count is meaningful.
There was a problem hiding this comment.
I've added comments to these tests and links to the related issue.
|
Done review pass (commit 2) |
| if (destination is FunctionTypeSymbol destinationFunctionType) | ||
| { | ||
| return HasImplicitFunctionTypeToFunctionTypeConversion(source, destinationFunctionType, ref useSiteInfo); | ||
| if (!HasImplicitFunctionTypeToFunctionTypeConversion(source, destinationFunctionType, ref useSiteInfo)) |
There was a problem hiding this comment.
| @@ -2699,6 +2705,11 @@ private bool HasImplicitFunctionTypeToFunctionTypeConversion(FunctionTypeSymbol | |||
| var sourceDelegate = sourceType.GetInternalDelegateType(); | |||
There was a problem hiding this comment.
Yes, I have reviewed all use of GetInternalDelegateType().
| var otherType = (t2 as FunctionTypeSymbol)?._delegateType; | ||
| return _delegateType.Equals(otherType, compareKind); | ||
| return t2 is FunctionTypeSymbol otherType && | ||
| Equals(GetInternalDelegateType(), otherType.GetInternalDelegateType(), compareKind); |
| { | ||
| return false; | ||
| } | ||
| return source.GetInternalDelegateType() is { }; |
There was a problem hiding this comment.
How confident are we that all places like this one got fixed up? I mean places that do not explicitly use GetInternalDelegateType API, but assume that it is going to return a non-null value just because we are dealing with FunctionTypeSymbol and before this PR that meant that the signature was inferred successfully. #Closed
There was a problem hiding this comment.
I believe I have reviewed all callers that use FunctionTypeSymbol directly or indirectly.
The most interesting cases are in MethodTypeInferrer where the bounds collection was (and still is) including FunctionTypeSymbol instances in the set of lower bounds and which now explicitly drops bounds with null delegate type in MethodTypeInferrer.Fix().
|
Done with review pass (commit 3). |
AlekseyTs
left a comment
There was a problem hiding this comment.
LGTM (commit 4), assuming CI is passing.
…rations * upstream/main: (396 commits) Update several ExpressionCompiler unit tests for inferred delegate types (dotnet#58203) Avoid calculating inferred delegate type unnecessarily in conversions and type inference (dotnet#58115) OmniSharp options (dotnet#58208) Fix generator caching in compiler server (dotnet#57177) Clarify use of null as an initialized value BoundDecisionDag.Rewrite - Avoid capturing the replacement map (dotnet#58137) Address feedback Add regex parser tests Add additional test for another bug report Add additional test for another bug report Add additional test for another bug report Add additional test for another bug report Add additional test for another bug report Add missing delegate casts (dotnet#58170) Add additional test for another bug report Add additional test for another bug report Add additional test for another bug report Add additional test for another bug report Add additional test for another bug report Add additional test for another bug report ...
Fixes #58106.