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 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).