Skip to content

FrameworkImportsCache lends the first project's --pathmap to every project of the framework set #20474

Description

@xperiandri

FrameworkImportsCache (src/Compiler/Service/IncrementalBuild.fs) caches the framework TcImports together with the TcGlobals built for the first project that asked for a given framework set. Its key — the framework assemblies, the primary assembly, the target framework directories, the compiler binaries directory and the import-reuse key — does not include TcConfig.pathMap. When a later project with the same framework set reuses the entry, FrameworkImportsCache.Get (and the same code in TransparentCompiler.fs) creates a fresh TcGlobals only if langVersion or realsig differ, and even then it copies tcGlobals.pathMap from the cached instance instead of taking tcConfig.pathMap.

So every project of one framework set is checked with the path map of whichever project filled the cache first:

  • a project without --pathmap gets the map of a sibling that has one, and
  • a project with --pathmap is checked without it when a sibling came first.

TypedTreePickle.p_range applies tcGlobals.pathMap to range file names, and EncodeSignatureData applies it to compileTimeWorkingDir, so the ranges an in-memory FSharpReferencedProject.FSharpReference exposes to other projects depend on that accident.

Where it shows: a Visual Studio solution whose Directory.Build.props sets <PathMap>$(MSBuildThisFileDirectory)=.\</PathMap> (DeterministicSourcePaths). The project system forwards --pathmap: to the IDE options; symbols imported from a sibling project then carry a file name such as .\backend\Use cases\Circulars\GraphQL\.\backend\Use cases\Circulars\GraphQL\Types\Circular.fs (mapped working directory + mapped file name, joined by SymbolHelpers.fs), no workspace document matches, and Go To Definition opens the generated signature instead of the source. #20470 stops the IDE from passing --pathmap at all; this issue is about the cache reusing one project's map for another, which any host that mixes mapped and unmapped projects in one FSharpChecker can hit.

Repro (two projects sharing a checker, same framework):

  1. Check project A with --pathmap:<dir of B>=.\.
  2. Check project C that references project B (no --pathmap) through FSharpReferencedProject.FSharpReference.
  3. DeclarationLocation.FileName of a B symbol seen from C is .\B\B.fs-like instead of B's absolute file path.

Proposed fix: treat pathMap like langVersion and realsig — build a new TcGlobals from the cached one when tcConfig.pathMap differs, and take the map from tcConfig in both IncrementalBuild.fs and TransparentCompiler.fs. The cached framework imports themselves do not depend on the map.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions