Restrict partial evaluation to ProjectInstance - #14340
Merged
Merged
Conversation
The opt-in partial (stop-after-pass) evaluation feature was exposed on both Project and ProjectInstance. Project is mutable and cached by ProjectCollection, so a partial Project is a footgun: it either serves stale partial state from the cache or gets silently upgraded to a full evaluation (discarding the perf win) when handed to something that requires later passes. ProjectInstance is an uncached, read-only snapshot and is trap-proof, so partial evaluation now lives there exclusively. Changes: - Remove all partial-eval honoring from Project: the public EvaluationStage property, the ProjectImpl stage field/guards, the partial->Full upgrade blocks in ReevaluateIfNecessary/CreateProjectInstance, and the evaluationStage ctor parameters. Project factories now throw ArgumentException when a non-Full stage is requested via ProjectOptions (new OM_PartialEvaluationNotSupportedForProject resource + xlf entries). - Drop the now-dead cache upgrade-in-place logic in ProjectCollection.LoadProject. - Switch the -getProperty/-getItem (no-target) CLI path in XMake to ProjectInstance.FromFile, and log MSB4025 for pre-evaluation project load failures (Project logged these before throwing; ProjectInstance does not). - Clean up orphaned Project-based JSON item formatter overloads. - Point the partial-eval benchmark at ProjectInstance. - Update the partial-evaluation spec and unit tests accordingly. ProjectInstance retains full partial-evaluation support (EvaluationStage, member guards, OM_PartialEvaluationMemberUnavailable/CannotBuild). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 008efa7a-b4fc-4f33-9dc7-d37d3f0e93c3
ViktorHofer
temporarily deployed
to
copilot-pat-pool
July 13, 2026 14:05 — with
GitHub Actions
Inactive
ViktorHofer
temporarily deployed
to
copilot-pat-pool
July 13, 2026 14:05 — with
GitHub Actions
Inactive
ViktorHofer
had a problem deploying
to
copilot-pat-pool
July 13, 2026 14:06 — with
GitHub Actions
Failure
ViktorHofer
temporarily deployed
to
copilot-pat-pool
July 13, 2026 14:07 — with
GitHub Actions
Inactive
Contributor
There was a problem hiding this comment.
Pull request overview
Restricts partial (stop-after-pass) evaluation support to ProjectInstance only, removing/denying partial evaluation paths on mutable, ProjectCollection-cached Project to avoid stale cached partial state and hidden upgrade-to-full work.
Changes:
- MSBuild CLI
-getProperty/-getItemno-target path now evaluates viaProjectInstance.FromFileand updates JSON item formatting accordingly. Projectfactories reject non-FullProjectOptions.EvaluationStageandProjectCollection.LoadProjectdrops now-dead partial-upgrade cache logic.- Updates tests, benchmarks, resources/localization, and the partial-evaluation spec to reflect the
ProjectInstance-only model.
Show a summary per file
| File | Description |
|---|---|
| src/MSBuild/XMake.cs | Switches no-target -getProperty/-getItem evaluation to ProjectInstance and adjusts error surfacing and JSON item formatting calls. |
| src/MSBuild/JsonOutputFormatter.cs | Removes Project-based item JSON formatting overloads; keeps ProjectInstance path. |
| src/MSBuild.Benchmarks/PartialEvaluationBenchmark.cs | Updates benchmark to mirror CLI by loading via ProjectInstance. |
| src/Build/Resources/xlf/Strings.zh-Hant.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.zh-Hans.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.tr.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.ru.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.pt-BR.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.pl.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.ko.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.ja.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.it.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.fr.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.es.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.de.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/xlf/Strings.cs.xlf | Adds localized placeholder entry for OM_PartialEvaluationNotSupportedForProject. |
| src/Build/Resources/Strings.resx | Adds OM_PartialEvaluationNotSupportedForProject resource string. |
| src/Build/Definition/ProjectOptions.cs | Documents that partial stages are honored only for ProjectInstance, and Project factories throw. |
| src/Build/Definition/ProjectCollection.cs | Removes partial-eval upgrade-in-place logic from the loaded-project cache. |
| src/Build/Definition/Project.cs | Removes Project partial-eval plumbing/guards and adds up-front rejection for partial stages in Project factory methods. |
| src/Build.UnitTests/Evaluation/PartialEvaluation_Tests.cs | Reworks tests to validate Project factories reject partial stages and ProjectInstance retains behavior. |
| documentation/specs/proposed/partial-evaluation.md | Updates spec to explicitly scope partial evaluation to ProjectInstance and explains why Project does not support it. |
Copilot's findings
- Files reviewed: 22/22 changed files
- Comments generated: 2
- ThrowIfPartialEvaluationRequested now validates options for null up front, so the public Project.From* factories throw ArgumentNullException (not NullReferenceException) when passed null ProjectOptions. Added a covering test. - The -getProperty/-getItem invalid-project error path now prints ex.Message instead of ex.BaseMessage so the project file path is retained in the MSB4025 output, matching the prior Project-based behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 008efa7a-b4fc-4f33-9dc7-d37d3f0e93c3
baronfel
approved these changes
Jul 13, 2026
This was referenced Sep 10, 2026
This was referenced Sep 16, 2026
Open
WarperSan
pushed a commit
to WarperSan/ThunderPipe
that referenced
this pull request
Sep 17, 2026
Updated [Microsoft.Build.Utilities.Core](https://github.com/dotnet/msbuild) from 18.9.6 to 18.10.1. <details> <summary>Release notes</summary> _Sourced from [Microsoft.Build.Utilities.Core's releases](https://github.com/dotnet/msbuild/releases)._ ## 18.10.1 ## What's Changed * [vs16.11] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13103 * [vs17.12] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13796 * [vs17.8] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13902 * [vs17.11] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13903 * [vs17.12] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13909 * [vs17.12] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13986 * Add vs18.9 to merge-flow config; retire vs18.3 by @JanProvaznik in dotnet/msbuild#14214 * Bump labeler-cache-retention to use issue-labeler v2.1.0 by @jeffhandley in dotnet/msbuild#14171 * Bump main to 18.10.0 after vs18.9 snap by @JanProvaznik in dotnet/msbuild#14216 * Improve release skill: Phase 2 DARC rules, VMR backflow, deterministic baseline by @JanProvaznik in dotnet/msbuild#14220 * Determinize release: hardcode OptProf baseline + Phase 3.2 baseline resolver by @JanProvaznik in dotnet/msbuild#14222 * Serialize BuildRequestConfiguration.RequestedTargets to fix solution metaproject MSB4057 in parallel builds by @ViktorHofer in dotnet/msbuild#14223 * [main] Update dependencies from nuget/nuget.client by @dotnet-maestro[bot] in dotnet/msbuild#14203 * Core support for AbsolutePath/FileInfo/DirectoryInfo and ITaskItem<T> as task parameters by @baronfel in dotnet/msbuild#13971 * [main] Update dependencies from dotnet/roslyn by @dotnet-maestro[bot] in dotnet/msbuild#14206 * Fix existence cache kind poisoning by @AlesProkop in dotnet/msbuild#14249 * [main] Source code updates from dotnet/dotnet by @dotnet-maestro[bot] in dotnet/msbuild#14226 * Don't disable the MSBuild server for /mt builds when node reuse is off by @AR-May in dotnet/msbuild#14248 * Enhance expert reviewer guidelines with additional checks. by @AR-May in dotnet/msbuild#14255 * [main] Source code updates from dotnet/dotnet by @dotnet-maestro[bot] in dotnet/msbuild#14253 * [main] Update dependencies from dotnet/roslyn by @dotnet-maestro[bot] in dotnet/msbuild#14268 * [main] Update dependencies from nuget/nuget.client by @dotnet-maestro[bot] in dotnet/msbuild#14267 * Bump github/gh-aw-actions/setup from 0.81.6 to 0.82.2 by @dependabot[bot] in dotnet/msbuild#14266 * Avoid boxing the struct enumerator in PropertyDictionary<T>.GetEnumerator() by @nareshjo in dotnet/msbuild#14272 * Refresh copy marker when implementation output changes by @AlesProkop in dotnet/msbuild#14231 * Send task-host build process environment as delta by @OvesN in dotnet/msbuild#14126 * Add regression coverage for metadata newline preservation by @VolPlita in dotnet/msbuild#14261 * Fix EmbedInBinlog items with relative paths from child projects by @huulinhnguyen-dev in dotnet/msbuild#13990 * Stop requiring VersionPrefix updates in servicing - insert prerelease versions to VS by @ViktorHofer in dotnet/msbuild#14277 * Fix WriteLinesToFile rewriting unchanged file when custom encoding is used by @huulinhnguyen-dev in dotnet/msbuild#14146 * Enable trim/AOT analyzers for Microsoft.Build and clean up annotations by @JeremyKuhne in dotnet/msbuild#14064 * [automated] Merge branch 'vs18.9' => 'main' by @github-actions[bot] in dotnet/msbuild#14291 * Fix MicroBuild plugin feed URL to use allowed pkgs.dev.azure.com format by @AlesProkop in dotnet/msbuild#14295 * Pass ExcludeRestorePackageImports during restore to avoid redundant evaluations by @ViktorHofer with @Copilot in dotnet/msbuild#14274 * [vs18.7] Update dependencies from dotnet/arcade by @dotnet-maestro[bot] in dotnet/msbuild#13988 * Adopt Clever Test Selection (CTS) as parallel, non-blocking PR pipeline by @jankratochvilcz in dotnet/msbuild#14212 * Harden exceptions when connecting to server by @JanProvaznik in dotnet/msbuild#14292 * Update MicrosoftBuildVersion in analyzer template by @github-actions[bot] in dotnet/msbuild#13886 * Fix MSBuild Server client dropping build result under WaitAny race (#14172) by @JanProvaznik in dotnet/msbuild#14251 * Partially revert #13660: remove NuGet RestoreTask transient TaskHost workaround by @JanProvaznik in dotnet/msbuild#14297 * Disable daily AI credits guardrail for Expert Code Review workflow by @JanProvaznik with @Copilot in dotnet/msbuild#14314 * Localized file check-in by OneLocBuild Task: Build definition ID 9434: Build ID 14614733 by @dotnet-bot in dotnet/msbuild#14246 * Add opt-in partial (stop-after-pass) project evaluation by @ViktorHofer in dotnet/msbuild#14290 * Use partial evaluation for -getProperty/-getItem without a target by @ViktorHofer in dotnet/msbuild#14296 * [main] Source code updates from dotnet/dotnet by @dotnet-maestro[bot] in dotnet/msbuild#14324 * [main] Update dependencies from dotnet/roslyn by @dotnet-maestro[bot] in dotnet/msbuild#14333 * [main] Update dependencies from nuget/nuget.client by @dotnet-maestro[bot] in dotnet/msbuild#14330 * Bump github/gh-aw-actions/setup from 0.82.2 to 0.82.8 by @dependabot[bot] in dotnet/msbuild#14328 * Restrict partial evaluation to ProjectInstance by @ViktorHofer in dotnet/msbuild#14340 ... (truncated) Commits viewable in [compare view](dotnet/msbuild@v18.9.6...v18.10.1). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This was referenced Sep 17, 2026
Open
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Partial (stop-after-pass) evaluation was exposed on both
ProjectandProjectInstance. This PR restricts it toProjectInstanceonly.Projectis mutable and cached byProjectCollection, which makes a partially-evaluatedProjecta footgun:Projectcan be handed back to a caller expecting a full evaluation, serving stale partial state, orProjectInstanceis an uncached, read-only evaluation snapshot with none of these traps, so partial evaluation now lives there exclusively.Changes
Project: removed all partial-eval honoring — the publicEvaluationStageproperty, theProjectImplstage field + member guards, the partial→Full upgrade blocks inReevaluateIfNecessary/CreateProjectInstance, and theevaluationStageconstructor parameters.Project.FromFile/FromProjectRootElement/FromXmlReadernow throwArgumentExceptionwhen a non-Fullstage is requested viaProjectOptions(newOM_PartialEvaluationNotSupportedForProjectresource + xlf entries).ProjectCollection.LoadProject: dropped the now-dead partial cache upgrade-in-place logic.XMake(-getProperty/-getItem, no-target path): switched fromProject.FromFiletoProjectInstance.FromFile.ProjectInstancedoes not log pre-evaluation project-load failures (malformed XML) the wayProjectdid, so the catch block now surfacesMSB4025in canonical format (guarded byHasBeenLoggedto avoid double-logging genuine evaluation errors).JsonOutputFormatter: removed orphanedProject-based item formatter overloads.PartialEvaluationBenchmarknow usesProjectInstance.ProjectInstanceretains full partial-evaluation support (EvaluationStage, member guards,OM_PartialEvaluationMemberUnavailable/OM_PartialEvaluationCannotBuild).Testing
PartialEvaluation_Tests(Engine.UnitTests): 13/13 pass.-getProperty/-getItemCLI tests + fullXMakeAppTests(CommandLine.UnitTests): pass (incl.GetPropertyWithInvalidProjectThrowsInvalidProjectFileExceptionNotInternalError, which verifiesMSB4025is still emitted).