Skip to content

Restrict partial evaluation to ProjectInstance - #14340

Merged
ViktorHofer merged 2 commits into
mainfrom
vihofer/remove-partial-eval-from-project
Jul 13, 2026
Merged

Restrict partial evaluation to ProjectInstance#14340
ViktorHofer merged 2 commits into
mainfrom
vihofer/remove-partial-eval-from-project

Conversation

@ViktorHofer

Copy link
Copy Markdown
Member

Summary

Partial (stop-after-pass) evaluation was exposed on both Project and ProjectInstance. This PR restricts it to ProjectInstance only.

Project is mutable and cached by ProjectCollection, which makes a partially-evaluated Project a footgun:

  • A cached partial Project can be handed back to a caller expecting a full evaluation, serving stale partial state, or
  • It gets silently upgraded to a full evaluation (re-evaluated in place) when something touches later-pass state — discarding the performance win the caller asked for, as hidden work.

ProjectInstance is 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 public EvaluationStage property, the ProjectImpl stage field + member guards, the partial→Full upgrade blocks in ReevaluateIfNecessary/CreateProjectInstance, and the evaluationStage constructor parameters. Project.FromFile/FromProjectRootElement/FromXmlReader now throw ArgumentException when a non-Full stage is requested via ProjectOptions (new OM_PartialEvaluationNotSupportedForProject resource + xlf entries).
  • ProjectCollection.LoadProject: dropped the now-dead partial cache upgrade-in-place logic.
  • XMake (-getProperty/-getItem, no-target path): switched from Project.FromFile to ProjectInstance.FromFile. ProjectInstance does not log pre-evaluation project-load failures (malformed XML) the way Project did, so the catch block now surfaces MSB4025 in canonical format (guarded by HasBeenLogged to avoid double-logging genuine evaluation errors).
  • JsonOutputFormatter: removed orphaned Project-based item formatter overloads.
  • Benchmark: PartialEvaluationBenchmark now uses ProjectInstance.
  • Docs/tests: updated the partial-evaluation spec and reworked the unit tests.

ProjectInstance retains full partial-evaluation support (EvaluationStage, member guards, OM_PartialEvaluationMemberUnavailable/OM_PartialEvaluationCannotBuild).

Testing

  • PartialEvaluation_Tests (Engine.UnitTests): 13/13 pass.
  • -getProperty/-getItem CLI tests + full XMakeAppTests (CommandLine.UnitTests): pass (incl. GetPropertyWithInvalidProjectThrowsInvalidProjectFileExceptionNotInternalError, which verifies MSB4025 is still emitted).
  • Full repo build clean.

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
Copilot AI review requested due to automatic review settings July 13, 2026 14:05
@ViktorHofer
ViktorHofer temporarily deployed to copilot-pat-pool July 13, 2026 14:05 — with GitHub Actions Inactive
@ViktorHofer
ViktorHofer temporarily deployed to copilot-pat-pool July 13, 2026 14:05 — with GitHub Actions Inactive
@ViktorHofer
ViktorHofer temporarily deployed to copilot-pat-pool July 13, 2026 14:07 — with GitHub Actions Inactive

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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/-getItem no-target path now evaluates via ProjectInstance.FromFile and updates JSON item formatting accordingly.
  • Project factories reject non-Full ProjectOptions.EvaluationStage and ProjectCollection.LoadProject drops 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

Comment thread src/Build/Definition/Project.cs
Comment thread src/MSBuild/XMake.cs Outdated
- 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
@ViktorHofer
ViktorHofer requested review from OvesN and baronfel July 13, 2026 15:03
@ViktorHofer
ViktorHofer merged commit 4bdea96 into main Jul 13, 2026
14 checks passed
@ViktorHofer
ViktorHofer deleted the vihofer/remove-partial-eval-from-project branch July 13, 2026 19:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants