Skip to content
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

Avoid cyclic references during incremental project update #58720

Merged
merged 1 commit into from
Jan 14, 2022

Conversation

sharwell
Copy link
Member

@sharwell sharwell commented Jan 7, 2022

This change operates under the assumption that neither the starting state nor the final state include any cycles. By removing all project references from projects that change their reference sets prior to other work, we ensure extraneous references cannot lead to an invalid intermediate state. In terms of graph theory, this change relies on the fact that any subset of edges from an acyclic directed graph will also be an acyclic directed graph.

This increases the amount of work required to complete an incremental update when project references change, but does not impact the more common updates where all project references are unchanged.

Fixes #52578

@sharwell sharwell requested a review from a team as a code owner January 7, 2022 19:55
Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix looks solid, and the tests looks good. I privately had some concern with @sharwell about whether this is producing more updates to the project dependency graph than we'd want; we have optimizations for addition/removal but the .With() that just blows away all the references won't have any of those running. He correctly observed that's more or less what we're doing today, so if there's performance wins here this may not make things any worse than they are now.

@jasonmalinowski
Copy link
Member

@sharwell @jinujoseph Given we've had a bunch of dupes of this, do we want to take this for 17.1? It seems nice and low risk.

This change operates under the assumption that neither the starting
state nor the final state include any cycles. By removing all project
references from projects that change their reference sets prior to other
work, we ensure extraneous references cannot lead to an invalid
intermediate state.

This increases the amount of work required to complete an incremental
update when project references change, but does not impact the more
common updates where all project references are unchanged.

Fixes dotnet#52578
@sharwell sharwell merged commit 71d5b9e into dotnet:main Jan 14, 2022
@sharwell sharwell deleted the avoid-cycles branch January 14, 2022 06:10
@ghost ghost added this to the Next milestone Jan 14, 2022
@sharwell
Copy link
Member Author

📝 Commit bcc2112 is based on 17.1 so we can merge it there without any rebase/porting if we need to.

@vdevappa
Copy link

Which VS update will contain this fix?

@sharwell
Copy link
Member Author

17.2 Preview 1 will contain this fix.

@vdevappa Since you're asking, I'm assuming you've hit this issue. If this is the case, I'm curious how you are hitting it. It seems extremely difficult to hit this accidentally.

@vdevappa
Copy link

vdevappa commented Jan 14, 2022

I have a large .net solution that was migrated over time and now contains .net 4.8 and .net core projects. I hit this when I change between x64 and AnyCPU. I have to reboot VS every single time after this. Also, the .NET Core migration tool also throws this error and dies.

Will this fix the .net core migration tool as well?

I did that right now and see this error in VS yellow bar on top:

StreamJsonRpc.RemoteInvocationException: Adding project reference from '(ProjectId, #511c784e-0a6f-4eaa-aa92-a07a958c2a43 - Locus.MongoDB.Core)' to '(ProjectId, #ed174d50-8aad-498e-8c9a-702f4070aec7 - Locus.Models.Public)' will cause a circular reference.
at StreamJsonRpc.JsonRpc.d__1391.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Threading.Tasks.ValueTask1.get_Result()
at Microsoft.CodeAnalysis.Remote.BrokeredServiceConnection1.<TryInvokeAsync>d__181.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.VisualStudio.Telemetry.WindowsErrorReporting.WatsonReport.GetClrWatsonExceptionInfo(Exception exceptionObject)
RPC server exception:
System.InvalidOperationException: Adding project reference from '(ProjectId, #511c784e-0a6f-4eaa-aa92-a07a958c2a43 - Locus.MongoDB.Core)' to '(ProjectId, #ed174d50-8aad-498e-8c9a-702f4070aec7 - Locus.Models.Public)' will cause a circular reference.
at Microsoft.CodeAnalysis.Solution.CheckCircularProjectReferences(ProjectId projectId, IReadOnlyCollection1 projectReferences) at Microsoft.CodeAnalysis.Solution.WithProjectReferences(ProjectId projectId, IEnumerable1 projectReferences)
at Microsoft.CodeAnalysis.Project.WithProjectReferences(IEnumerable1 projectReferences) at Microsoft.CodeAnalysis.Remote.RemoteWorkspace.SolutionCreator.<UpdateProjectAsync>d__10.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.CodeAnalysis.Remote.RemoteWorkspace.SolutionCreator.<UpdateProjectsAsync>d__8.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.CodeAnalysis.Remote.RemoteWorkspace.SolutionCreator.<UpdateProjectsAsync>d__7.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.CodeAnalysis.Remote.RemoteWorkspace.SolutionCreator.<CreateSolutionAsync>d__6.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.VisualStudio.Telemetry.WindowsErrorReporting.WatsonReport.GetClrWatsonExceptionInfo(Exception exceptionObject) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.CodeAnalysis.Remote.RemoteWorkspace.<<GetProjectSubsetSolutionAsync>g__GetProjectSubsetSolutionSlowAsync|15_0>d.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.CodeAnalysis.Remote.RemoteNavigationBarItemService.<>c__DisplayClass2_0.<<GetItemsAsync>b__0>d.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Threading.Tasks.ValueTask1.get_Result()
at Microsoft.CodeAnalysis.Remote.BrokeredServiceBase.d__13`1.MoveNext()
VS error on x64

@sharwell
Copy link
Member Author

@vdevappa have you submitted a feedback ticket to developer community on this in the past? Can you either create a new one or update the existing one (and link me to it) to contain the following:

⚠️ These logs can contain environment variables and other information from your project files so don't put them here on public github.

  1. The msbuild.binlog produced by msbuild /p:AnyCPU /bl
  2. The msbuild.binlog produced by msbuild /p:x64 /bl

Somewhere in one (or both) of these is a conditional <ProjectReference> element that points in one direction for the Any CPU build and the opposite direction for the x64 build. I'm guessing this ordering is unintentional but it may be more clear from the logs.

@vdevappa
Copy link

@sharwell
Copy link
Member Author

@vdevappa that issue is too old and all the attached diagnostics were cleared out. I think we'll need a new one filed instead.

@RikkiGibson RikkiGibson modified the milestones: Next, 17.2.P1 Feb 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Crash in solution sync with transitive reference
4 participants